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!
Related
I am currently migrating from springfox to springdoc-openapi-ui and have run into some issues that the migration documentation does not touch on.
I am getting the error Cannot resolve method 'response' at response = Example.class and response = ErrorResponse.class below.
I've tried using responses instead but had no luck.
With springfox, my code looked like this:
#ApiOperation(
value = "sample summary",
response = Example.class,
notes = "sample description")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successful"),
#ApiResponse(code = 400, message = "Bad Request", response = ErrorResponse.class),
#ApiResponse(code = 401, message = "Not Authorized", response = ErrorResponse.class),
#ApiResponse(code = 403, message = "Forbidden", response = ErrorResponse.class),
#ApiResponse(code = 404, message = "Not Found", response = ErrorResponse.class)})
#PostMapping(value = {"/sampleEndpoint"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
after migrating to springdoc, here's where it stands:
#Operation(
summary = "sample summary",
response = Example.class,
description = "sample description")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "Successful"),
#ApiResponse(responseCode = "400", description = "Bad Request", response = ErrorResponse.class),
#ApiResponse(responseCode = "401", description = "Not Authorized", response = ErrorResponse.class),
#ApiResponse(responseCode = "403", description = "Forbidden", response = ErrorResponse.class),
#ApiResponse(responseCode = "404", description = "Not Found", response = ErrorResponse.class)})
#PostMapping(value = {"/sampleEndpoint"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
You can use
content = #Content(mediaType =...,schema = #Schema(implementation=...))
You didn't show the rest of your code, but I'm assuming you're returning your ErrorResponse class as json in the 4xx responses?
If so, I think the spring-doc definition would look something like this:
#ApiResponse(responseCode = "400", description = "Bad Request", content = #Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = #Schema(implementation = ErrorResponse.class)))
I couldn't find a direct example of this on the base spring-doc page, but how to hide a schema has something similar: https://springdoc.org/#how-can-i-hide-schema-of-the-the-response
Edit for your comments:
Since you specified the produces type in the PostMapping spring-doc will infer this for all responses by default, so there's no need to specify that in the #Content annotation.
It's not entirely clear to me what your method signature looks like:
Are you returning ResponseEntity<String> and mapping the json in the error response yourself?
Or are you returning ResponseEntity<ErrorResponse> and then returning an empty body on 200?
spring-doc will automatically attempt to infer the response schema based on the return type, so if you're doing the second one, you won't need to specify the #Content type at all (except on the 200 response where you're returning an empty body, where you'll want to specify just by using an empty #Content annotation to omit the schema).
Example of #1
If you'd like the schema (with examples) to show up in your spring-doc interface you're going to want to include the schema = #Schema(implementation = ...) portion.
Here's a further example of what I think you might be trying to achieve:
#Operation(summary = "sample summary",
description = "sample description")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "Successful", content = #Content),
#ApiResponse(responseCode = "400", description = "Bad Request", content =
#Content(schema = #Schema(implementation = ErrorResponse.class))),
#ApiResponse(responseCode = "401", description = "Not Authorized", content =
#Content(schema = #Schema(implementation = ErrorResponse.class))),
#ApiResponse(responseCode = "403", description = "Forbidden", content =
#Content(schema = #Schema(implementation = ErrorResponse.class))),
#ApiResponse(responseCode = "404", description = "Not Found", content =
#Content(schema = #Schema(implementation = ErrorResponse.class)))
})
#PostMapping(value = {"/sampleEndpoint"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> postSampleEndpoint() {
// just a fake response here
ErrorResponse exampleErrorResponse = new ErrorResponse("fakeErrorDescription", "fakeSuggestion");
ObjectMapper mapper = new ObjectMapper();
String jsonErrorResult;
try {
jsonErrorResult = mapper.writeValueAsString(exampleErrorResponse);
} catch (JsonProcessingException e) {
// fill the json error manually with something else if mapping fails
throw new RuntimeException(e);
}
return new ResponseEntity<>(jsonErrorResult, HttpStatus.BAD_REQUEST);
}
Example of #2
#Operation(summary = "sample summary",
description = "sample description")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "Successful", content = #Content),
#ApiResponse(responseCode = "400", description = "Bad Request"),
#ApiResponse(responseCode = "401", description = "Not Authorized"),
#ApiResponse(responseCode = "403", description = "Forbidden"),
#ApiResponse(responseCode = "404", description = "Not Found")
})
#PostMapping(value = {"/sampleEndpoint"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ErrorResponse> postSampleEndpoint() {
// just a fake response here
ErrorResponse exampleErrorResponse = new ErrorResponse("fakeErrorDescription", "fakeSuggestion");
return new ResponseEntity<>(exampleErrorResponse, HttpStatus.BAD_REQUEST);
}
Then in the ErrorResponse model class you can use the #Schema annotation to provide examples:
ErrorResponse.java:
public class ErrorResponse {
#JsonProperty("error_description")
#Schema(example = "Example Error Description")
private String errorDescription;
#Schema(example = "Example Suggestion")
private String suggestion;
public ErrorResponse(String errorDescription, String suggestion) {
this.errorDescription = errorDescription;
this.suggestion = suggestion;
}
public String getErrorDescription() {
return errorDescription;
}
public void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public String getSuggestion() {
return suggestion;
}
public void setSuggestion(String suggestion) {
this.suggestion = suggestion;
}
}
Which generates a swagger doc UI like this:
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 a gateway defined like this:
<int:gateway
service-interface="com.charter.egateway.integration.accountbase.AccountBaseSearchServiceInterface"
default-reply-timeout="13000" >
<int:method name="search" request-channel="accountBaseRequestChannel" reply-channel="accountBaseResponseChannel" />
</int:gateway>
When it timeouts after 13s, my code below receives a 'null' - but I'm using 'null' for 'null responses', i.e, responses without content:
#Secured(SecurityRoles.ROLE_READ)
#RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE, value = "search", method = RequestMethod.GET)
#ApiOperation(
value = "This service works like a single entry to execute searches on Salesforce",
notes = "Returns a list of accounts."
)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success", response = AccountSearchResponse.class),
#ApiResponse(code = 400, message = "Invalid request.", response = ErrorResponse.class, responseContainer="List"),
#ApiResponse(code = 500, message = "Internal Server Error.", response = ErrorResponse.class, responseContainer="List"),
#ApiResponse(code = 204, message = "No content.", response = AccountSearchResponse.class)
})
public ResponseEntity<?> search(#Valid AccountSearchRequest objectSearch) {
logger.debug("Returning request: {}.", objectSearch.toString());
ResponseEntity<ErrorResponse>response = RequestMessageValidator.validate(objectSearch);
if (null != response) {
logger.debug("Returning ErrorResponse: {}.", response.toString());
return response;
}
Message<AccountSearchRequest> requestMsg = MessageBuilder.withPayload(objectSearch).setCorrelationId(transaction.getTransactionId()).build();
EndAccountSearchResponse searchResponse = (EndAccountSearchResponse) service.search(requestMsg);
if(searchResponse==null){
logger.debug("Returning no content.");
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
logger.debug("Returning Response: {}.", searchResponse.toString());
return ResponseEntity.ok(searchResponse);
}
How can I differentiate outcome from timeout, which is null from 'no content' (searchResponse == null)?
Regards,
You can't "return null". null is an invalid message payload; when a component in an integration flow returns null; the flow stops; nothing is sent back to the gateway. The gateway will always time out (and return null) in this case.
You should either return a special value indicating no result, or throw an exception (and catch it).
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.