swagger-core icon indicating copy to clipboard operation
swagger-core copied to clipboard

Cannot generate global `parameters` node using Java annotations

Open brpeterman opened this issue 6 years ago • 7 comments

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.

brpeterman avatar Nov 19 '18 19:11 brpeterman

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]

catbref avatar Dec 07 '18 10:12 catbref

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.

catbref avatar Dec 07 '18 12:12 catbref

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.

brpeterman avatar Dec 07 '18 15:12 brpeterman

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.

catbref avatar Dec 07 '18 16:12 catbref

We still need this. The workarounds are a pain. Please add an @Components annotation or some equivalent.

ccleve avatar Dec 10 '20 16:12 ccleve

+1 on the addition of @Components

andreaangiolillo avatar Apr 23 '21 14:04 andreaangiolillo

+1 on the addition of @Components

tomekrojek avatar Jul 18 '23 14:07 tomekrojek