Open drapej opened 5 years ago
+1 :)
+2 :)
That sounds more like a backend issue. The Accept
header is only a hint to the producer as to what the client wants to receive. The producer, on the other hand, should try to match the media type if it can, but if it cannot, it's up it to decide whether to throw 500 or return a different media type it can.
In the case of the documentation, it just shows what can be returned, it does not represent what the client should ask for.
It's worth noting that we recently had a discussion of content negotiation with the Accept header over in Swagger Client: https://github.com/swagger-api/swagger-js/issues/1475
is there any solution to this problem?
I had the same problem in an API to download document and in case of error it returned a JSON with the error. From what I could find, SpringFramework doesn't ignore the Accept header by default.
I found this guide to configure Conntent Negotiation: https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
This code worked for me for a Spring Boot 2.2.4 project:
@Configuration
public class ContentNegociationConf implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.ignoreAcceptHeader(true)
.defaultContentType(MediaType.ALL);
}
}
On the other hand, about this:
That sounds more like a backend issue. The
Accept
header is only a hint to the producer as to what the client wants to receive. The producer, on the other hand, should try to match the media type if it can, but if it cannot, it's up it to decide whether to throw 500 or return a different media type it can.In the case of the documentation, it just shows what can be returned, it does not represent what the client should ask for.
This solution is still a workarround on the backend. If in the API definition it indicates that it can return different "content-types" swagger-ui as client should configure the request to include in the accept
all the different response types, not only the content-type from the 200 Response.
+1 It seems like Swagger UI try it out feature should let the user select which media types to send in the Accept header from any of the media types defined for any of the response status codes, not just the success status code.
Consider a DELETE request that typically returns a 204 no content, but may also return error status codes that do have response content (e.g. a 422) with multiple supported media types (e.g. "application/xml" and "application/json"). Or perhaps it is using media type API versioning (e.g. "application/vnd.my.company+json; version=1.0" and "application/vnd.my.company+json; version=2.0") where the error responses are different between the 2 versions. Currently if an endpoint defines a 204 response in the OpenAPI 3.0 spec (with no media type defined since there is no content), it looks like Swagger UI will send and Accept header of "*/*" even if there are media types defined on error response status codes. This limits what can be "tried out" from Swagger UI, as we can't try out the JSON error response vs the XML, or the version 1.0 error response vs the version 2.0.
+1 The Swagger UI should allow to define multiple Media Types in the Accept Header. Especially for the usage of Spring's ExceptionHandler / ControllerAdvice. For instance, if I have a REST definition that produces and returns a file based on posted data, it may fail and the exception is caught by Spring's ExceptionHandler, which will return a JSON containing information about the failure, e.g.:
{
"apierror": {
"status": "BAD_REQUEST",
"timestamp": "2021-07-02T14:28:38.625+02:00",
"message": "Could not generate report",
"debugMessage": ".....",
"subErrors": null
}
}
Therefore, we must define produces = {"application/zip", MediaType.APPLICATION_JSON_VALUE}
.
@PostMapping(path = "/billing/{month}/{year}", produces = {"application/zip", MediaType.APPLICATION_JSON_VALUE}, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<byte[]> generateBilling(@PathVariable("month") Integer month,
@PathVariable("year") Integer year,
@RequestBody Configuration config) {
...
}
In Swagger UI I can either select "application/zip" OR "application/json" but not "application/zip, application/json" together. If the request fails, and ExceptionHandler returns the JSON, it will show the stacktrace on the UI for "application/zip" and the JSON response from ExceptionHandler if I choose "application/json". However, I cannot know if the request will succeed beforehand, and I want to receive the file if it runs without errors and the ExceptionHandler's JSON if it does not.
The only workaround is to accept all media type */*
Further, even if I annotate with the following, there is always "accept: application/zip" in the header
@ApiResponses(value = {
@ApiResponse(responseCode = "400", description = "Error Response",
content = { @Content(mediaType = "application/json",
schema = @Schema(implementation = ApiError.class)) }),
@ApiResponse(responseCode = "200", description = "The billing report",
content = @Content(mediaType = "application/zip", schema = @Schema(type = "string", format = "byte")))})
I second this, my setup is essentially the same as described by @adrian-haenni: download a file if all preconditions are met (accept
header being application/octet-stream
in this case) or throw a JSON error (the case of application/json
). Obviously there's no way to know the result of the call beforehand but sending two headers at the same time instead of just one "standard" would solve it.
This would be great please +1!
+1 have the same concept described by @adrian-haenni
Q&A (please complete the following information)
Content & configuration
Swagger/OpenAPI definition:
Swagger-UI configuration options: i use default index.html file
Describe the bug you're encountering
With Swagger UI, when i made a request (with Try it out), only the content-type from the 200 Response (xml) is used to Accept Header, so when my request produce a 406 Response (json), I have a 500 Response because my backend can't match the content type json with the Accept headers (which has only content type "xml")
I think that the request has to have in the Accept Header all the content type from all the responses (or give a possibility to choose the Accept header)
Thank you ;)