I have Springfox annotations in the code as follows:
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Options for the endpoint", responseHeaders = {#ResponseHeader(name = "Allow", description = "Verbs allowed")})})
However, the header is not being rendered below the response In Swagger UI.
If I add global response (for internal server error) through Docket, its header renders just fine.
Is this a misconfiguration or what is a problem here?
My problem was that annotation parameter "response" was not set to String.class. It defaults to Void.class and does not render with it.
Corrected code is:
#ApiResponse(code = 200, message = "Options for the endpoint", responseHeaders = {#ResponseHeader(name = "Allow", description = "Verbs allowed", response = String.class)})})
Related
I built a dummy api and I want to test it on swagger. The swagger.json has been successfully generated and executed to show the swagger UI.
But there is the 404 error that cannot find the response part.
How can I solve this?
This is the built swagger UI.
And this is the code.
#Service
#Api
public class className () {
#GET
#Path("/oauth2/authorize")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#ApiOperation(value = "Authorization Grant", notes = "Authorization Grant")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successfully Granted the Authorization"),
#ApiResponse(code = 400, message = "Missing or invalid request body"),
#ApiResponse(code = 403, message = "Forbidden"),
#ApiResponse(code = 404, message = "Schema not found"),
#ApiResponse(code = 500, message = "Internal error")})
public Response authorizationGrant(
#HeaderParam("X-AUTH-TOKEN") final String token,
#HeaderParam("X-CSRF-TOKEN") final String csrftoken,
#ApiParam(value = "Client ID", required = true) #QueryParam("Client ID") final String clientId,
#ApiParam(value = "Scope", required = true) #QueryParam("Scope") final String scope,
#ApiParam(value = "Redirect Uri", required = true) #QueryParam("Redirect Uri") final String redirectUri,
#ApiParam(value = "Response Type", required = true) #QueryParam("Response Type") final String responseType ) throws AccessDeniedException {
return Response
.status(Response.Status.OK)
.entity("{\"hello\": \"This is a JSON response\"}")
.type(MediaType.APPLICATION_JSON)
.build();
}
}
Please tell me what you need more to be clear with this error.
The problem solved!!!
I hope this answer could help for others who are suffered from this trouble. :)
The error was from the #Api Definition part. I should have define the path in that part.
This is the corrected code.
#Path("/oauth2")
#Service
#Api
public class className () {
.....
#GET
#Path("/authorize")
.....
}
As you can see the #Api definition part requires the #Path annotation.
:)
as in the topic. I want to have different operations in swagger with same path and http method but with different content-type. Example:
I'm currently using Spring Boot in version 2.0.5 and Swagger ui in version 2.9.2.
In my API I have two methods to register user:
#RequestMapping(method = RequestMethod.POST, consumes = "application/customer+json", produces = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "Registers a new application customer", notes = "Registers a new application customer.\n", response = CustomerResource.class)
#ApiResponses(value = {
#ApiResponse(code = 201, message = "Customer successfully registered"),
#ApiResponse(code = 409, message = "User with such email is already registered"),
#ApiResponse(code = 422, message = "Customer registration request contains validation errors. Response contains detailed field validation error message"),
#ApiResponse(code = 428, message = "Database error. Application log needs to be checked")})
public ResponseEntity<UserResource> registerCustomer(
#ApiParam(value = "Model representation of the transferred data to register a new customer") #Valid #RequestBody CustomerDto customerDto,
UriComponentsBuilder uriComponentsBuilder, BindingResult bindingResult)
{
...
}
and
#RequestMapping(method = RequestMethod.POST, consumes = "application/partner+json", produces = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "Registers a new application partner", notes = "Registers a new Easy Parking partner.\n", response = PartnerResource.class)
#ApiResponses(value = {
#ApiResponse(code = 201, message = "Partner successfully registered"),
#ApiResponse(code = 409, message = "User with such email is already registered"),
#ApiResponse(code = 422, message = "Partner registration request contains validation errors. Response contains detailed field validation error message"),
#ApiResponse(code = 428, message = "Database error. Application log needs to be checked")})
public ResponseEntity<UserResource> registerPartner(
#ApiParam(value = "Model representation of the transferred data to register a new user") #Valid #RequestBody PartnerDto partnerDto,
UriComponentsBuilder uriComponentsBuilder, BindingResult bindingResult)
{ ... }
I want to have one POST path: /api/users to register two types of user: customer and partner. Two operations are required because partner has slightly different attributes than customer. I want to use content-type (consumes) to have different operations but swagger seems to work only with path and http method. Isn't it a bug?? Is there a way to configure it in Spring Boot Swagger?
I like Swagger because it makes your apis very user friendly. I use Swagger annotations like
#ApiParam
#ApiResponse | #ApiResponses
#ApiOperation
Others
On endpoints, query params, request params, request body and so on.
I like to keep my POJO classes clean and in general I try my best to follow DRY rule however, when it comes to swagger I noticed that I keep repeating myself over and over as shown below
#ApiOperation(value = "Retrieve object by id")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 500, message = "ISE")
})
public Response retrieveById(#ApiParam(value = "Some id") #PathParam("sid") int id) {
}
#ApiOperation(value = "Create object")
#ApiResponses(value = {
#ApiResponse(code = 201, message = "Created"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 500, message = "ISE")
})
public Response create(#ApiParam(value = "Request body") RequestBody body) {
}
How to avoid repeating yourself with Swagger annotations?
I did some Googling around and came across this github issue and some other SO questions that are not directly related to ApiResponses annotations and none of them seem to present a working solution.
Using Swagger UI 2.0 I thought let's give it a try, so I did the following
I created a custom annotations GroupedApiResponses..
I annotated GroupedApiResponses.. with a group of Swagger annotations
I used the GroupedApiResponses.. annotations on top of endpoints
Works just like before
See below
package com.raf.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Ok"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 500, message = "ISE")
})
public #interface GroupedApiResponsesAvecOk {
}
Similarly (you can group annotations as you want in one or more than one custom annotation depending on structure of your endpoints and the response messages it return)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#ApiResponses(value = {
#ApiResponse(code = 201, message = "Created"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 500, message = "ISE")
})
public #interface GroupedApiResponsesAvecCreated {
}
And then I used the above #GroupedApiResponsesAvecOk on retrieveById and #GroupedApiResponsesAvecCreated on create endpoint in place of #ApiResponses and worked it just like before.
As shown above, the ApiResponse annotations relating to 400, 404, 500 can now be reused across other endpoints.
I use swagger to create a RESTful API, and have several endpoints which return the same errors and responses:
#GET
#Path("/some/endpoint")
#ApiOperation(
value = "Some method",
notes = "Some method")
#ApiResponses(
value = {
#ApiResponse(code = 200, message = RestConstants.HTTP_200, response = Response.class),
#ApiResponse(code = 400, message = RestConstants.HTTP_400, response = Error.class),
#ApiResponse(code = 401, message = RestConstants.HTTP_401, response = Error.class),
#ApiResponse(code = 403, message = RestConstants.HTTP_403, response = Error.class),
#ApiResponse(code = 404, message = RestConstants.HTTP_404, response = Error.class),
#ApiResponse(code = 500, message = RestConstants.HTTP_500, response = Error.class)
})
public Response someMethod(){...}
The amount of #ApiResonses is may about to change. As of now, I need to declare all of theses for my individual endpoint methods.
Is there a way to use a constant value as an #ApiResponses value, e.g. like:
#ApiResponses(value = MY_RESPONSES)
Am I missing something?
This unfortunately isn't possible using the Swagger annotations.
For this to work ApiResponse would have to be a normal class/interface rather than an annotation.
I'm having trouble with Swagger understanding Play! 2.0 routing wildcard routing, so the swagger ui ends up with broken URL.
My routes file has this route:
GET /settings/api/:project/*path #controllers.API.getParams(project, path)
Then my Controller has the following code:
#ApiOperation(value = "Returns settings for given project and path.", response = String.class, httpMethod = "GET")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Request completed successfully."),
#ApiResponse(code = 500, message = "Internal error while processing request")
})
#ApiImplicitParams({
#ApiImplicitParam(name = "project", value = "Project name", required = true, dataType = "String", paramType = "path"),
#ApiImplicitParam(name = "path", value = "path", required = true, dataType = "String", paramType = "path")
})
public Result getParams(String project, String path) {
return ok(path);
}
Then when Swagger UI gets rendered, I see the path for this action rendered as
POST /settings/api/{project}/{path<.+>
And when I do a call it turns into
/settings/api/test/{path<.+>
So basically the :project gets replaced but the *path remains broken/intact.
Please share if you know how to fix this. Thanks!
So turns out that swagger doesn't support wildcard routes.