Easily Integrate OpenAPI with a Spring Boot Project: A Simple Setup Guide

Pragya Sinha
Goalist Blog
Published in
5 min readMay 24, 2024

Spring Boot is a remarkable framework that simplifies the setup and development of standalone, production-grade Spring-based applications. In this article, we will walk through the steps to set up a simple Spring Boot project that uses OpenAPI specification files to generate API interfaces and request/response schemas.

Prerequisites

Before we start, ensure that you have the following installed on your machine:

  • Java v21
  • Spring boot v3.2.5
  • Gradle v8.7
  • IntelliJ IDEA or any other preferred IDE

Step 1: Create a New Spring Boot Project

You can get started with the Spring Initializr tool. For this project, you need to add the following dependencies: ‘Spring Web’, ‘Spring DevTools’ and ‘OpenAPI 3’.

This article follows this repository for demonstration purposes. You can refer to the dependencies defined in the build.gradle file of this repository for your project.

Step 2: Setting Up the OpenAPI Specification

Once you have your project set up, you can start to define your OpenAPI specification. This will define your API interfaces and request/response schemas. You can do this in a YAML or JSON file. For simplicity, we’ll do this in a YAML file. I have placed all specification files in specs directory. The routes.yaml file has configurations and path routes defined, the sub folders stores the properties of these paths. It is a good practice to use $ref and separate the concerns like route properties, request and response schemas into distinct files.

For this article, we are creating only a healthcheck endpoint to demonstrate setup:

openapi: "3.0.3"
info:
description: "example-project"
version: "1.1.0"
title: "example-project"
servers:
- url: "<http://localhost:8080>"
variables:
basePath:
default: /api/v1
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
paths:
/healthcheck:
$ref: "./paths/healthcheck/index.yaml"

from a glance we can see the benefit of using reference, this will make it easy to add more paths and organise them in one place for easy reference.

We will now write the HTTP methods for this endpoint, since we just want to fetch information of application health, using GET is appropriate.

get:
summary: "healthcheck"
operationId: healthcheck
responses:
"200":
description: "OK"
content:
application/json:
schema:
$ref: "../../schemas/responses/healthcheck_response.yaml"

One advantage of using reference in response schema is that, when API Model will be generated, the name of class will be yaml file name converted to camel case.

We now define response schema to be something simple:

type: object
required:
- status
properties:
status:
description: ok
type: string
msg:
description: test
type: string

Refer to OpenAPI 3.0 documentation to understand more about writing spec files (https://swagger.io/docs/specification/paths-and-operations).

Step 3: Generate API Interfaces & Request/Response Schemas

To generate the API interfaces and request/response schemas from the OpenAPI specification file, we will configure ‘openapi-generator-gradle-plugin’ for Gradle by adding this to build.gradle file:

import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
id 'org.openapi.generator' version '7.2.0'
}
...
sourceSets {
main {
java {
srcDirs 'src/main/java', 'build/generated/src/main/java'
}
}
}
repositories {
...
}
dependencies {
// other dependencies
...
implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'
implementation 'org.springdoc:springdoc-openapi-data-rest:1.7.0'
implementation 'org.openapitools:jackson-databind-nullable:0.2.1'
}
...tasks.named('compileJava') {
dependsOn 'openApiGenerate', 'mergeSpec'
}
openApiGenerate {
generatorName = 'spring'
inputSpec = "$rootDir/specs/routes.yaml"
outputDir = "$buildDir/generated"
apiPackage = "${group}.simpleauth.api"
modelPackage = "${group}.simpleauth.model"
configOptions.set([
useSpringBoot3: "true",
interfaceOnly : "true"
])
}
openApiValidate {
inputSpec = "$rootDir/specs/routes.yaml"
}
tasks.register('mergeSpec', GenerateTask) {
generatorName = "openapi-yaml"
inputSpec = "$rootDir/specs/routes.yaml"
outputDir = "$rootDir/specs/out"
configOptions.set([
outputFile: 'openapi-gen.yaml'
])
}

First, we have imported the GenerateTask, which is defined in OpenAPI’s plugin for Gradle, and added to the plugins.

Next, we’ve added an additional source directory, build/generated/src.., which will store the generated stubs.

We’ve then included a dependency on OpenAPI and other required tools.

The compileJava task, which compiles the main Java source files of the project, depends on two other tasks: openApiGenerate and mergeSpec. This means that Gradle will run openApiGenerate and mergeSpec before executing compileJava.

We’ve also utilized the OpenAPI plugin to configure the openApiGenerate and openApiValidate tasks, as well as created the mergeSpec task.

  • mergeSpec merges multiple OpenAPI spec files into a single yaml file. The output of this task is then used by the generate task to write API stubs.
  • openApiGenerate generates the stubs using the OpenAPI specification. The parameters within this block indicate where to find the OpenAPI specification, the location for the generated code, and the package names to use. It also provides specific configuration options for the generator.
  • openApiValidate validates the OpenAPI specification files.

Generate API Stubs:

Run the following command once OpenAPI setup is done

./gradlew openApiValidate openApiGenerate mergeSpec

Step 5: Healthcheck controller

When inspecting the generated directory, you'll find these files:

We’ll implement the newly created interface as our HealthCheck controller in the src directory.

Take a look at the code generated in HealthcheckAPI:

/**
* NOTE: This class is auto generated by OpenAPI Generator (<https://openapi-generator.tech>) (7.2.0).
* <https://openapi-generator.tech>
* Do not edit the class manually.
*/
// ...
public interface HealthcheckApi {
// ...
/**
* GET /healthcheck : healthcheck
*
* @return OK (status code 200)
*/
@Operation(
operationId = "healthcheck",
summary = "healthcheck",
responses = {
@ApiResponse(responseCode = "200", description = "OK", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = HealthcheckResponse.class))
})
}
)
@RequestMapping(
method = RequestMethod.GET,
value = "/healthcheck",
produces = { "application/json" }
)

default ResponseEntity<HealthcheckResponse> healthcheck(

) {
// ...
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}

In this interface, the request mapping, response type and API description is generated. We now have to implement the method with required logic.

We will implement this healthcheck() method declared here; by creating a HealthcheckController class in src/main/java/controllers :

@RestController
public class HealthcheckController implements HealthcheckApi {
@Override
public ResponseEntity<HealthcheckResponse> healthcheck() {
HealthcheckResponse response = new HealthcheckResponse()
.status("200")
.msg("Application is Running!");
return ResponseEntity.ok(response);
}
}

In this example, we’re returning a basic response to indicate that the application has started.

Step 6: Running the Application

Once everything is set up, you can run your application. With Spring Boot, this is as simple as running the ‘main’ method in your main class.

In your terminal, the steps for running the application would be:

  • Building openAPI stubs:
./gradlew clean openApiValidate openApiGenerate mergeSpec
  • Building project:
./gradlew build
  • Running the application:
./gradlew bootRun

The server usually starts on 8080 port:

Port after successful build

When you open the specified url for healthcheck, it will look like:

Server is running!

We’ve successfully set up a basic Spring Boot project! Now, we can begin adding more features to it.

--

--