Swagger2 in Spring Boot app doesn't pick up #ApiResponses with custom Docket - spring-boot

I have a controller handler method:
#ApiResponses({
#ApiResponse(code = 201, message = "aaa", response = Response.class),
#ApiResponse(code = 400, message = "bbb")
})
#PostMapping("api/aa")
public Response save() {
...
}
...
Whenever I add a custom Docket configuration as below. #ApiResponse defined in #ApiResponses don't seem to work anymore. As I no longer see them showing up on the UI or under v2/api-docs's json. Any ideas what I am missing?
#Bean
public Docket api() {
return new Docket(DocumentationType.SPRING_WEB)
.host(kongHost)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.mypackage.controller"))
.paths(PathSelectors.ant("/api/*"))
.build();
}

Turns out I would need to specify the DocumentationType to be SWAGGER_2

Related

For java Controller swagger-ui.html renders unexpected http codes

I have the following java endpoint inside a Springboot RestController annotated with some Swagger annotations for 4 ApiResponses:
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successfully sign in"),
#ApiResponse(code = 400, message = "Missing request body"),
#ApiResponse(code = 404, message = "Schema not found"),
#ApiResponse(code = 500, message = "Internal error")
})
#PostMapping(
path = "/login",
produces = "application/json; charset=utf-8")
public LoginResponse login(
#ApiParam(
name="cred",
value="Credenciales de quien intenta ingresar al sistema")
#RequestBody CredencialesRequest cred
) throws ControllerException {
return accessService.login(cred.getUsuario(), cred.getClave());
}
As you can see, I have declared 4 response codes as a possible HTTP responses: 200, 400, 404 and 500
When I run the application and go to http://localhost:8080/swagger-ui.html the UI shows the 4 codes that I have described in the endpoint. However, it shows MORE http codes. Please take a look at this picture:
The extra codes are: 201 (created), 401 (unauthorized) & 403 (forbidden). Why? For my use case, the "login" endpoint should be always accessible to any user, so at least, 401 & 403 doesn't make sense at all, in this context.
Just like it was said in the comments, in order to remove the extra http codes in the swagger UI, we need to modify our configuration file by adding useDefaultResponseMessages(false) to the api() method in our SwaggerConfig like this:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false) // I HAD TO ADD THIS LINE !!!!
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
That's it !

Swagger 3 Required Global Request Parameter

I am using Spring Boot 2.5.4 with Swagger 3. I have added one Global Request Parameter as type header and required=true in Swagger Config file .
Swagger UI is correctly showing the required request header in all APIs but the problem is that it's allowing requests to be sent when the value is empty for required request header. In Swagger 2 , UI used to disable sending request until the value was filled.
Any suggestions.
#Bean
public Docket api() {
RequestParameterBuilder aParameterBuilder = new RequestParameterBuilder();
aParameterBuilder.name("x-remote-user").description("Remote User").in(ParameterType.HEADER).required(true)
.build();
List<RequestParameter> aParameters = new ArrayList<>();
aParameters.add(aParameterBuilder.build());
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.securityContexts(Arrays.asList(securityContext())).securitySchemes(Arrays.asList(apiKey())).select()
.apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
.paths(PathSelectors.ant("/api/**")).build().globalRequestParameters(aParameters);
}
I found out the solution . Posting it here if someone else is looking for it .
If we disallow empty values , then swagger UI starts blocking us from Executing API if header value is kept empty.
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.securityContexts(Arrays.asList(securityContext())).securitySchemes(Arrays.asList(apiKey())).select()
.apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
.paths(PathSelectors.ant("/api/**")).build()
.globalRequestParameters(Arrays.asList(new RequestParameterBuilder().name("x-remote-user")
.description("Remote User").in(ParameterType.HEADER).required(true)
.query(simpleParameterSpecificationBuilder -> simpleParameterSpecificationBuilder
.allowEmptyValue(false).model(modelSpecificationBuilder -> modelSpecificationBuilder
.scalarModel(ScalarType.STRING)))
.build()));
}
it maybe help you
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(this::selector)
.build();
}
boolean selector(OperationContext operationContext) {
String url = operationContext.requestMappingPattern();
// filter url
return true;
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "Authorization header");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Collections.singletonList(new SecurityReference("Authorization", authorizationScopes));
}
private List<SecurityScheme> securitySchemeList(){
ApiKey apiKey = new ApiKey("Authorization", "Authorization token", "header");
return Collections.singletonList(apiKey);
}
private List<RequestParameter> globalRequestParameters() {
RequestParameterBuilder parameterBuilder = new RequestParameterBuilder()
.in(ParameterType.HEADER)
.name("Authorization")
.required(true)
.query(param -> param.model(model -> model.scalarModel(ScalarType.STRING)));
return Collections.singletonList(parameterBuilder.build());
}
#Bean
public Docket authorization() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.securityContexts(Collections.singletonList(securityContext()))
.securitySchemes(securitySchemeList())
.globalRequestParameters(globalRequestParameters())
.select()
.paths(PathSelectors.regex("^(?!/error).*"))
.build()
;
}

Hide internal parameters from Spring interface for Swagger UI

I have an folowing endpoint:
#PostMapping(value = "/home", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Mono<String> getData(ServerWebExchange exchange) { return Mono.empty(); }
The ServerWebExchange object is implemented in org.springframework.web.server.
When I run it, in Swagger all the getters objects are shown. While I only need the body (I want to hide the reqest and the respone objects).
Tried to use
.ignoredParameterTypes(Principal.class, ServerHttpRequest.class, ServerHttpResponse.class)
But, it didn't had any effect.
Is there a way to hide those?
Solution found:
Desable the SeverWebExchange interface for swagger
Configure requier input.
`
#PostMapping(value = "/home", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ApiImplicitParams({
#ApiImplicitParam(name = "Body Params", paramType = "body")
})
public Mono<String> getData(
#ApiIgnore ServerWebExchange exchange
) {
return Mono.empty();
}

swagger doesn't recognize api description

I instatiate docket like this
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.config.internal"))
.paths(Predicates.or(PathSelectors.ant("/api**/**")))
.build();
}
I created a set of stub endpoints that imitate the real one for /login or /oauth.
#Api("Authentication")
#RequestMapping("/api")
public interface LoginEndpointApi {
#ApiOperation(value = "Github SSO endpoint", notes = "Endpoint for Github SSO authentication")
#ApiResponses({
#ApiResponse(code = 200, message = "HTML page of main application")
})
#GetMapping("/oauth/github")
default void oauthGithub() {
throw new UnsupportedOperationException();
}
#ApiOperation(value = "Get CSRF token", notes = "Returns current CSRF token")
#ApiResponses({
#ApiResponse(code = 200, message = "CSRF token response", response = String.class,
examples = #Example({#ExampleProperty(value = "015275eb-293d-4ce9-ba07-ff5e1c348092")}))
})
#GetMapping("/csrf-token")
default void csrfToken() {
throw new UnsupportedOperationException();
}
#ApiOperation(value = "Login endpoint", notes = "Login endpoint for authorization")
#ApiResponses({
#ApiResponse(code = 200, message = "Successful authentication")
})
#PostMapping("/login")
default void login(
#ApiParam(required = true, name = "login", value = "login body")
#RequestBody LoginRequest loginRequest) {
throw new UnsupportedOperationException();
}
}
But it doesn't recognize it. It is located in the same com.config.internal package as I described.
But the page swagger ui is empty and shows that No operations defined in spec!
What is the problem?
If you want to provide swagger documentation for your request mappings specified above you could simply describe it with .paths(Predicates.or(PathSelectors.ant("/api/**"))) path matchers. But if your path includes something more complicated like api + text without backslash separator then you should get known with
https://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/util/AntPathMatcher.html

Spring + Springfox + Header Parameters

#RequestMapping(...)
public Foo getFoo(#HeaderParam("header") final String header) {
...
}
Adding a #HeaderParam method parameter as above springfox picks it up and when I look at the swagger-ui it has a field for the header. This is exactly what I want. Is there a way I can tell springfox to include this header parameter on a set of methods without having to include the parameters on the method itself? What we really have going on is a servlet filter which uses the header and we'd like an easy to set it through the swagger-ui.
You could use the globalOperationParametersin the docket definition. For e.g.
new Docket(...)
.globalOperationParameters(
Arrays.asList(new ParameterBuilder()
.name("header")
.description("Description of header")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(true)
.build()))
See #22 in the documentation for more information.
One more explained answer for same :-
#Bean
public Docket api() {
//Adding Header
ParameterBuilder aParameterBuilder = new ParameterBuilder();
aParameterBuilder.name("headerName").modelRef(new ModelRef("string")).parameterType("header").required(true).build();
List<Parameter> aParameters = new ArrayList<Parameter>();
aParameters.add(aParameterBuilder.build());
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build().apiInfo(apiInfo()).pathMapping("").globalOperationParameters(aParameters);
}

Resources