Ever found yourself struggling to explain your API endpoints to team members or clients? 

We’ve all been there — diving into codebases where the only way to understand the API is through countless trial-and-error requests or digging through scattered documentation.

This is where Swagger comes into play, and it’s not just another fancy tool in your development skillset. 

Think of Swagger as your API’s autobiography — it tells the complete story of your endpoints, request parameters, response structures, and authentication requirements, all in an interactive and user-friendly interface. 

In this comprehensive guide, you’ll learn how to implement Swagger 3 in your Spring Boot applications using the latest springdoc-openapi library. 

You’ll discover how to transform your REST APIs into well-documented, interactive specifications that your team and clients will love.

What is Swagger ?

Swagger is a widely-used framework for building RESTful APIs. Swagger is based on OpenAPI Specification.

It is an open-source tool that allows you to describe, produce, and consume REST APIs.

With Swagger, you can create a standardized, language-agnostic interface for your API, making it easier for developers to understand and interact with your API.

One of the key features of Swagger is its ability to automatically generate API documentation, including code samples and tutorials.

This is achieved through the use of annotations such as @Tag, @ApiResponse, @Schema etc.

With tools like Swagger UI, you can create an interactive webpage where users can see how your API works and even test it. 

Swagger Editor makes it easy to write and update API descriptions. 

Swagger 3 also supports advanced features like reusable components, which save time and ensure consistency.

By using Swagger 3, you can make your APIs easy to understand for everyone, from developers to business teams. 

It’s a great way to build reliable APIs and keep your documentation up to date. 

Whether you’re just starting or working on a large project, Swagger 3 is a helpful tool for creating great APIs.

Swagger 3 Configuration

One of the first steps in implementing Swagger is adding the required dependency to your project. 

For Maven, add this to your pom.xml: 

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

Swagger UI

You can access your API documentation through Swagger UI by navigating to http://localhost:8080/swagger-ui/index.html after starting your application. 

This interface provides an interactive way to explore and test your API endpoints.

With Swagger UI, you can explore detailed information about each endpoint, including request parameters, response models, and authentication requirements. 

The interface allows you to execute API calls directly from the browser, making it an excellent tool for testing and development.

API documentation example

An example of API documentation can be created using the @Operation annotation on a controller method. 

For instance: 

@Operation(summary = "Get all users", 
           description = "Returns a list of all users") 
@GetMapping("/users") 
public List getAllUsers() { 
  // implementation 
}

This will generate the API documentation for the getAllUsers() method, including the summary and description. 

You can view the documentation in the Swagger UI.

Swagger Annotations

Swagger annotations are important for documenting your API. 

You will use them to describe your API endpoints, methods, and parameters.

@OpenAPIDefinition

Used at the application level to provide metadata for the OpenAPI specification, such as info, servers, tags, and security. Example:

@OpenAPIDefinition(
    info = @Info(title = "API Title", 
                 version = "1.0", 
                 description = "API Description"),
    servers = {@Server(url = "http://localhost:8080", 
                       description = "Local server")}
)
public class OpenAPIConfig { }

@Tag

You can use @Tag to provide metadata about your controller class, including a name and description.

@Tag(name = "Product Management", 
     description = "APIs for managing product operations") 
@RestController 
@RequestMapping("/api/products") 
public class ProductController { 
  // Controller methods 
}

In Swagger 3, @Tag annotation replaces the older @Api annotation.

@Operation

@Operation annotation is used to describe a specific operation or method in your API. 

This will help you to provide a clear understanding of what your method does.

Plus, you can use @Operation to specify the HTTP method, response type, and other details about the operation. 

For example, you can use @Operation to describe a GET method that retrieves a list of users: 

@Operation(summary = "Get all users", 
              description = "Returns a list of all users", 
              method = "GET")

In Swagger 3, @Operation annotation replaces @ApiOperation.

@Parameter

One of the important annotations is @Parameter, which is used to describe a method parameter. 

You can use it to specify the name, description, and other details about the parameter.

For example: 

@Parameter(value = "The user ID", required = true)

In Swagger 3, @Parameter annotation replaces @ApiParam.

@ApiResponse

Assuming you want to document the response of an API operation, you can use @ApiResponse

This annotation will help you to describe the response, including the response code, message, and response type.

@ApiResponse is used to document the possible responses of an API operation. 

For example: 

@ApiResponse(responseCode = 200, code = "User found")

In Swagger 3 vs Swagger 2, the parameters have been changed from code to responseCode and message to description.

@Schema

@Schema is used to describe a model or a data object. 

You can use it to provide a description of the model, and also to specify the properties of the model.

You can also use @Schema in the following places:

  1. Method Parameters
    Add metadata to controller method parameters for clarity.
  2. Method Return Types
    Document what a method returns for better API understanding.
  3. Fields in Request/Response Objects
    Provide detailed descriptions for fields in custom request/response models.
  4. Enums
    Explain possible enum values and their meanings.

Example of @Schema at a model class is:

@Schema(description = "Represents a user in the system")
public class User {

    @Schema(description = "Unique identifier of the user", 
            example = "12345")
    private Long id;

    @Schema(description = "Full name of the user", 
            example = "John Doe", required = true)
    private String name;

    @Schema(description = "Email address of the user", 
            example = "john.doe@example.com")
    private String email;

    @Schema(description = "Age of the user", 
            example = "30", 
            minimum = "18", 
            maximum = "100")
    private Integer age;

There are many other annotations such as @Content, @MediaType, @SecurityRequirement, @SecurityScheme etc., but the ones described in this article and below example are the most commonly used.

Swagger 3 Practical Example

Here’s a real-world example of using Swagger 3 annotations in a Spring Boot application for a User Management API

This example demonstrates various Swagger 3 annotations, including @Operation, @Schema, @Parameter, @ApiResponse, @RequestBody, and @Tags.

This API allows users to:

  1. Create a new user.
  2. Get user details by ID.
  3. Update user information.

Model Class(User)

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "Represents a user in the application")
public class User {

    @Schema(description = "Unique ID of the user", 
            example = "1", 
            required = true)
    private Long id;

    @Schema(description = "Full name of the user", 
            example = "John Doe", 
            required = true)
    private String name;

    @Schema(description = "Email address of the user", 
            example = "john.doe@example.com", 
            required = true)
    private String email;

    @Schema(description = "Age of the user", 
            example = "30", 
            minimum = "18", 
            maximum = "100")
    private Integer age;

    // Getters and setters
}

Controller Class

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.media.RequestBody;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/users")
@Tag(name = "User Management", description = "APIs for managing users")
public class UserController {

  private final List<User> users = new ArrayList<>();

  @Operation(summary = "Create a new user", description = "Adds a new user to the system")
  @ApiResponses(value = {
         @ApiResponse(responseCode = "201", 
                      description = "User created successfully"),
         @ApiResponse(responseCode = "400", 
                      description = "Invalid user input")
  })
  
  @PostMapping
  public String createUser(@RequestBody(description = "Details of the user to be created", 
                                        required = true) User user) {
        users.add(user);
    return "User created successfully!";
  }

  @Operation(summary = "Get user by ID", description = "Fetches user details by their unique ID")
  @ApiResponses(value = {
         @ApiResponse(responseCode = "200", 
                      description = "User details retrieved successfully"),
         @ApiResponse(responseCode = "404", 
                      description = "User not found")
  })
  
  @GetMapping("/{id}")
  public User getUserById(
            @Parameter(description = "ID of the user to fetch", 
                       example = "1", 
                       required = true)
            @PathVariable Long id) {
        return users.stream()
                .filter(user -> user.getId().equals(id))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("User not found"));
    }

    @Operation(summary = "Update user details", 
               description = "Updates the information of an existing user")
    @ApiResponses(value = {
         @ApiResponse(responseCode = "200", 
                      description = "User updated successfully"),
         @ApiResponse(responseCode = "404", 
                      description = "User not found"),
            @ApiResponse(responseCode = "400", description = "Invalid user input")
    })
    @PutMapping("/{id}")
    public String updateUser(
            @Parameter(description = "ID of the user to update", 
                       example = "1", 
                       required = true)
            @PathVariable Long id,
            @RequestBody(description = "Updated details of the user", 
                         required = true) User updatedUser) {
        User user = users.stream()
                .filter(u -> u.getId().equals(id))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("User not found"));

        user.setName(updatedUser.getName());
        user.setEmail(updatedUser.getEmail());
        user.setAge(updatedUser.getAge());
        return "User updated successfully!";
    }
}

Swagger 3 Annotations Used

  1. @Schema
    Describes the fields in the User model.
  2. @Tag
    Groups APIs by functionality.
  3. @Operation
    Describes the purpose and functionality of an API endpoint.
  4. @ApiResponse
    Specifies possible responses for an API.
  5. @Parameter
    Adds metadata to method parameters.
  6. @RequestBody
    Describes the body of a request.

Swagger Vs OpenAPI

Swagger and OpenAPI are closely related but serve different purposes and represent different stages in the evolution of API documentation tools and standards. 

Swagger is a suite of tools for designing, building, documenting, and testing APIs. 

It originally introduced a specification format for describing APIs, which has since evolved into the OpenAPI Specification.

The OpenAPI Specification (OAS) is a standardized format for describing REST APIs, defining how endpoints, inputs, outputs, and other details should be documented. 

It is the industry standard for API documentation.

Analogy

Imagine you are building a house:

OpenAPI is the blueprint or plan that specifies what the house will look like and how it will function.

Swagger is the set of tools (hammer, saw, drill) that helps you bring that plan to life efficiently.

In the API world, OpenAPI defines the standard, and Swagger provides the tools to implement and visualize it.

To wrap up

You now have a comprehensive understanding of using Swagger with Spring Boot. 

You’ve learned how to set up and configure Swagger, use real-world examples. 

With this knowledge, you can effectively document your APIs, making it easier for your users to understand and interact with your application, and you can maintain your API documentation with ease, ensuring your application’s success.

Categorized in:

Spring Boot,