Skip to content

New configuration properties #757

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

Closed
wants to merge 1 commit into from

Conversation

maciejkopecpl
Copy link
Contributor

Hey,

In my project, we run into the following challenges when using this awesome library:

  1. We wanted to have the possibility to add a generated server to the server's list even if we've already defined a list of our own servers. Reson why is this important in our case is the following. We have a set of well-known environments (dev, stage, perf, pre-prod, and prod). However, on top of those, some of our teams have their own instances. Obviously, we don't want to keep list of all of them in our swagger documentation, but at the same time, it is extremely useful for those teams to use Swagger UI and have ability to send requests to their instance.

This issue address first new property, called alwaysAddGeneratedServer

  1. One of our standards requires to remove common suffixes from endpoints, e.g.:
    instead of:
    /cms/posts/
    /cms/categories/
    we should define our hostname as: http://hostname/cms and then endpoints should be define as follow:
    /posts
    /categories

Because of this, we couldn't just add a prefix to the endpoints, but we need possibility to add a suffix to the server. This is addressed by the new property: generatedServerSuffix

Both properties are optional.

Add property to always add a generated server to the server's list.
Add property for adding a custom suffix to the generated server hostname.
@bnasslahsen
Copy link
Collaborator

bnasslahsen commented Jun 30, 2020

This enhancement is specific to your environment context.

You can use: OpenAPI Bean definition, to customize your server list. And attach your custom logic.

@Bean
public OpenAPI customOpenAPI() {
	return new OpenAPI().addServersItem(new Server().url("https://myserver.com"))
			.components(new Components().addSecuritySchemes("basicScheme",
					new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")))
			.info(new Info().title("SpringShop API").version("V0")
					.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}

Or just use property configuration properties, where you can declare your server list.

@maciejkopecpl
Copy link
Contributor Author

I think you missed the point of this change.

I can't really use that approach, because I would like to get the current hostname where the app is running, and this information is available only in a controller (OpenApiResource). So, there is no way to customize the generated server. There is also no option to add this generated server to the predefined list because this generated server is calculated at runtime.

I believe that having option to customize the generated server is worth adding. And for sure, the option to have both, predefined list of the server AND generated server is something that many people will use. Usually, you don't want to have in your docs addresses to the dev/stage, etc servers. Only prod and maybe sandbox. However, at the same time, developers would like to have easy way to use swagger UI on those dev/stage environments. When you define that list of servers, generated server is gone.

@bnasslahsen
Copy link
Collaborator

You can use OpenApiCustomiser Bean, where you have access to the original generated server list by springdoc-openapi, and customize it ...

@maciejkopecpl
Copy link
Contributor Author

It won't work. On the bean level, you don't have access to the request context in order to retrieve the hostname of the server where the application is deployed, don't you?

Here is how the server base URL is calculated in OpenApiResource

protected void calculateServerUrl(HttpServletRequest request, String apiDocsUrl) {
		String requestUrl = decode(request.getRequestURL().toString());
		String calculatedUrl = requestUrl.substring(0, requestUrl.length() - apiDocsUrl.length());
		openAPIBuilder.setServerBaseUrl(calculatedUrl);
	}

@bnasslahsen
Copy link
Collaborator

OpenApiCustomiser, handles the final version of the OpenAPI Bean, which containts the calculated serverUrl.
Have you really tried OpenApiCustomiser, before arguing it won't work ?

@maciejkopecpl
Copy link
Contributor Author

Yes, I did. When you define a list of servers then the generated server won't be added to the list, because flag isServersPresent will be set to true. And therefore, the method which adds generated server to the list (OpenAPIBuilder#updateServers()) won't be executed. That's the current behavior.

@bnasslahsen
Copy link
Collaborator

Please add your OpenApiCustomiser code.

@maciejkopecpl
Copy link
Contributor Author

@Bean
	public OpenApiCustomiser openApiCustomiser(){
		return openApi -> openApi.getServers().stream()
				.filter(Objects::nonNull)
				.forEach(server -> server.setUrl(server.getUrl() + "/path"));
	}

In order to get this generated server in this list, it is necessary to get to the request context, grab the request URL, and do the same thing that the library is doing. Something like:

  private @Value(API_DOCS_URL) String apiDocsUrl;
  private @Autowired HttpServletRequest request;

  @Bean
  public OpenApiBuilderCustomiser appendSuffixToServers() {
    return openApiBuilder -> {
      final List<Server> servers = openApiBuilder.getCalculatedOpenAPI().getServers();
      final String requestUrl = request.getRequestURL().toString();
      servers.add(
          new Server().url(requestUrl.substring(0, requestUrl.length() - apiDocsUrl.length())));
      servers.forEach(server -> server.setUrl(server.getUrl() + "/path"));

    };
  }

So it would replicate built-in behavior. I just think that it would be nice to let users turn this option on/off so it won't be necessary to replicate same logic that is already in the library. However, if you think this is superfluous and overkill then let's close it.

Cheers!

bnasslahsen pushed a commit that referenced this pull request Jul 1, 2020
@bnasslahsen
Copy link
Collaborator

Hi @maciejkopecpl,

There was an issue here. openApiCustomisers, should be called at the end, so you can reuse the final version of the calculated servers.
Thank you for pointing this out.
This should be working now with the latest SNAPHOST and the next release:

@Bean
public OpenApiCustomiser openApiCustomiser(){
	return openApi -> openApi.getServers().stream()
			.filter(Objects::nonNull)
			.forEach(server -> server.setUrl(server.getUrl() + "/path"));
}

For the properties, we will let in stand by for the moment, as it seems very specifc customization to your naming environments rules. But can be added in the future, if there a lot of demand on it.

@maciejkopecpl
Copy link
Contributor Author

@bnasslahsen I assumed that order was on purpose ;) When the next release is planned?

@bnasslahsen
Copy link
Collaborator

@maciejkopecpl,

The version v1.4.3 is now released!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants