How to document error messages using Spring Rest Doc - spring

I'm using Spring rest doc along spring mvc test to generate a restful documentation. Now I'm trying to describe the possible error messages on the resource, but I cannot find anything that will help me in the spring documentation.
What I'm trying to achieve is similar to Error 4xx section of http://apidocjs.com/example/
Any thoughts ?

Just create a test that intentionally generates an error response. And document the fields like you would with any other Spring Rest Docs test.
#Test
public void errorExample() throws Exception {
RestDocumentationResultHandler docs = document("Error Response",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
responseFields(
fieldWithPath("status").optional().type("Integer").description("Application status field."),
fieldWithPath("errorMsg").type("String").description("A global description of the cause of the error")
)
);
AppConfig req = getAppConfigReq(null, null, null);
ResultActions result = this.mockMvc.perform( post("/SomeAPICall/")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(req))
);
result.andExpect(status().is(401));
result.andDo(docs);
}

Related

Error handling on quarkus mutiny rest client

On my quarkus rest project i have a restclient that uses mutiny:
#Path("/")
#RegisterRestClient(configKey = "my-api")
#RegisterClientHeaders
#RegisterProvider(MyExceptionMapper.class)
public interface MyClient {
#POST
#Path("path")
Uni<MyBean> get(String body);
}
I wanna handle propery non 2XX httpError so i have made my ExceptionMaper
public class MyExceptionMapper implements ResponseExceptionMapper<MyException> {
#Override
public MyException toThrowable(Response response) {
//TODO
return new MyException();
}
}
a bad call on the client shows that MyExceptionMapper handle the response but the exception raises and does not became a failure on my Uni Client response object
Uni<MyBean> bean = myClient.get("") // i do not have a failure in case of 4XX http
.onFailure().invoke(fail -> System.out.println("how can i get here?"));
Am i using mutiny on a rest client in the wrong way?
Thanks
UPDATE
ok i forgot to add the dependency quarkus-rest-client-mutiny, adding this i notice 2 things,
i still pass through Myexceptionmapper
i also produce a Uni.failure, but the exception into the failure is not the custom exception i created into MyExceptionmapper but a RestEasyWebApplicationException
Failure : org.jboss.resteasy.client.exception.ResteasyWebApplicationException: Unknown error, status code 400
at org.jboss.resteasy.client.exception.WebApplicationExceptionWrapper.wrap(WebApplicationExceptionWrapper.java:107)
at org.jboss.resteasy.microprofile.client.DefaultResponseExceptionMapper.toThrowable(DefaultResponseExceptionMapper.java:21)
Does the ExceptionMapper becomes useless in this context?
I think this is a bug in quarkus-rest-client-mutiny. I created an Github issue based on your findings.
It will work as you expect if you switch to quarkus-rest-client-reactive

How to create an Open API 3.0.1 Specification

I am new to swagger documentation etc
Please, could you share any good resource or steps for creating an open api spec for the following endpoint, which is an endpoint of a spring boot microservice:
#PostMapping(path = "/pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<ByteArrayResource> createReport(#RequestParam MultipartFile template, #RequestParam MultipartFile templateDataAsJson) throws IOException {
log.info("Triggering PDF Generation and Download");
log.info("Step 1 Starts : Sending Json data to the template data binder microservice: Request:{}", templateDataAsJson);
String completedHtmlJson = restClient.populateTemplate(template, templateDataAsJson);
log.info("Steps 2 Starts: Sending populated html template to html-to-pdf microservice for rendering:{}", completedHtmlJson);
ResponseEntity<ByteArrayResource> response = restClient.html2PdfGeneration(completedHtmlJson);
return ResponseEntity.ok().contentType(APPLICATION_PDF).body(response.getBody());
}
Any help or references will be appreciated.
Thanks all.
You can look at SpringDoc
https://github.com/springdoc/springdoc-openapi
It will generate the documentation on the fly for for you.

Spring http status code - java.lang.IllegalArgumentException: No matching constant

I'm using The spring rest-template for calling the rest URL , I get a response from the server but the http-status code is invalid and the Spring throws , java.lang.IllegalArgumentException: No matching constant . Due to this exception the application is failing , this looks like a bug in the Spring code . Since the http status code received is not in the list spring framework is looking forit failed . Is there a Spring way to handle it ?
Spring seems to use the standard status code in their enum. You can find the status codes here: org.springframework.http.HttpStatus.
Probably the API you're querying is not returning a standard HTTP Status code. Your best bet is to create a custom error handler, like this:
var r = new RestTemplate();
r.setErrorHandler(new ResponseErrorHandler() {
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getRawStatusCode() != 550;
}
#Override
public void handleError(ClientHttpResponse response) {
// Do nothing?
}
});
var response = r.exchange("https://httpbin.org/status/550", HttpMethod.GET, null, String.class);
System.out.println(response.getStatusCodeValue());
What we're saying is basically if the status code returned is 550 (not a standard code), we don't want to do anything about it.
Another option you have is, of course, to catch the exception and do something about it.
try {
// Call the API here
} catch (IllegalArgumentException e) {
// Do something about it here...
}

406 error while mocking File Download REST API using MockMVC

I am implementing a REST API using Spring framework, which returns
return new ResponseEntity<>(new InputStreamResource(myInputStream),
responseHeaders, HttpStatus.OK);
REST API is declared as:
#RequestMapping(value = "/download", method = RequestMethod.GET,
produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
While writing unit test for this API, I am using MockMVC like below:
final MappingJackson2HttpMessageConverter messageConverter =
new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(new ObjectMapper());
messageConverter.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
this.mockMvc =
MockMvcBuilders.standaloneSetup(myController)
.setMessageConverters(messageConverter)
.apply(new RestDocumentationConfigurer()
.withScheme("https").withHost("localhost")
.withPort(443)).build();
And my Test case looks like this:
mockMvc.perform(
org.springframework.test.web.servlet.request.MockMvcRequestBuilders
.get(restUri))
.andExpect(
org.springframework.test.web.servlet.result.MockMvcResultMatchers
.status().isOk())
.andDo(document("myApi")).andReturn();
But I am getting status as error 406.
java.lang.AssertionError: Status expected:<200> but was:<406>
at org.springframework.test.util.AssertionErrors.fail
What I am missing here?
Any help would be much appreciated.
You inject instance of MappingJackson2HttpMessageConverter to MockMvcBuilders which can't deal with converting classes inheriting from Resource. All you need to do is add ResourceHttpMessageConverter to your test specification:
MockMvcBuilders.standaloneSetup(myController)
.setMessageConverters(messageConverter, new ResourceHttpMessageConverter())
Status code 406 means "Not Acceptable", which indicates that the server is missing a header specifying an accepted content type. You'll need to include that in your mockMvc call.

How to handle exceptions with Swagger?

I am building some test APIs using swagger (1.5) and JAX-rs with Jersey (1.13) and I m trying to implement exception handling. For example I have the following code when receiving the results from my DB (Elasticsearch)
#POST
#Path("/category")
#ApiOperation(value="returns products")
#Produces({ "application/json" })
public Response getPostCategories(
#ApiParam(value="keyphrase, required=true) #QueryParam("keyphrase") String keyphrase,
#ApiParam(value="category) #QueryParam("category") String category,
#Context SecurityContext securityContext)
throws WebApplicationException {
SearchRequest searchRequest = new SearchRequest();
searchRequest.setKeyphrase(keyphrase);
searchRequest.setCategory(category);
SearchCategoryQuery categoryQuery = new SearchCategoryQuery();
String searchResponse = null;
try
{
searchResponse = categoryQuery.searchCategory(searchRequest);
}
catch (WebApplicationException ex)
{
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("results no found").type(javax.ws.rs.core.MediaType.APPLICATION_JSON).build());
}
return Response.ok(searchResponse).build();
}
However, in the output swagger always prints the same response
What I need instead is to receive the error messages I specify in each exception. Any ideas?
Swagger by itself does not handle application exceptions as yet.
You will either need to create custom Exception classes (that extend java.lang.exception) or use the existing ones (like WebApplicationException that you are already using) and make the API definition throw these errors. So basically you need to use Java/J2EE/Jersey to throw proper exceptions. Swagger UI will display them for you.
Check this link for details on REST exception handling with Spring.

Resources