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.
Related
I have a microservice that need to consume from another microservice. The thing is that the controller has an authentication header. So how can I get that token from it to make a call from this new rest client?
I have used swagger codegen to get the different endpoints that I need to check.
The interface is as follows:
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-06-20T09:40:39.340424400+02:00[Europe/Berlin]")
#Api(value = "getRelationByCucoId", description = "the getRelationByCucoId API")
public interface GetRelationByCucoIdApi {
#ApiOperation(value = "Retrieve a list of CustomerIDs for a certain CucoId", nickname = "getRelationByCucoIdUsingGET", notes = "This is a description", response = CucoPerson.class, responseContainer = "List", tags={ "Customers", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successfully retrieved list", response = CucoPerson.class, responseContainer = "List"),
#ApiResponse(code = 400, message = "The provided CucoID format or length is incorrect (Integer up to 10 digit)"),
#ApiResponse(code = 401, message = "You are not authorized to view the resource, check if the JWT was provided in the header"),
#ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
#RequestMapping(value = "/getRelationByCucoId/{cucoId}",
produces = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<CucoPerson>> getRelationByCucoIdUsingGET(#ApiParam(value = "cucoId",required=true) #PathVariable("cucoId") Integer cucoId
,#ApiParam(value = "Authentication Header" ) #RequestHeader(value="GS-AUTH-TOKEN", required=false) String GS_AUTH_TOKEN, #AuthenticationPrincipal Principal principal
);
}
And the implementation:
#Override
public ResponseEntity<List<CucoPerson>> getRelationByCucoIdUsingGET(Integer cucoId, String GS_AUTH_TOKEN, Principal principal) {
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK);
}
So how can I get it authenticated?
Thanks!
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 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)})})
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.