Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@ApiResponse response parameter not used in 3.0.0 #3503

Open
varjasz opened this issue Aug 17, 2020 · 14 comments
Open

@ApiResponse response parameter not used in 3.0.0 #3503

varjasz opened this issue Aug 17, 2020 · 14 comments
Labels
Milestone

Comments

@varjasz
Copy link

varjasz commented Aug 17, 2020

Starting with 3.0.0 (in 2.9.2 it worked properly)

@ApiResponse(code = 404, message = "Not Found", response = CustomError::class)

The 404 - Not Found is in the documentation, but the defined response (CustomError in example) not shown in the generated documentation (response sample and model)

@danielfelgar
Copy link

@varjasz do you find any solution?

@varjasz
Copy link
Author

varjasz commented Aug 23, 2020

@varjasz do you find any solution?

No, but I wasn't looking for it.

@dilipkrish dilipkrish added the bug label Aug 24, 2020
@dilipkrish dilipkrish added this to the 3.0.1 milestone Aug 24, 2020
@dilipkrish
Copy link
Member

Thanks for reporting @varjasz

@gonwan
Copy link

gonwan commented Sep 1, 2020

Same issue here.
After some debugging, root cause should be:

Springfox 3.0 uses v3 models by default, but source.getResponses() gives wrong type. To workaround it for now, add:
springfox.documentation.swagger.use-model-v3=false in your application.properties.

@drognisep
Copy link

To workaround it for now, add: springfox.documentation.swagger.use-model-v3=false

The prescribed workaround doesn't seem to work for ResponseEntity<?> return types. I'm not sure if that's a separate issue or if it's part and parcel to this bug.

@DominicIovino
Copy link

I can confirm the fix with springfox.documentation.swagger.use-model-v3=false for doc type DocumentationType.SWAGGER_2.

On the other hand, shouldn't it work out of the box with doc type DocumentationType.OAS_30? I tried it both with and without the app.prop setting but it behaves the same as the initial issue by not showing up at all.

@arlyon
Copy link

arlyon commented Jul 21, 2021

Also getting this on springfox 3.0.0 using OAS_30. Specifically, the problem is that my POST requests to a JPA respository return a body with 201 responses, which are incorrectly labelled to have no body. Overriding this using ApiResponse has no effect.

edit: I believe the issue for me comes from here:

context.produces()
.forEach(mediaType ->
finalType.map(t -> modelSpecifications.create(modelContext, t))
.ifPresent(model -> responseContext.responseBuilder()
.representation(mediaType)
.apply(r -> r.model(m -> m.copyOf(model)))));
responseContext.responseBuilder()
.examples(examples)
.description(apiResponse.message())
.headers(headers.values())
.code(String.valueOf(apiResponse.code()));
responses.add(documentationPlugins.response(responseContext));

OperationContext::produces is empty, and so the representations and return types are not added to the responses. This is in opposition to responseMessages, which are created correctly. The reason is that the set of produces media types is empty, which can be traced back to SpringDataRestRequestHandler.actionSpecification, whose produces HashSet is empty.

edit 2: I've traced this back to EntitySaveExtractor which seems like the right place (at least for the specific variation of this issue I am experiencing).

entityAction(context, handler)
.path(String.format("%s%s/{id}",
context.basePath(),
context.resourcePath()))
.supportsMethod(PUT)
.supportsMethod(PATCH)
.parameterType(ParameterType.ID)
.parameterType(ParameterType.RESOURCE)
.build()
.map(put -> new SpringDataRestRequestHandler(context, put))
.ifPresent(handlers::add);
entityAction(context, handler)
.supportsMethod(POST)
.parameterType(ParameterType.RESOURCE)
.build()
.map(post -> new SpringDataRestRequestHandler(context, post))
.ifPresent(handlers::add);

It adds support for PUT, PATCH, POST, but doesn't set the media types it produces and consumes, causing SwaggerResponseMessageReader to ignore the return types. It should be noted that setting the produces field on the Docket is not respected here. Any ideas to fix this welcome so that I can write a PR.

edit 3: from the spring rest docs, the only valid media types are application/json and application/hal+json. I will just add those manually and test if that fixes my issue.

@ale-rd
Copy link

ale-rd commented Aug 12, 2021

I tried with springfox.documentation.swagger.use-model-v3=false, but then the globalRequestParameters I had configured in the Docket didn't work anymore (some custom global headers).

After a few hours I found a way to add my custom errors as a global response. It may not be a suitable solution if your endpoints have different custom errors, but in my case it was good enough and hopefully it will save someone's time, so I'll share it anyway.

Here's an example on how to add the class CustomError as a global response for POST operations that return a status code 400

@Bean
    public Docket api(TypeResolver typeResolver) {

        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                // omitted config...
                .additionalModels(
                        typeResolver.resolve(CustomError.class)
                )
                .globalResponses(
                        HttpMethod.POST,
                        List.of(
                                new ResponseBuilder()
                                        .code("400")
                                        .description("some description..")
                                        .representation(MediaType.APPLICATION_JSON)
                                        .apply(r ->
                                                r.model(m ->
                                                        m.referenceModel(rm ->
                                                                rm.key(k ->
                                                                        k.qualifiedModelName(q ->
                                                                                q.namespace(CustomError.class.getPackageName())
                                                                                        .name(CustomError.class.getSimpleName()))))))
                                        .build()
                        ))
    }

Note that you need to register the class with additionalModels, otherwise it won't work.
It doesn't look pretty but hey, it's only temporary

@fduser1
Copy link

fduser1 commented Aug 20, 2021

As already pointed out, the bug is tied to an empty set of produces media type(s) for the operation. A simple workaround it is to explicitly set your @XXXXXMapping produces value on your operation (i.e. @GetMapping(produces={"application/json"})).

I would recommend avoid setting springfox.documentation.swagger.use-model-v3=false since it may have unintended consequences as observed by this issue and other issues.

FYI... root cause of this particular issue is tied to SwaggerResponseMessageReader class. It's v2 counterpart ResponseMessagesReader does not suffer from this bug because it will default produces to */* if its empty.

@Vanderhoof
Copy link

@ale-rd 's solution worked, and it's still possible to add custom error responses by specifying @ApiResponse for specific endpoints, but you still have to register your custom error models in .additionalModels.

@sahinyanlik
Copy link

@fduser1 how we can overcome this by only defining @produces and @consumes in class level ?

@madhur
Copy link

madhur commented Jul 22, 2022

Is there any update on this issue?

@falcoco
Copy link

falcoco commented Jul 29, 2022

I got the same issue, but it's caused by spring.main.lazy-initialization = true, so don't override this configuration.

Spring Boot 2.7.2
io.springfox:springfox-boot-starter:3.0.0

@yasszoug
Copy link

yasszoug commented Apr 5, 2023

set your @XXXXXMapping produces value on your operation

i.e :

@GetMapping(value="/endpoint", produces={"application/json"}).
or
@GetMapping(value="/endpoint", produces=MediaType.APPLICATION_JSON_VALUE)

That would solve your problem ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests