javaswaggerquarkusopenapimicroprofile

How to put Microprofile / OpenAPI annotations into interface for generating Swagger-file while keeping source-code clean


In Quarkus, I need to define an API that will result in a Swagger-UI JSON/YAML-File to give out to consumers.

This works as expected/documented by defining many annotations in the REST-endpoint. For example:

@POST
@Operation(summary = "creates a new product")
@APIResponse(responseCode = "201", description = "product creation successful")
@APIResponse(responseCode = "500", description = "Server unavailable")
@Path("/")
@RequestBody(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductRequest.EXAMPLE1_NAME,
        description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
        value = CreateProductRequest.EXAMPLE1_VALUE
    )
}))
@APIResponse(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductResponse.EXAMPLE1_NAME,
        description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
        value = CreateProductResponse.EXAMPLE1_VALUE
    )
}))
@ResponseStatus(201)
public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
    return productManager.create(new RequestContext(1, 1), createProductRequest);
}

The REST-endpoint almost gets unreadable this way (this is one of the smaller examples).

My preferred way to solve this, would be to define an interface, that the REST-endpoint would implement.

Can somehow help me to...

What I would have expected to work (but does not, the annotations in the interface are completely ignored by the framework and will not find their way into the generated swagger-json/yaml file):

@Path("/api/v1/products")
public class ProductControllerV1 implements ProductApiV1 {

    @POST
    @Path("/")
    @Override
    public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
        return productManager.create(new RequestContext(1, 1), createProductRequest);
    }
}
@Tag(
    name = "Product Controller V1",
    description = "Product Operations, for testing many different use-cases"
)
@Path("/api/v1/products")
public interface ProductApiV1 {

    @POST
    @Operation(summary = "creates a new product")
    @APIResponse(responseCode = "201", description = "product creation successful")
    @APIResponse(responseCode = "500", description = "Server unavailable")
    @Path("/")
    @RequestBody(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductRequest.EXAMPLE1_NAME,
            description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
            value = CreateProductRequest.EXAMPLE1_VALUE
        )
    }))
    @APIResponse(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductResponse.EXAMPLE1_NAME,
            description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
            value = CreateProductResponse.EXAMPLE1_VALUE
        )
    }))
    @ResponseStatus(201)
    CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException;

Solution

  • Can you try this in your REST Controller:

    @ApplicationScoped
    public class ProductControllerV1 implements ProductApiV1 {
    
        @Override
        public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
            return productManager.create(new RequestContext(1, 1), createProductRequest);
        }
    }
    

    Another way of maintaining the OpenApi documenation is by making use of the hybrid approach.

    That means: you store openapi.yml in src/main/resources/META-INF and edit this file with the stuff that is hard to do in code with annotations, and you can add some simple annotations on your code and Quarkus will combine both results (giving code higher priority).