Skip to content

qaware/openapi-generator-for-spring

Repository files navigation

OpenAPI v3 generator for Spring Boot

Build Status Quality Gate Status Code Coverage Maven Central

This library automagically generates a OpenApi v3 specification at runtime for Spring Boot applications.

It aims at fully analyzing Spring request mappings augmented by Swagger annotations to provide a self-descriptive API specification of your application.

Features

Note that some features are not fully implemented yet, see issues.

Getting started

Inside your Spring Boot application, add the following (maven) dependency:

<dependency>
    <groupId>de.qaware.tools.openapi-generator-for-spring</groupId>
    <artifactId>openapi-generator-for-spring-starter</artifactId>
    <version>6.0.0</version>
</dependency>

After starting your application, the OpenApi v3 specification of your application is provided at /v3/api-docs as JSON. This specification can be viewed by visiting /swagger-ui inside your browser (relative to context path).

Have a look at the Demo for WebMVC and Demo for WebFlux for a first impression.

Configuration Properties

The following configuration properties are available with the prefix openapi-generator-for-spring.:

The following extension properties are currently part of this library:

How To

How to filter paths, operations and parameters within the specification?

The library supports filtering at the following stages during OpenApi specification building, in this order:

  1. HandlerMethodFilter filters before passing on the found handler methods to the path building.
  2. OperationPreFilter filters before the Operation model object is built.
  3. OperationParameterPreFilter filters before a Parameter model object of an operation is built.
  4. OperationParameterPostFilter filters after a Parameter has been built.
  5. OperationPostFilter filters after a Operation has been built. All information has been set except referenced components.
  6. PathItemFilter filters after a PathItem is fully constructed. All information has been set except referenced components.

Insert a bean extending one or more of the above interfaces, which will be picked up by the library.

The later the filter is called the more work has been done, but also more information is supplied to make the filtering decision. Possibly referenced components must be manually cleared later on in an extra customization step if filtering happened too late. It is thus recommended applying filtering as early as possible.

How to obtain a grouped OpenAPI specification?

Grouping is realized by applying filters, preferably a OperationPreFilter, while building the OpenAPI specification. Query and header parameters of the HTTP request to /v3/api-docs can be obtained within the filter by auto-wiring the bean of type OpenApiRequestParameterProvider.

This way, you can control which operations are considered for the specification when /v3/api-docs?group=MyGroup. The Swagger UI can also be customized to display more than one specification by providing a bean of type OpenApiSwaggerUiApiDocsUrisSupplier.

See the *Configuration class of this integration test or this integration test for a fully working WebMVC or WebFlux example, respectively. Note that the test cases invoke the endpoint with different header or query parameters.

How to customize the specification?

The library offers various customizers, which allow the library user to (hopefully) adapt to any use case which comes to mind.

The following shows some examples for customizers:

Feel free to investigate the api module for more details. The relevant interfaces all have the suffix Customizer and extend the Ordered interface.

Examples

OperationCustomizer bean that uses the class name of the RestController to set it as OpenAPI tag

/**
 * Provide an OperationCustomizer to use the class name of the REST controller as Tag. This way the API endpoints are grouped per REST controller.
 *
 * @return OperationCustomizer
 */
@Bean
public OperationCustomizer operationTagCustomizer() {
    return (operation, operationBuilderContext) -> {
        if (CollectionUtils.isEmpty(operation.getTags())) {
            operationBuilderContext.getHandlerMethod(SpringWebHandlerMethod.class).ifPresent(handlerMethod -> {
                String declaringClassName = handlerMethod.getMethod().getMethod().getDeclaringClass().getSimpleName();
                operation.setTags(singletonList(declaringClassName));
                operationBuilderContext.getReferencedItemConsumer(ReferencedTagsConsumer.class)
                        .accept(singletonList(Tag.builder().name(declaringClassName).build()));
            });
        }
    };
}

OperationIdProvider to generate deep-links to specific endpoints that are compatible to the SpringFox style

/**
 * Provide an OperationIdProvider to generate deep-links that are compatible to the SpringFox style.
 *
 * @return OperationIdProvider
 */
@Bean
public OperationIdProvider operationIdProvider() {
    return operationInfo -> operationInfo.getHandlerMethod().getIdentifier() + "Using" + operationInfo.getRequestMethod().name();
}

How to customize the included Swagger UI?

The Swagger UI index.html is generated from a Mustache template and uses the Swagger UI Webjar distribution.

The default implementation of OpenApiSwaggerUiApiDocsUrisSupplier uses the given URI to the API Docs endpoint and names the entry Default. This name is ignored as there is only one entry in the Swagger UI.

See this integration test for an example how to customize the offered API Docs within the Swagger UI.

How to substitute a type for Schema resolution?

Define the following bean of type InitialTypeBuilder if you want to resolve the type YourType always as if it was of type String:

@Bean
public InitialTypeBuilder openApiSchemaTypeSubstitutionForYourType(){
        return(caller,javaType,annotationsSupplier,recursiveBuilder)->{
        if(javaType.getRawClass().equals(YourType.class)){
            return recursiveBuilder.build(String.class, annotationsSupplier);
        }
        return null;
    };
}

How to handle error responses elegantly?

Spring (Boot) offers to handle exceptions from handler methods via @ExceptionHandler annotated methods. This mechanism can be plugged into the specification by using an OperationCustomizer, which scans a SpringWebHandlerMethod for its exception signature and adds additional ApiResponses to the Operation for each exception.

One can even figure out the @ExceptionHandler method, as Spring would do, to automatically determine the Schema of the error response and also scan for @ReponseStatus to determine the error code.

It is also possible to throw an error when there is an exception declared but no appropriate @ExceptionHandler method is found.

See this configuration of the integration test for a fully worked out example.

Why not another library?

This library is based on experience while using Spring Fox and SpringDoc OpenApi. As those libraries have turned out to be not flexible enough for our internal projects, this library aims at being fully customizable.

Composing Spring beans in combination with Spring Boot autoconfiguration enable this flexibility. The library offers opinionated (and hopefully sane) default implementations but marks all of them with @ConditionalOnMissingBean. It is encouraged to override those defaults by providing own bean implementations.

Default implementations in common module will use the api module interfaces as much as possible. This way it is ensured that the provided api module actually offers useful interfaces.

Module structure

All the following module names are prefixed with openapi-generator-for-spring-.

model contains Jackson-serializable POJOs to represent the OpenApi v3 model.

api contains the public API to extend and adapt the functionality of this library.

common contains the main algorithm parsing the swagger-annotated handler methods. It provides default implementations for most of the interfaces in openapi-generator-for-spring-api module.

autoconfigure contains the Spring Boot auto-configuration of common beans.

web shared support code for Spring WebMVC and WebFlux including shared auto-configuration.

webmvc supports Spring WebMVC via Spring Boot auto-configuration.

webflux supports Spring WebFlux via Spring Boot auto-configuration.

ui Provides Swagger UI below /swagger-ui. Offers UI Resource transformation for WebMVC and WebFlux and sets up correct redirect routes.

starter Opinionated choice of dependencies. Enables Swagger UI and support for WebMVC and WebFlux if present.

test contains all integration tests for WebMVC and WebFlux.

shaded contains shaded dependencies to avoid interference with Spring Boot autoconfiguration. This library does not want to trigger Mustache or WebJar exposure for users of this library. Shading is the only mechanism which still allows to use such code but hide it from Spring Boot.

Each module aims to have minimal dependencies. General library dependencies are:

  • Spring Core (Web/WebMVC/WebFlux are optional)
  • Jackson
  • Swagger Annotations
  • WebJar for Swagger UI (shaded)
  • Mustache (shaded)
  • Apache Commons

Development & Contributing

Please open an issue before posting a pull request unless you have a very obvious fix or improvement to contribute.

When developing with IntelliJ, run mvn clean package -DskipTests first in order to get the integration tests also running from within the IDE.