May 31, 2021

Auto Generate OpenAPI/Swagger Specification from Annotated Java Code, with maven, Java 11, Eclipse Microprofile, Java EE 8

OpenAPI Specification (formerly Swagger Specification)

Auto generate documentation for your REST API, is a great way to document and it's auto generated and finally you follows a specification, that people have thought throw.

OpenAPI (part of Eclise Microprofile) Annotation

Maven dependency.

        <dependency>
            <groupId>org.eclipse.microprofile</groupId>
            <artifactId>microprofile</artifactId>
            <version>3.0</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>

And annotated Java code.

package se.magnuskkarlsson.example_openapi_swagger.boundary;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;

import se.magnuskkarlsson.example_openapi_swagger.entity.Person;

@Path("/persons")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

    @GET
    @Operation(summary = "Get all persons.", description = "Get all persons in DB.")
    @APIResponses(value = { //
            @APIResponse( //
                    responseCode = "500", //
                    description = "Internal Error", //
                    content = @Content(mediaType = MediaType.APPLICATION_JSON)),
            @APIResponse( //
                    responseCode = "200", //
                    description = "All persons in DB.", //
                    content = @Content( //
                            mediaType = MediaType.APPLICATION_JSON, //
                            schema = @Schema(implementation = Person.class))) })
    public List<Person> search( //
            @Parameter( //
                    description = "The name to search for.", //
                    required = false, //
                    example = "*he*", //
                    schema = @Schema(type = SchemaType.STRING)) //
            @QueryParam("name") String name) {
        var persons = new ArrayList<Person>();

        var person1 = new Person().setName("FOO").setAge(24);
        persons.add(person1);

        var person2 = new Person().setName("BAR").setAge(51);
        persons.add(person2);

        return persons;
    }

}

And maven plugin, which will auto generate OpenAPI specification and output in YAML file in your webapp root folder.

            <!-- https://github.com/kongchen/swagger-maven-plugin -->
            <plugin>
                <groupId>com.github.kongchen</groupId>
                <artifactId>swagger-maven-plugin</artifactId>
                <version>3.1.8</version>
                <configuration>
                    <apiSources>
                        <apiSource>
                            <springmvc>false</springmvc>
                            <locations>se.magnuskkarlsson.example_openapi_swagger.boundary</locations>
                            <!-- <schemes>http</schemes> <host>localhost:8081</host> -->
                            <basePath>/${project.build.finalName}</basePath>
                            <info>
                                <title>Users API</title>
                                <version>v1</version>
                                <description>Users rest endpoints</description>
                            </info>
                            <outputFormats>yaml</outputFormats>
                            <swaggerDirectory>${basedir}/src/main/webapp</swaggerDirectory>
                        </apiSource>
                    </apiSources>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>javax.xml.bind</groupId>
                        <artifactId>jaxb-api</artifactId>
                        <version>2.3.1</version>
                    </dependency>
                </dependencies>
            </plugin>

Reference:

Generated OpenAPI YAML Specification

---
swagger: "2.0"
info:
  description: "Users rest endpoints"
  version: "v1"
  title: "Users API"
basePath: "/example-openapi-swagger-1.0.0-SNAPSHOT"
paths:
  /persons:
    get:
      operationId: "search"
      consumes:
      - "application/json"
      produces:
      - "application/json"
      parameters:
      - name: "name"
        in: "query"
        required: false
        type: "string"
      responses:
        200:
          description: "successful operation"
          schema:
            type: "array"
            items:
              $ref: "#/definitions/Person"
definitions:
  Person:
    type: "object"
    properties:
      name:
        type: "string"
      age:
        type: "integer"
        format: "int32"

Complete pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>se.magnuskkarlsson</groupId>
    <artifactId>example-openapi-swagger</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <bouncycastle.version>1.65</bouncycastle.version>
        <hibernate.version>5.3.14.Final</hibernate.version>
        <hibernate-validator.version>6.0.18.Final</hibernate-validator.version>
        <primefaces.version>10.0.0</primefaces.version>
    </properties>

    <dependencies>
        <!-- Java EE 8 -->
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>8.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- JBoss EAP 7.3 -->
        <dependency>
            <groupId>org.eclipse.microprofile</groupId>
            <artifactId>microprofile</artifactId>
            <version>3.0</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>

        <!-- Test Support -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>2.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.10.19</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.javafaker</groupId>
            <artifactId>javafaker</artifactId>
            <version>0.17.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-envers</artifactId>
            <version>${hibernate.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate-validator.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>jakarta.el</artifactId>
            <version>3.0.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <release>11</release>
                        <showDeprecation>true</showDeprecation>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <!-- https://github.com/kongchen/swagger-maven-plugin -->
            <plugin>
                <groupId>com.github.kongchen</groupId>
                <artifactId>swagger-maven-plugin</artifactId>
                <version>3.1.8</version>
                <configuration>
                    <apiSources>
                        <apiSource>
                            <springmvc>false</springmvc>
                            <locations>se.magnuskkarlsson.example_openapi_swagger.boundary</locations>
                            <!-- <schemes>http</schemes> <host>localhost:8081</host> -->
                            <basePath>/${project.build.finalName}</basePath>
                            <info>
                                <title>Users API</title>
                                <version>v1</version>
                                <description>Users rest endpoints</description>
                            </info>
                            <outputFormats>yaml</outputFormats>
                            <swaggerDirectory>${basedir}/src/main/webapp</swaggerDirectory>
                        </apiSource>
                    </apiSources>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>javax.xml.bind</groupId>
                        <artifactId>jaxb-api</artifactId>
                        <version>2.3.1</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

No comments: