Documenting an API has several benefits. It helps stakeholders understand the API itself, and it speeds up development by giving clear instruction. Most projects use OpenAPI specification as the format. I will explain how to integrate OpenAPI specification into a Spring Boot project, specifically Tabunganku.

OpenAPI

OpenAPI specification, originally named Swagger specification, is a standardized format for documenting RESTful APIs, outlining details such as request/response formats, endpoints, and more. I use springdoc-openapi library for generating a documentation using OpenAPI specification. To use this library, the application must have annotations that will be parsed later by the library.

Example of Documentation Page using Swagger

Implementation

Import Library

To use springdoc-openapi, we have to add a new dependency in pom.xml:

1
2
3
4
5
<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>2.1.0</version>
</dependency>

Implementation in Java

After importing it, we can use the new annotations to define our operations. I use them in the interface classes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Tag(name = "Category", description = "Category management APIs")
public interface ICategoriesController {

  @Operation(
      summary = "Add a new category",
      description = "Add a new category. The request must provide user_id, category_name"
          + ", transaction_type",
      tags = {"categories", "save"}
  )
  @ApiResponses({
      @ApiResponse(
          responseCode = "200",
          content = {@Content(
              schema = @Schema(implementation = AddCategoryResponse.class),
              mediaType = "application/json")
          }
      ),
      @ApiResponse(
          responseCode = "400",
          content = {@Content(
              schema = @Schema(ref = "#/components/schemas/ErrorBody"),
              mediaType = "application/json")
          }
      )
  })
  AddCategoryResponse insertNewCategory(long userId, AddCategoryRequest request);

In the ICategoriesController class above, I use several annotations: @Tag, @Operation, and @ApiResponses. @Tag is used to describe a class. In this case, the name of this controller is Category. To describe the operation itself, I use @Operation and @ApiResponses.

What is the difference between those two? I use @Operation to write general information about what the operation does, and @ApiResponses to define possible outputs of the operation. In the example above, I write summary, description, and tags of an operation using @Operation annotation. On the other hand, I use @ApiResponses to map two possible outputs of the operation usong @ApiResponse annotation. The first @ApiResponse is the output when the function succeeds and returning AddCategoryResponse object. The other one is when the function encounters an error and return a status code 400, along with an ErrorBody schema.

What is ErrorBody schema mentioned above then ? It is a custom schema to wrap validation errors. If you haven’t already tried it, every validation error will lead to a list that explains the reason for the input being invalid. This is what the ErrorBody entails.

Example of Validation Error

To create this custom schema in the document, we define it in a configuration class. In DocsConfiguration class, I create an OpenAPI bean and create a new Schema object named errorSchema, which is a map with the key errors and a list of error strings as the value.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Bean
public OpenAPI customOpenAPI() {
  Schema errorSchema = new Schema<Map<String, Object>>()
      .addProperty("errors",
          new ArraySchema()
              .items(new StringSchema())
              .example("[\"str1\", \"str2\", \"str3\"]"));
  return new OpenAPI()
      .components(new Components().addSchemas("ErrorBody", errorSchema));
}

Insert @OpenAPIDefinition annotation in the main class (TabungankuApplication) to flesh out information about the application in the generated document.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@OpenAPIDefinition(
	servers = {
			@Server(url = "/", description = "Default Server URL")
	},
	info = @Info(
			title = "Tabunganku",
			description = "An application to track daily spending.",
			version = "0.1.0"
	)
)
@SpringBootApplication

In the code above, I include additional data about server endpoint, application name, application description, and application version.

Configuration File

To view the documentation page, we have to add a new property in the configuration file. Add this in the application.properties file:

springdoc.api-docs.enabled=true 

Run the backend server, and go to the endpoint /swagger-ui/index.html. For instance, if the backend server’s base URL is http://localhost:8080, go to http://localhost:8080/swagger-ui/index.html to view the API document.

Tabunganku API Documentation

  • Tabunganku BE: link
  • Petstore Swagger Example: link
  • springdoc-openapi library: link
  • springdoc properties: link