How to integrate Zuul with Swagger - spring

I faced with some issue generating swagger documentaion in my microservices project. When I add zuul custom routings swagger documentation becames inconsistent.
Examples:
RestController:
#RestController
public class Controller {
#PostMapping("/foo")
public void foo() {}
}
Zuul routings:
zuul:
routes:
foo:
path: /bar/**
url: http://localhost:8080/foo
Swagger configuration
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("my.package"))
.build();
}
}
What I need: Swagger UI displays /bar endpoint
What I get: Swagger UI displays /foo endpoint (and it's useless for frontend developers because they generates their components in runtime using swagger)
So, is there any solution how can I configure swagger or zuul to avoid the problem?

We had to add zuul configuration in application.yml file.
# custom configuration - used by swagger to rename endpoints in documentation
springfox:
documentation:
swagger:
v2:
path: /api/uaa/api-docs
whitelistInternal:
- method: GET
path: '/api/**/api-docs'
- method: GET
path: '/swagger-ui.html'
- method: GET
path: '/swagger-resources/**'
Please, check lines that suit you.
This is an example how it can be done
https://dzone.com/articles/centralized-documentation-in-microservice-spring-b

Related

How do I hide endpoints only for a specific profile in spring boot?

I am using open api 3 and want to hide some endpoints in swagger ui. In swagger2 I found what can be done in this way by creating my own annotation, but I don't understand how I can do it in openapi3.
#Bean
public Docket postsApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("public-api")
.apiInfo(apiInfo())
.select()
// This is the part that will ignore the method
.apis((handler) -> !handler.isAnnotatedWith(IgnoreForProd.class))
.build();
}
I've solved this issue like this:
1st - I have removed the springfox and springfox-swagger-ui dependencies from pom.xml and replaced it with springdoc-openapi-ui like this:
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.6</version>
2nd - created the Bean below:
#Configuration
public class OpenAPIConfig {
#Value("${version:unknown}")
private String version;
#Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("Title API")
.description("Description API")
.version(version)
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
}
3rd - then on application.yml you can filter by package and/or path:
springdoc:
packages-to-scan: com.company.projectxyz.controller
pathsToMatch: /api/whatever/public/**
4th - and if you need to filter different paths/packages per profile, also on application.yml you can do the 3rd step inside of:
spring.config.activate.on-profile: dev/qa/prod...
and access your swagger at /swagger-ui/index.html
I hope it helps =)

Security is not added to Swagger from Open API generator

I am working on a new project in my team and we are implementing an API following the API first methodology. We are using openapi-generator-maven-plugin to generate our API from an yml file of format OpenAPI 3.0.3. To generate the swagger file we use springfox 2.9.2. The issue that I am facing is when I am trying to add security to the swagger for the requests.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: [ ]
The Authorize button doesn't appear in swagger page, only the lock near to the request appears but it doesn't do anything (see picture below).
What I observed is that if I open the /v2/api-docs the swagger json doesn't include the security definitions part.
The only way that I managed to add security is by adding by code in the Docket object the security part like so:
new Docket(DocumentationType.SWAGGER_2)
.securityContexts(Collections.singletonList(securityContext()))
.securitySchemes(Collections.singletonList(bearerJwtKey()))
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build();
Is this the only way to add security to Swagger UI or am I missing something?
Reason: Bearer Auth isn't implemented in spring library yet :(
Workaround solution - extend generated Docket:
Import generated config class and then add a security schema (ApiKey) to the existing Docket bean. Example:
#Configuration
#Import(OpenAPIDocumentationConfig.class) // openapi generated config class
public class SwaggerConfiguration {
#Autowired
ApplicationContext context;
#PostConstruct
public void extendExistingDocketWithSecurity() {
Docket docket = context.getBean(Docket.class);
docker.securitySchemes(Collections.singletonList(bearer()));
}
private static ApiKey bearer() {
// where "bearerAuth" - name of your schema in YML spec. file
return new ApiKey ("bearerAuth", HttpHeaders.AUTHORIZATION, "header");
}
Done! You're awesome!
Now you're using generated swagger config without overriding, but just extending

Adding Actuator as a groupedOpenApi

Could we add Actuator endpoints as a groupedOpenApi that will be gourped separately ?
ex :
#bean
public GroupedOpenApi actuatorApi() {
return GroupedOpenApi.builder().setGroup("Actuator")
.packagesToScan("org.springframework.boot.actuate")
.pathsToMatch("/actuator/**")
.build();
}
Thanks
First you need to enable actuator on the swagger-ui:
springdoc.show-actuator=true
You just need to declare GroupedOpenApi bean:
#Bean
public GroupedOpenApi actuatorApi(){
String[] paths = {"/actuator/**"};
return GroupedOpenApi.builder()
.setGroup("groups")
.pathsToMatch(paths)
.build();
}
Here are the steps to add actuator:
https://github.com/springdoc/springdoc-openapi-demos/commit/aa6bcf1f0312c8fc36f94aeb4653718b36c308f6
The solution provided by #brianbro mostly works but there is an issue where some endpoints that use parameters in URL, e.g. /actuator/metrics/{requiredMetricName} due to way spring boot handles the actuator endpoints (single handler method, no #PathParam) the PathParam fields don't show in Swagger. See Spring boot actuator endpoint parameters issue.
Example of what shows in Swagger without resolving the issue:
Example of what shows in Swagger after resolving the issue:
How to fix this is discussed in Adding Actuator as a groupedOpenApi but some of the links are broken. The key issue is there is an ActuatorOpenApiCustomiser class that is used to fix the PathParams for Actuator, and that class is not being called when Actuator resides within a GroupedOpenApi.
Full solution (working with springdoc:1.6.9)...
First you need to enable actuator on the swagger-ui:
springdoc.show-actuator=true
Declare GroupedOpenApi bean using code (you can't use the springdoc.group-configs[0] properties because you need to add a OpenApiCustomiser to the group):
#Bean
public GroupedOpenApi actuatorApi(OpenApiCustomiser actuatorOpenApiCustomiser){
String[] paths = {"/actuator/**"};
return GroupedOpenApi.builder()
.setGroup("Actuator")
.pathsToMatch(paths)
.addOpenApiCustomiser(actuatorOpenApiCustomiser)
.build();
}
Addtional Sample from SpringDoc

Adding base path to swagger documentaion

I am trying to change the base path of swagger codumentation. Currently I have
#RequestMapping(path = "/api/resourceName/v1")
and swagger config
return new Docket(DocumentationType.SWAGGER_2).
select()
.apis(RequestHandlerSelectors.basePackage("com.company"))
.paths(PathSelectors.ant("/api/**"))
.build()
.apiInfo(apiInfo());
This is giving swagger base path as "basePath": "/"
I want to add base path as "basePath": "/api" so I followed diff threads like this How to change basePath for Springfox Swagger 2.0 and added
return new Docket(DocumentationType.SWAGGER_2).
select()
.apis(RequestHandlerSelectors.basePackage("com.company"))
.paths(PathSelectors.ant("/api/**"))
.build()
.apiInfo(apiInfo())
.pathProvider(new RelativePathProvider(servletContext) {
#Override
public String getApplicationBasePath() {
return "/api";
}
});
now the base path is changed to "basePath": "/api" and I updated my path mapping to #RequestMapping(path = "/resourceName/v1") as base has been added.
When I send the request from swagger, the request is going to /api/resourceName/v1 but the service returns 404.
When I send the request through postman for /resourceName.v1 then it works.
So the api is registred as /resourceName/v1 and the base is just added by swagger on top of it and will not work if the request sent throguh swagger UI
Then I added server.servlet-path=/api to application.properties to register basepath in the request mapping and now swagger shows the base path as /api without needing additional configuration.
But the problem is now swagger documentation is available at http://localhost:8080/api/swagger-ui.html instead of http://localhost:8080/swagger-ui.html. As we have all our other services doc at http://host/swagger-ui.html this is not useful.
Is there any way to add the base and still access the doc at http://host/swagger-ui.html and api's works as expected fro swagger and postman
Yes, you can add base path for all swagger requests. I used following config for this purpose:
#Configuration
#EnableSwagger2
public class SpringFoxConfig {
#Bean
public Docket api() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
docket.pathMapping("api");
return docket;
}
}
Hope this helps.
There is way to change the api-doc base path using properties defined in application.properties file.
The properties are:
springfox.documentation.openApi.v3.path=/external/api/app/v3/api-docs
springfox.documentation.swaggerv2.path=/external/api/app/v2/api-docs
This can help you to change the path.

Hide Feign client endpoints in Swagger

I am using Springboot autoconfiguration, and currently all my Feign endpoints are exposed in swagger-ui. How can I disable this feature?
You can set this in your application.properties as:
endpoints.enabled=false
endpoints.health.enabled=true
endpoints.loggers.enabled=true
In your case it will be something like
endpoints.feign.***=true
But this is not disabling for swagger but endpoints exposure themselves. For Swagger you have to markup them explicitly with #Api#hidden() for example.
So far the best way to not include unrelated endpoints is through Swagger Docker, e.g.
#Configuration
#EnableSwagger2
class SwaggerConf {
#Bean
Docket allApis() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("all")
.select().apis(RequestHandlerSelectors.basePackage("com.example.base"))
.build();
}
}
Simplest solution that worked for me is to add #ApiIgnore to the Feign Client
#ApiIgnore
#FeignClient()
public interface FeignApi {
}

Resources