How to have custom context Path for Swagger Url in OpenApi3 Springboot Application

7.1k views Asked by At

I am migrating from springfox to OpenApi3 in my Springboot project as we have a requirement to upgrade to latest springboot with version 2.7.0

I need to configure custom contextPath for different environments like below

dev - https://qa.swagger.com/dev/api/myApp/swagger-ui/index.html

qa - https://qa.swagger.com/api/myApp/swagger-ui/index.html

uat - https://uat.swagger.com/api/myApp/swagger-ui/index.html#/

// pom.xml

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

<dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.8</version>
        </dependency>

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-webmvc-core</artifactId>
            <version>1.6.8</version>
        </dependency>

// SwaggerConfig class

@Configuration
@Profile({ "local", "dev", "qat", "uat" })
public class SwaggerConfig {

@Bean
    public OpenAPI openAPI() {

        return new OpenAPI().info(info());
    }
    
    private Info info() {
         return new Info()
        .title(title)
        .version(version)
        .license(new License().name(licenseName).url(licenseUrl));
        }
}

//application.properties

spring.application.name=myApp
server.servlet.context-path=/api/${spring.application.name}

With the above configuration, I am able to run swagger using below url and getting all required response from controller apis http://localhost:8082/api/myApp/swagger-ui/index.html#/

For configuring the Swagger url for other environments,I tried to create a listener configuration class like below which didn't work

@Component
public class SwaggerListener implements ApplicationListener<ApplicationPreparedEvent> {

    final ApplicationPreparedEvent event = null;

    @Override
    public void onApplicationEvent(final ApplicationPreparedEvent event) {

        ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();

        Properties properties = new Properties();
        properties.put("springdoc.swagger-ui.path", swaggerPath(event));
        environment.getPropertySources().addFirst(new PropertiesPropertySource("programmatically", properties));

    }

    private String swaggerPath(final ApplicationPreparedEvent event) {
        String basePath = null;
        String swagger = "swagger-ui/index.html";
        ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
        String[] profilesList = environment.getActiveProfiles();
        List<String> profiles = Arrays.asList(profilesList);
        String contextPath = environment.getProperty("server.servlet.context-path");
        if (profiles != null && (profiles.contains("local"))) {
            basePath = swagger;
        } else if (profiles != null && profiles.contains("dev")) {
            basePath = "/dev/api/myApp/" + swagger;
        } else if (profiles != null && (profiles.contains("qat") || profiles.contains("uat"))) {
            basePath = "/api/myApp/";

        }
        return basePath;
    }

}

Adding above listener to main class

@SpringBootApplication(scanBasePackages = { "com.myApp.controller" })
@OpenAPIDefinition
public class myApi {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(myApi.class);
        springApplication.addListeners(new SwaggerListener());      
        springApplication.run(args);

    }

}

The above listener configuration is not working Can anyone help me out here and let me know what am I missing here ?

1

There are 1 answers

0
Alejandro Virgili On

I have been looking the same. This documentation help me:

To enable the support of multiple OpenAPI definitions, a bean of type GroupedOpenApi needs to be defined.

For the following Group definition(based on package path), the OpenAPI description URL will be : /v3/api-docs/stores

@Bean
public GroupedOpenApi storeOpenApi() {
   String paths[] = {"/store/**"};
   return GroupedOpenApi.builder().group("stores").pathsToMatch(paths)
         .build();
}

For the following Group definition (based on package name), the OpenAPI description URL will be: /v3/api-docs/users

@Bean
public GroupedOpenApi userOpenApi() {
   String packagesToscan[] = {"test.org.springdoc.api.app68.api.user"};
   return GroupedOpenApi.builder().group("users").packagesToScan(packagesToscan)
         .build();
}

For the following Group definition(based on path), the OpenAPI description URL will be: /v3/api-docs/pets

@Bean
public GroupedOpenApi petOpenApi() {
   String paths[] = {"/pet/**"};
   return GroupedOpenApi.builder().group("pets").pathsToMatch(paths)
         .build();
}

For the following Group definition (based on package name and path), the OpenAPI description URL will be: /v3/api-docs/groups

@Bean
public GroupedOpenApi groupOpenApi() {
   String paths[] = {"/v1/**"};
   String packagesToscan[] = {"test.org.springdoc.api.app68.api.user", "test.org.springdoc.api.app68.api.store"};
   return GroupedOpenApi.builder().group("groups").pathsToMatch(paths).packagesToScan(packagesToscan)
         .build();
}

Source: SPRINDOC