Swagger-core: How to DRY ApiResponses Annotations

Created on 25 Sep 2014  路  12Comments  路  Source: swagger-api/swagger-core

I have integrated Swagger into our our new Java server app and am trying to come up with a way to eliminate redundant ApiResponse values contained within ApiResponses annotations. I have tried numerous techniques w/o luck and Java does not allow subclassing an annotation, but there must be some way. As an example, returning a 404 is quite common so I'd like a simple annotation such as @ApiResponseNotFound(optionalMessage="x not found").

For a bonus, I'd love @ApiResponseList("400, 404") or equivalent such as @ApiResponses({@ApiResponseNotFound, @ApiResponseArgument})

@ApiResponses(@ApiResponse(code = 404, message = "not found"))

or

@ApiResponses({ @ApiResponses(@ApiResponse(code = 400, message = "invalid argument"), @ApiResponse(code = 404, message = "not found") })

Documentation P3

Most helpful comment

I came across this thread as I too need a way to define our Response Codes once, and use them across the API. We have several response codes (500, 400, 200, etc.) that we don't want to copy/paste all throughout the API. Yes, I could statically define the strings for the responses, but the annotations would still need to be duplicated.

Has anyone figured this out? I don't think I followed what @fehguy was suggesting back in March.

Thank you very much in advance! Love using Swagger!

All 12 comments

Unfortunately, that's not really an option, at least not without going into extreme annotation processing (which even then may not offer what you want).

Annotation values are determined at compilation and not runtime, so at most you can have static strings and use those as values for the annotations.

In terms of annotation processing, accepting user-generated annotations won't work as well, as like you said, there's no annotation inheritance.

We could at some point change the @ApiResponse to a java class to allow static initialization, but even if we do end up doing that, it'll only be in a future major version since it'll break backwards compatibility.

Not sure if I misunderstood the question, but can this be achieved by allowing @ApiResponse be a meta-annotation?

//other metas
@Target(ElementType.METHOD, ElementType.ANNOTATION_TYPE)
@ApiResponse

Then we could have user defined annotations like:

@ApiResponse(code="404", message="Resource not found")
public @interface MyResourceNotFound

The annotation processor can then check if the @MyResourceNotFound has @ApiResponse in its meta-annotation "hierarchy".

@mwhig - thanks for the suggestion, looks interesting, especially as an idea to allow user-created response annotations.

That partially solve the second request from @todd-richmond, but not the first. If I understand correctly, he wants the "message" part to be dynamic - so not just "Resource not found" but rather "{X} not found" where X is replaced by the resource name.

The reason that it only partially solves the second request is that @ApiResponse is currently not used processed from being directly on the method but rather only as an input to @ApiRsponses. The @Target(ElementType.METHOD) is actually a bug and the proper declaration should have been @Target({}). The reason for that is simple - you can't have more than one instance of an annotation on a method, and if you want to include several responses you won't be able to do that (and we don't support it for a single response declaration). Your suggestion may help there, but it would also _force_ the user to create their own annotations which is not necessarily what we want.

Nope - i don't need var substitution in the default response string. It would definitely be useful to optionally override the entire string so if you want more descriptive "foo not found" instead of plain "not found" you would have to supply it yourself. Default strings can come straight from the RFC spec

With 1.5.x-M1, you can now plug your own annotation processors. While documentation needs to be written, you can follow the swagger-jersey2-jaxrs module as an example, allowing you to create a simple module which is loaded via SPI.

Unfortuenetly, I did not understand your described solution.
Has anyone a link where I can see how I may define my general Response Codes such as 500, 502 which apply for all operations and use them in each operation annotation to avoid the same block of documentation for every operation ?
Thanks a lot in advance.

an example would definitely help. Our REST API has a global exception handler that we use to catch most issues and translate to HTTP codes in a general manner. As a result, the documented responses would all share the same docs. Ideally I'd like to create a base set of responses for each HTTP command (PUT, PATCH, GET, DELETE...) and then be able to add a few per-route additions

I came across this thread as I too need a way to define our Response Codes once, and use them across the API. We have several response codes (500, 400, 200, etc.) that we don't want to copy/paste all throughout the API. Yes, I could statically define the strings for the responses, but the annotations would still need to be duplicated.

Has anyone figured this out? I don't think I followed what @fehguy was suggesting back in March.

Thank you very much in advance! Love using Swagger!

If I understand correctly, the swagger json format already supports references that would do the trick. All we need is annotation support for it. Or am I missing something?

+1

+1
Would be extremely helpful if you added the full spec of the Swagger object (or at least definitions, parameters and responses) to @SwaggerDefinition. Alternatively, as @jlous pointed out, it would be sufficient to give us an option to reference global definitions in @ApiOperation, @ApiParam etc. (e.g. with a field ref), as one can define the global definitions by subclassing ReaderListener as described here: http://swagger.io/customizing-your-auto-generated-swagger-definitions-in-1-5-x/

So it is possible to create an a Custom annotation (i.e. GroupedApiResponses) and annotate it with @ApiResponses and then use the custom annotations GroupedAPiResponses on endpoints and works just fine. I have posted an answer in SO about the same.

It saves a lots of repetitive code.

Was this page helpful?
0 / 5 - 0 ratings