Friday, September 26, 2025

Spring Boot REST API Documentation - OpenAPI, Swagger

In this article we'll see how to integrate Spring Boot application with Open API to generate REST API documentation based on Open API specification.

springdoc-openapi library

springdoc-openapi Java library provides integration of Spring Boot application with Open API and Swagger. This library automates the generation of API documentation as per Open API 3 specification. springdoc-openapi works by examining an application at runtime to infer API semantics based on spring configurations, class structure and various annotations.

This library supports:

  • OpenAPI 3
  • Spring-boot v3
  • JSR-303 (Bean Validation)
  • Swagger-ui
  • OAuth 2
  • GraalVM native images

What you get with springdoc-openapi library

  1. Automatically generates documentation in JSON/YAML and HTML format APIs.
  2. You can enhance the automatically generated documentation by using Swagger-API annotations (e.g., @Tag, @Operation, @ApiResponse, @Parameter)
  3. springdoc-openapi provides various modules to support different Spring technologies and features-
  4. Spring WebMvc support through springdoc-openapi-starter-webmvc-ui (for both OpenAPI description and swagger-ui), springdoc-openapi-starter-webmvc-api (if you need only OpenAPI description).
  5. Spring WebFlux support through springdoc-openapi-starter-webflux-ui (for both OpenAPI description and swagger-ui), springdoc-openapi-starter-webflux-api (if you need only OpenAPI description).
  6. Spring Hateoas support- The support for Spring Hateoas is available using the dependency springdoc-openapi-hateoas.
  7. Spring Data Rest support- springdoc-openapi project supports spring-boot-starter-data-rest types like: @RepositoryRestResource and QuerydslPredicate annotations.
  8. Provides support for spring-security, Kotlin, Groovy, Javadoc.

Spring Boot with Open API and Swagger example

Please refer this post- Spring Boot + Data JPA + MySQL REST API CRUD Example to see the Controller class for which we are going to write unit tests.

UserController.java

Controller class is given here also for easy understanding.

@RestController
@RequestMapping("/user")
public class UserController {
  
  private final UserService userService;
  UserController(UserService userService){
    this.userService = userService;
  }
  
  // Insert user record
  @PostMapping
  public ResponseEntity<User> addUser(@Valid @RequestBody User user) {
    User createdUser = userService.addUser(user);
    return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
  }
  
  // Fetch all user records
  @GetMapping("/allusers")
  public ResponseEntity<List<User>> getAllUsers(){
    return ResponseEntity.ok(userService.getAllUsers());
  }
  
  // Fetch single user
  @GetMapping("/{id}")
  public ResponseEntity<User> getUserById(@PathVariable("id") int userId){
    //System.out.println("ID to find " + userId);
    User user = userService.getUserById(userId);
      return ResponseEntity.ok(user);
  }
  
  // Update user record
  @PutMapping
  public ResponseEntity<User> updateUser(@RequestBody User user) {
    System.out.println(user);
    User updatedUser = userService.updateUser(user);
    return new ResponseEntity<User>(updatedUser, HttpStatus.OK);
    
  }
  
  // Delete user record
  @DeleteMapping("/{id}")
  public ResponseEntity<Void> deleteUser(@PathVariable int id){
      userService.deleteUserById(id);
      return ResponseEntity.noContent().build();
      //return new ResponseEntity<String>("User deleted successfully", HttpStatus.OK);   
  }
  
  @GetMapping("/type")
  ResponseEntity<?> getUserByType(@RequestParam("type") String userType){

    System.out.println("userType " + userType);
    List<User> users = userService.getAllUsersByUserType(userType);
    if(users.isEmpty()) {
      return ResponseEntity.noContent().build();
    }
    return ResponseEntity.ok(users);
    
  }
}

springdoc-openapi dependency

First thing is to add the springdoc-openapi-starter-webmvc-ui starter for the integration between spring-boot and swagger-ui. Add the following to your pom.xml if you are using Maven

<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>2.8.12</version>
</dependency>

If you are using Gradle then

implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui: 2.8.12")

Please check the version as per your Spring Boot version.

That's all you need to generate API documentation. You can access the given endpoints.

  1. Endpoint for swagger UI page is- /swagger-ui.html
  2. Endpoint for OpenAPI description (in JSON format)- v3/api-docs

With Swagger UI you can see how to send requests for different methods in controller classes and what do you get back as response. You can even test the methods from Swagger UI.

On accessing http://localhost:8080/swagger-ui/index.html

Spring Boot Swagger UI

As you can see in the documentation for PUT mapping, it shows how request should look like, what will be the response format. You can test it too by clicking on "Try it out" button.

Access http://localhost:8080/v3/api-docs to get the API documentation in JSON format.

Spring Boot Open API

In the Swagger UI, you can also see the schema part where validations are also documented. User class is displayed here and you can see that the firstName and lastName are marked with @NotBlank annotation.

public class User {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private int userId;
  
  @NotBlank(message = "First name is required")
  @Column(name="FIRST_NAME")
  private String firstName;
  
  @NotBlank(message = "Last name is required")
  @Column(name="LAST_NAME")
  private String lastName;
  …
 …
}

In the schemas section you can see that the validation information is documented.

OpenAPI Scehmas

Open API Configuration

You can provide some information about the API documentation like title, description, contact, license etc.

For that you can create a bean definition for io.swagger.v3.oas.models.OpenAPI class, which is a root object for representing an OpenAPI document. You can add that bean definition to SpringBoot application class.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;

@SpringBootApplication
public class UserProjApplication {

	public static void main(String[] args) {
		SpringApplication.run(UserProjApplication.class, args);
	}
	
	@Bean
	public OpenAPI configOpenApi() {
		Contact contact = new Contact();
		contact.setName("TestUser");
		contact.setEmail("[email protected]");
		 return new OpenAPI().info(new Info()
				 	.title("User Management System")
				 	.version("1.0")
				 	.description("REST APIs to manage users")
				 	.contact(contact)
				 	.termsOfService("http://swagger.io/terms/")
				 	.license(new License().name("Apache 2.0").url("http://springdoc.org")));
				 
	}
}

With that you can verify that the given information is now getting displayed.

Spring Boot REST API Documentation

Customizing API documentation using Swagger 3 annotations

Using following annotations in your controller class you can enrich the generated documentation.

  1. @ApiResponse- To describe possible API responses.
  2. @Operation- To describe API operations (individual methods in Controller class)
  3. @Parameter- To describe method parameters.
  4. @Tag- To group related API operations.

Using @Tag annotation

You can use @Tag annotation with class or method. It is used to group the related methods. For example, in UserController there are three get methods which can be grouped together using @Tag annotation.

import io.swagger.v3.oas.annotations.tags.Tag;

@RestController
@RequestMapping("/user")
@Tag(name = "User", description = "User management REST APIs")
public class UserController {
  // Fetch all user records
  @GetMapping("/allusers")
  @Tag(name = "get", description = "Get all users")
  public ResponseEntity<List<User>> getAllUsers(){
    return ResponseEntity.ok(userService.getAllUsers());
  }
  
  // Fetch single user
  @GetMapping("/{id}")
  @Tag(name = "get", description = "Get user by ID")
  public ResponseEntity<User> getUserById(@PathVariable("id") int userId){
    //System.out.println("ID to find " + userId);
    User user = userService.getUserById(userId);
      return ResponseEntity.ok(user);
  }
  
  @GetMapping("/type")
  @Tag(name = "get", description = "Get users by user type")
  ResponseEntity<?> getUserByType(@RequestParam("type") String userType){

    System.out.println("userType " + userType);
    List<User> users = userService.getAllUsersByUserType(userType);
    if(users.isEmpty()) {
      return ResponseEntity.noContent().build();
    }
    return ResponseEntity.ok(users);
    
  }
  
  // Delete user record
  @DeleteMapping("/{id}")
  @Tag(name = "delete", description = "Delete user by ID")
  public ResponseEntity<Void> deleteUser(@PathVariable int id){
      userService.deleteUserById(id);
      return ResponseEntity.noContent().build();
      //return new ResponseEntity<String>("User deleted successfully", HttpStatus.OK);   
  }
}

As we have used @Tag annotation at class level that will group all the operations with in the class under "user" tag.

There is a @Tag annotation with name as "get" used with all the three get operations so, the get operations will be grouped together under "get" tag. Same way delete operations will be grouped together under "delete" tag.

Swagger tag Annotation

Using @Operation annotation

Using @Operation annotation you can provide additional information about API operation. For example, adding @Operation annotation on addUser() method (@PostMapping).

// Insert user record
@Operation(summary = "Insert user record", 
    description = "Create a new user, user data is sent as JSON. The response is created user.")
@PostMapping
public ResponseEntity<User> addUser(@Valid @RequestBody User user) {
  User createdUser = userService.addUser(user);
  return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
Swagger Operation Annotation

Using @ApiResponses and @ApiResponse annotations

Using @ApiResponses annotation you can provide information about the possible responses of an operation. Each response in turn is wrapped within ApiResponse annotation. For example, while creating a user, possible responses are 201 (Created), 400 (Bad request- Failed validation), 409(Conflict- User already exists).

// Insert user record
@Operation(summary = "Insert user record", 
    description = "Create a new user, user data is sent as JSON. The response is created user.")
@ApiResponses({
    @ApiResponse(responseCode = "201", content = {@Content(mediaType = "application/json",
            schema = @Schema(implementation = User.class))}),
    @ApiResponse(responseCode = "400", description = "User validation failed",
            content = @Content),
    @ApiResponse(responseCode = "409", description = "Created user already exists",
    content = @Content)})
@PostMapping
public ResponseEntity<User> addUser(@Valid @RequestBody User user) {
  User createdUser = userService.addUser(user);
  return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
Swagger API Responses

Using @Parameter annotation

Using @Parameter annotation you can provide information about the method parameters.

// Fetch single user
@GetMapping("/{id}")
@Tag(name = "get", description = "Get user by ID")
public ResponseEntity<User> getUserById(@Parameter(
        description = "ID of User to be fetched",
        required = true) @PathVariable("id") int userId){
  //System.out.println("ID to find " + userId);
  User user = userService.getUserById(userId);
    return ResponseEntity.ok(user);
}

@GetMapping("/type")
@Tag(name = "get", description = "Get users by user type")
ResponseEntity<?> getUserByType(@Parameter(
        description = "Type of users to be fetched",
        required = true) @RequestParam("type") String userType){

  System.out.println("userType " + userType);
  List<User> users = userService.getAllUsersByUserType(userType);
  if(users.isEmpty()) {
    return ResponseEntity.noContent().build();
  }
  return ResponseEntity.ok(users);
  
}
Swagger Parameter Annotation

That's all for this topic Spring Boot REST API Documentation - OpenAPI, Swagger. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Boot Unit Test For REST API
  2. Spring Boot + Spring Security JWT Authentication Example
  3. Spring Boot Spring Initializr
  4. Spring Boot Microservice - Service Registration and Discovery With Eureka
  5. Spring Boot Data JPA Repository Unit Test

You may also like-

  1. Spring depends-on Attribute and @DependsOn With Examples
  2. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example
  3. Spring Transaction Management Example - @Transactional Annotation and JDBC
  4. Spring Batch Processing With List of Objects in batchUpdate() Method
  5. Controlled and Uncontrolled Components in React
  6. How to Remove Elements From an ArrayList in Java
  7. Multi-Catch Statement in Java Exception Handling
  8. Strings in Python With Method Examples

No comments:

Post a Comment