Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot override servers in api-docs.yaml using OpenApiCustomiser #1188

Closed
bfrggit opened this issue Jun 12, 2021 · 6 comments
Closed

Cannot override servers in api-docs.yaml using OpenApiCustomiser #1188

bfrggit opened this issue Jun 12, 2021 · 6 comments
Labels
bug Something isn't working

Comments

@bfrggit
Copy link

bfrggit commented Jun 12, 2021

Describe the bug

I cannot override the servers field in api-docs.yaml using a OpenApiCustomiser @Bean, while other fields like info.version seem to work well with this approach, the servers remains the auto generated value.

To Reproduce

Spring Boot 2.4.5

'org.springdoc:springdoc-openapi-ui:1.5.9'

I have a class in src/main annotated with @OpenAPIDefinition, servers parameter is not set in this annotation. I cannot paste all the codes here, but it is basically like this:

@Configuration
@OpenAPIDefinition(info = @Info(title = "...", version = "v0",
      description = "...",
      contact = @Contact( ... ),
      license = @License( ... )), //
      tags = { ... } //
)
public class OpenApiConfig {
   private static Parameter getHeaderTenantId() {
      return new Parameter().in(ParameterIn.HEADER.toString()).name("X-Tenant-ID").schema(new StringSchema())
            .required(true).description("Tenant ID to which the composer or other objects belong to.");
   }

   @Bean
   OpenApiCustomiser getDefaultOpenApiCustomiser() {
      return openApi -> openApi.getComponents().addParameters("TenantId", getHeaderTenantId());
   }
}

In my integration test, there is such a config class:

@Slf4j
@Configuration
public class OpenApiTestConfig {
   @Bean
   OpenApiCustomiser intTestOpenApiCustomiser() {
      // this is only added for integration tests
      // so the automatically generated OpenAPI documents do not have a `localhost` server URL with random port
      return openApi -> {
         log.info("intTestOpenApiCustomiser");
         openApi.getInfo().version("v1"); // this works, successfully overriding the value in `api-docs.yaml`
         openApi.servers(List.of(new Server().url("").description("My URL"))); // however, this does not
      };
   }
}

In the generated YAML file, version is "v1" but servers:

servers:
- url: http://localhost:46407/api
  description: Generated server url

Expected behavior

servers:
- url: ""
  description: My URL

Screenshots

No.

Additional context

The main codes will serve the Swagger UI, documentation, etc. at runtime so I do not want to mess up with its own config. However, during the integration test, I'd like to "download" the YAML file so I can publish it somewhere using the build pipeline. I do not want this file to contain the random port server URL in the integration test.

So far as I am aware of, there are 3 ways that I can set this servers field in the YAML file:

  1. In @OpenAPIDefinition.
  2. In @Bean OpenAPI.
  3. In @Bean OpenApiCustomiser.

And I have two different source sets (main and integration tests). I want my application to use the generated URL when serving the Swagger UI, but let it use a fixed, hard-coded server URL in the YAML file when running integration tests so I can "download" the YAML file that does not contain a random server URL.

Other things I tried:

  1. Creating a @Bean OpenAPI in the main config class, instead of using @OpenAPIDefinition, then use the same customizers (in both main and integration tests). This does NOT work.
  2. Setting everything (incl. info, tags, servers, etc.) in a single @Bean OpenAPI in the integration test config class (i.e., without using any customizer). This works as expected. However, this requires me to use two different @Bean OpenAPI, one in main and one in integration tests, which can cause some additional confusions.
  3. Setting servers in the main @OpenAPIDefinition to contain one Server, then the customizer in integration tests works as expected (i.e., it can override the settings I put in @OpenApiDefinition). However, just an experiment: This makes the server URL hardcoded. Even if I set servers to List.of() (empty list) later in a customizer, there is no generated URL in the YAML file.

Some of my guesses, no need to take it serious -- It seems that at some point

  • After @Bean OpenAPI or @OpenAPIDefinition (whichever is used) takes effect,
  • Before @Bean OpenApiCustomiser customisers take effect,

It tries to detect if servers is empty -- if it is not, then it is serving the YAML file containing the servers. However, if it is empty, it is serving the YAML file with servers set to the generated URL, IGNORING servers in the OpenAPI object permanently, which makes it impossible to change the behavior by modifying OpenAPI.servers later in the customisers.

@bfrggit
Copy link
Author

bfrggit commented Jun 24, 2021

Given that

Setting servers in the main @OpenAPIDefinition to contain one Server, then the customizer in integration tests works as expected (i.e., it can override the settings I put in @OpenApiDefinition). However, just an experiment: This makes the server URL hardcoded. Even if I set servers to List.of() (empty list) or null later in a customizer, there is no generated URL in the YAML file.

I would like to know if there is a workaround that could do the reverse as is requested in the issue, i.e., when I am setting servers in the main @OpenAPIDefinition to contain one Server, I can later use a customizer to revert to using auto generated URL? This could also be helpful as a workaround when I want my application and my integration test to use different server URLs (one with auto generated and the other with fixed).

@bnasslahsen
Copy link
Contributor

@bfrggit,

It's possible to use OpenApiCustomiser to override the servers url.
Additionally, i am adding the possibility edf76e8 to use property in combination with @OpenAPIDefinition. So you could inject different urls, depending on your environments.

@bfrggit
Copy link
Author

bfrggit commented Aug 9, 2021

Version 1.5.10

@bnasslahsen I still cannot override the auto-generated server URLs section in the YAML file using customizer, if the server URL is NOT specified in @OpenAPIDefinition.

However, strangely enough, when this happens, the auto generated JSON file contains the overriding URL (i.e., this is what I want), but the YAML file contains the auto-generated server URL.

@bnasslahsen bnasslahsen reopened this Aug 9, 2021
@bnasslahsen
Copy link
Contributor

@bfrggit,

Not reproducible. Working in both json and yaml.
Please read the test related to this commit edf76e8.

And if you believe you are facing an issue, make sure you provide a Minimal, Reproducible Example - with HelloController that reproduces the problem

@vchen8761
Copy link

@bnasslahsen
I am facing this issue too. The linked repo is a reprex of the server field inconsistency in api-docs between JSON and YAML or just refreshing the page.

https://github.com/vchen8761/spring-doc-server-field-test

@bfrggit
Copy link
Author

bfrggit commented Sep 17, 2021

@bnasslahsen Please have a look at the reprex above from my coworker. It seems that the first time when the doc is loaded, it has the intended behavior (custom URL in customizer). However, after a refresh, it rolls back to the randomly generated one.

It turns out that both JSON and YAML are inconsistent after a refresh, so when I downloaded both programmatically, the first downloaded got the custom URL and the second got the randomly generated one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants