OpenAPI Generation with Spring
Tags: openapi, spring, generator, java
Published: 2022-10-17 11:11:45

## 1 Overview
In this article we consider example of using code generation  by [OpenAPI](https://swagger.io/specification/) specification. This is the [API-First](https://swagger.io/resources/articles/adopting-an-api-first-approach/) approach to building service. [Code generator](https://github.com/OpenAPITools/openapi-generator) will be used for generating code in java-spring application. Full source code of example project on [GitHub](https://github.com/AnatoliyKozlov/openapi-spring-generator-example)

## 2 Specification
Let's start with writing simple OpenAPI specifications. Here we use an example with 'Get' and 'Create' operations for some Clients.

```yaml
openapi: 3.0.3
info:
  title: client-api
  description: 'Client API'
  version: 1.0.0
paths:
  /client:
    get:
      parameters:
        - name: id
          in: query
          required: true
          schema:
            type: string
            format: uuid
            description: Client id
      responses:
        200:
          description: Success response with client
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClientResponse"
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Client'
        required: true
      responses:
        200:
          description: Success response with client
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClientResponse"
components:
  schemas:
    ClientResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Operation success flag
        message:
          type: string
          description: Error description
        client:
          $ref: "#/components/schemas/Client"
      required:
        - success
        - message
        - object
    Client:
      type: object
      description: Client data
      properties:
        id:
          type: string
          format: uuid
          description: Client unique id
        name:
          type: string
          description: Client name
          maximum: 32
          minimum: 2
        dateOfBirth:
          type: string
          format: date
        createdAt:
          type: string
          description: Date of client registration
          format: date-time
        banned:
          type: boolean
          description: Ban flag
        countAccounts:
          type: integer
          description: Count of client accounts
          minimum: 0
        serviceRate:
          type: string
          description: Service rate
          enum:
            - "FREE"
            - "STANDARD"
            - "VIP"
```

## 3 Setup dependencies
Let's setup [OpenAPI generator maven plugin](https://search.maven.org/search?q=g:org.openapitools%20AND%20a:openapi-generator-maven-plugin)
```xml
<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>6.2.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/specs/client-api.yaml</inputSpec>
                <generatorName>spring</generatorName>
                <apiPackage>dev.toliyansky.openapi.api</apiPackage>
                <modelPackage>dev.toliyansky.openapi.model</modelPackage>
            </configuration>
        </execution>
    </executions>
</plugin>
```

## 4 Code examples

After run `mvn clean install` generated classes will be placed into target directory.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8g0bc0gnz3l72q5euuzr.png)

To implement the HTTP route we should create a class that extends generated controller.

```java
@RestController
@RequestMapping("/api")
public class ClientController extends ClientApiController {

    private final RandomExceptionService randomExceptionService;

    public ClientController(NativeWebRequest request, RandomExceptionService randomExceptionService) {
        super(request);
        this.randomExceptionService = randomExceptionService;
    }

    @Override
    public ResponseEntity<ClientResponse> clientGet(UUID id) {
        var clientResponse = new ClientResponse();
        try {
            var client = new Client(); // Stub. But in real project get client from service level.
            clientResponse.setSuccess(true);
            clientResponse.setClient(client);
            randomExceptionService.generateException50percentChance();
            return ResponseEntity.ok(clientResponse);
        } catch (Exception e) {
            e.printStackTrace();
            clientResponse.setSuccess(false);
            clientResponse.setMessage(e.getMessage());
            clientResponse.setClient(null);
            return ResponseEntity.internalServerError().body(clientResponse);
        }
    }

    @Override
    public ResponseEntity<ClientResponse> clientPost(Client client) {
        var clientResponse = new ClientResponse();
        try {
            // Do some actions with client in service level.
            client.id(UUID.randomUUID());
            clientResponse.setSuccess(true);
            clientResponse.setClient(client);
            randomExceptionService.generateException50percentChance();
            return ResponseEntity.ok(clientResponse);
        } catch (Exception e) {
            e.printStackTrace();
            clientResponse.setSuccess(false);
            clientResponse.setMessage(e.getMessage());
            clientResponse.setClient(null);
            return ResponseEntity.internalServerError().body(clientResponse);
        }
    }
}

```

Now we can test it with HTTP request

```
### Create client
POST http://localhost:8080/api/client
Content-Type: application/json
------
HTTP/1.1 200 
Content-Type: application/json
{
  "success": true,
  "message": null,
  "client": {
    "id": "6796a90a-314a-4667-a7cc-dfbe592b27e5",
    "name": "Anatoliy",
    "dateOfBirth": "2020-01-01",
    "createdAt": "2020-01-01T00:00:00Z",
    "banned": false,
    "countAccounts": 3,
    "serviceRate": "VIP"
  }
}

### Get client by id
GET http://localhost:8080/api/client?id=6796a90a-314a-4667-a7cc-dfbe592b27e5
Accept: application/json
------
HTTP/1.1 200 
Content-Type: application/json
{
  "success": true,
  "message": null,
  "client": {
    "id": "6796a90a-314a-4667-a7cc-dfbe592b27e5",
    "name": "Anatoliy",
    "dateOfBirth": "2020-01-01",
    "createdAt": "2020-01-01T00:00:00Z",
    "banned": false,
    "countAccounts": 3,
    "serviceRate": "VIP"
  }
}
```

## 5 Conclusion 

In this article, we saw how to generate a java-spring service  with an API-First approach with OpenAPI YAML specification and OpenAPI generator maven plugin.

Full source code of example project on [GitHub](https://github.com/AnatoliyKozlov/openapi-spring-generator-example)