swagger-core
swagger-core copied to clipboard
Cannot generate global `parameters` node using Java annotations
I have a bunch of JAX-RS 2.0 interfaces that define my API. I'm using Swagger 2.0 annotations to produce an OpenAPI 3.0 spec.
Many of the operations in the API share certain query and header parameters (things like language, client version, etc). It would be incredibly excessive and a nightmare to maintain if we just copied and pasted these shared parameters onto each operation.
Ideally, we'd like to blanket apply all of these parameters to our operations, but there doesn't seem to be support for that in OpenAPI 3.0. The orthodox way to do this seems to be to use $ref
to refer to parameters defined at the global API level.
There doesn't seem to be any way to produce that global parameters
node using just Swagger annotations, though. Is this a gap in functionality, or am I missing how to do this?
As an implementation, I'd expect to see a parameters
field in the @OpenAPIDefinition
annotation.
Looking at the OpenAPI v3.0 spec it might be better, or even easier, to add a @Components
annotation for use inside @OpenAPIDefinition
. Then inside @Components
any number of @Parameter
or @Schema
or anything else as mentioned here: https://swagger.io/specification/#componentsObject
[Edit: quoting annotations]
If you need a work-around "yesterday" then you can declare your 'global' parameters on some unused endpoint like this:
@GET
@Path("/dud")
@Parameter(in = ParameterIn.QUERY, name = "limit", description = "Maximum number of entries to return", schema = @Schema(type = "integer", defaultValue = "10"))
@Parameter(in = ParameterIn.QUERY, name = "offset", description = "Starting entry in results", schema = @Schema(type = "integer"))
public String globalParameters() {
return "";
}
Then use a custom annotation processor to find the parameters and add them to the components
section:
public class AnnotationPostProcessor implements ReaderListener {
@Override
public void afterScan(Reader reader, OpenAPI openAPI) {
// Populate Components section with reusable parameters, like "limit" and "offset"
// We take the reusable parameters from path "/dud"
Components components = openAPI.getComponents();
PathItem globalParametersPathItem = openAPI.getPaths().get("/dud");
if (globalParametersPathItem != null)
for (Parameter parameter : globalParametersPathItem.getGet().getParameters())
components.addParameters(parameter.getName(), parameter);
}
}
Once this is done, you can refer to your 'global' parameters simply:
@GET
@Path("/pets/all")
public List<Pet> getPets(@Parameter(ref = "limit") int limit, @Parameter(ref = "offset") int offset) {
...
}
It's not pretty but in the future you would only need to replace the annotation processor and move the global @Parameter
entries to some other location, like @Components
.
That's a useful suggestion. For now, we've taken the route of defining global components in a YAML spec file and merging it with the annotation-driven specs at runtime.
Your route sounds like a pretty clean way to handle this for now.
I struggled to find a simple way of converting @Parameter
annotations into Parameter
models and couldn't find a way to hide the "/dud" endpoint but merging YAML spec would solve both this issues.
Later on I found out that @Parameter(in = ParameterIn.QUERY, name="limit")
doesn't 'imply' @QueryParam("limit")
and so still had to include those in the method signature:
public List<Pet> getPets(@Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) {
So not quite perfectly minimal but certainly better than lots of copy&paste.
We still need this. The workarounds are a pain. Please add an @Components
annotation or some equivalent.
+1 on the addition of @Components
+1 on the addition of @Components