OpenAPITools / OpenAPITools/openapi-generator

[BUG] Root server url cannot be used as a relative path

Open
#19,343 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Generated client will correctly recognise a relative server such as: /mypath and use this as the base path.
The relative server of just the root path / is not recognized and so the client will instead default to localhost as the base path.
A single slash should be recognised as a valid relative path.
This behavior occurs with multiple generator targets (typescript-fetch and java were tested).

openapi-generator version

7.7.0

This is not a regression:
The relevant code URLPathUtils.isRelativeUrl hasn't been touched in 3 years and a comment on the associated pull request pointed this out a year ago (#10057).

OpenAPI declaration file content
{
  "openapi": "3.0.1",
  "info": {
    "title": "OpenAPI definition",
    "version": "v0"
  },
  "servers": [
    {
      "url": "/",
      "description": "Generated server url"
    }
  ],
  "paths": {},
  "components": {}
}
Generation Details

Tested with both JDK 11 and JDK 17.
This was tested with both the typescript-fetch generator and the java generator.

CLI

java -jar openapi-generator-cli.jar generate -g typescript-fetch -i openapi.json -o my-generated-client

Alternatively, with Maven:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>7.7.0</version>
    <executions>
        <execution>
            <goals><goal>generate</goal></goals>
            <configuration>
                <generatorName>typescript-fetch</generatorName>
                <inputSpec>${project.build.directory}/openapi.json</inputSpec>
                <output>${project.build.directory}/ts-openapi</output>
            </configuration>
        </execution>
    </executions>
</plugin>
Steps to reproduce

Using the provided JSON, the generated client (see above) should have the base URL be empty, rather than falling back to localhost.
The reason for empty, rather than a slash, is so that concatting with work like normal with the context path.

In the typescript-fetch client see runtime.ts.

export const BASE_PATH = "http://localhost".replace(/\/+$/, "");

In the java client, see src/main/java/org/openapitools/client/ApiClient.java.

private String basePath = "http://localhost";
Related issues/PRs
  • Issue #10057 - the problem was mentioned, but only after that issue's fix had already been merged
  • Issue #3489 - dealt with an empty path, it looks like a language/generator specific fix was done, rather than a general fix applying to all of them.
  • Issue #13494 - used a single slash, but it seems to be focused on trailing slashes.
Suggest a fix

Code investigation:

When no server is defined, then a server with "/" is used as the default (OpenAPIDeserializer.parseRoot):`

ArrayNode array = getArray("servers", rootNode, false, location, result);
if (array != null && array.size() > 0) {
    openAPI.setServers(getServersList(array, String.format("%s.%s", location, "servers"), result, path));
} else {
    Server defaultServer = new Server();
    defaultServer.setUrl("/");
    List<Server> servers = new ArrayList<>();
    servers.add(defaultServer);
    openAPI.setServers(servers);
}

This then relates to the following in DefaultGenerator.configureGeneratorProperties:

if (URLPathUtils.isRelativeUrl(openAPI.getServers())) {
    basePath = removeTrailingSlash(basePathWithoutHost);
} else {
    basePath = removeTrailingSlash(config.escapeText(URLPathUtils.getHost(openAPI, config.serverVariableOverrides())));
}

This means that when URLPathUtils.getHost is called above, URLPathUtils.sanitizeUrl changes the URL to localhost:

} else if (url.startsWith("/")) {
    url = LOCAL_HOST + url;
    once(LOGGER).info("'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [{}] for server URL [{}]", LOCAL_HOST, url);
}

Patch:

I have created a patch to support /: https://github.com/scrhartley/openapi-generator/tree/root-relative-url

Why is this not a pull request?

Previously, several of the samples didn't specify an explicit server and so would default to /, which would then become localhost as explained above. By changing / to no longer default to localhost, this would affect readmes, api docs, generated client code and comments and generated spec files. In order to avoid this, I changed input spec files to explicitly use localhost so that the only generated client files that would change would be their generated spec files.

The problem with just changing the input specs to localhost is that some clients were already confused by / being specified as the server , but then the basePath becoming localhost. This means that explicitly specifying localhost as the server may cause some clients which had previously been generating a blank base path, to now use localhost. To avoid these clients changing, I instead made their server be blank (a relative url with the trailing slash removed) since I only updated isRelativeUrl to treat / as relative and hence blank server urls are still handled in the legacy manner.

I do not have the expertise to make existing clients handle / as a server in a more graceful manner, nor am I sure if it would be better to just allow some clients' URL to change to localhost, nor whether "" should also be accepted as a relative URL.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the supplied OpenAPI document with the typescript-fetch and java generators, then trace URLPathUtils.isRelativeUrl, URLPathUtils.sanitizeUrl, and DefaultGenerator.configureGeneratorProperties. Compare the generated runtime.ts and src/main/java/org/openapitools/client/ApiClient.java with the expected empty base URL, and verify that existing sample output does not change unintentionally.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, typescript
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.