Integrate Swagger 3 with Spring Boot Rest API

June 22, 2024 ・0comments

 What is Swagger:

Swagger (now known as OpenAPI) is a specification for describing and documenting a REST API. It specifies the format of the REST web services including URL, resources, methods, etc. Swagger generates documentation from the application code and handles the rendering part as well.

In this post, I will integrate Swagger 3 documentation into a Spring Boot 3 based REST web service using Spring Doc OpenAPI. If you need guidance on running or building a Spring Boot project, please refer to my previous post.

Dependencies:

Add the following dependencies to your project POM.xml file. In this project I am using Spring Doc OpenAPI starter and Swagger Core Annotation libraries. 

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>2.2.22</version>
        </dependency>


Spring Configuration: 

To configure the documentation, create a Spring Java Configuration class:

To configure the documentation, you can create a Spring Java Configuration class using Spring’s @Configuration annotation. The following example shows how to generate Swagger documentation based on the RestController classes:

package com.chandana.helloworld.config;

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;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {

        @Bean
        public OpenAPI customOpenAPI() {
                return new OpenAPI()
                                .info(new Info()
                                                .title("Greetings API Title")
                                                .description("Greetings API Definition")
                                                .version("1.0.0")
                                                .contact(new Contact()
                                                                .name("Chandana Napagoda")
                                                                .url("https://blog.napagoda.com")
                                                                .email("cnapagoda@gmail.com"))
                                                .license(new License()
                                                                .name("Apache 2.0")
                                                                .url("http://www.apache.org/licenses/LICENSE-2.0")));
        }

        @Bean
        public GroupedOpenApi publicApi() {
                return GroupedOpenApi.builder()
                                .group("1.0.0")
                                .pathsToMatch("/api/**")
                                .build();
        }
}

Spring doc OpenAPI uses GroupedOpenApi to configure a subset of the services to be documented and group them by a name, etc. This configuration will include all APIs under /api/** path.

You can provide custom information about your API using the OpenAPI class. This allows you to change default values such as the title, description, version, license, and contact information. With this configuration, the generated documentation will include the specified title, description, version, contact, and license information.

Spring Boot Generated Swagger Info

As an alternative to the Spring Java Configuration class, you can define a class with the @OpenAPIDefinition annotation and include complete documentation under that annotation. I have included examples of both in my GitHub repository(spring-boot-3-swagger-3-with-openapidefinition).

Controller and POJO Level Documentation : 

To document individual controllers and methods, use annotations from the Swagger library:

@Operation annotation to describe the resources and methods.

@ApiResponses annotation to describe other responses that can be returned by the operation (e.g., 200 OK or 202 Accepted).

@Schema annotation to describe the properties of the POJO (Bean) class or class.

@Parameter annotation to describe the parameters 

@Hidden annotation hide specific API endpoint or controller from auto-generated OpenAPI documentation.

package com.chandana.helloworld.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;

@RestController
@RequestMapping("/api/greetings")
@Tag(name = "greetings", description = "These are greetings API operations")
public class GreetingController {

    private final Map<Integer, GreetingResponse> examples = new HashMap<>();

    @GetMapping("/{id}")
    @Operation(summary = "Get example by ID", description = "Retrieve an example resource by its ID")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Successful operation"),
            @ApiResponse(responseCode = "404", description = "Greeting not found")
    })
    public ResponseEntity<GreetingResponse> getExample(
            @PathVariable @Parameter(allowEmptyValue = false, required = true) int id) {
        GreetingResponse example = examples.get(id);
        if (example == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(example, HttpStatus.OK);
    }

    @PostMapping
    @Operation(summary = "Create a new example", description = "Create a new example resource")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "Greeting created"),
            @ApiResponse(responseCode = "400", description = "Invalid input")
    })
    public ResponseEntity<GreetingResponse> createExample(@RequestBody GreetingRequest request) {
        GreetingResponse example = new GreetingResponse("Created " + request.getMessage());
        int id = examples.size() + 1;
        examples.put(id, example);
        return new ResponseEntity<>(example, HttpStatus.CREATED);
    }

    @PutMapping("/{id}")
    @Operation(summary = "Update an example by ID", description = "Update an existing example resource by its ID")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Greeting updated"),
            @ApiResponse(responseCode = "404", description = "Greeting not found")
    })
    public ResponseEntity<GreetingResponse> updateExample(
            @PathVariable @Parameter(allowEmptyValue = false, required = true) int id,
            @RequestBody GreetingRequest request) {
        GreetingResponse example = examples.get(id);
        if (example == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        example.setMessage("Updated " + request.getMessage());
        return new ResponseEntity<>(example, HttpStatus.OK);
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "Delete an example by ID", description = "Delete an example resource by its ID")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "Greeting deleted"),
            @ApiResponse(responseCode = "404", description = "Greeting not found")
    })
    public ResponseEntity<Void> deleteExample(
            @PathVariable @Parameter(allowEmptyValue = false, required = true) int id) {
        if (!examples.containsKey(id)) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        examples.remove(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

After adding these annotations, the final generated Swagger documentation will be enriched with detailed information about your API endpoints and data models. 

Swagger documentation published at : http://localhost:8080/swagger-ui/index.html 

Spring Boot Generated Complete Swagger Documentation



Greeting Request & Response Model:

package com.chandana.helloworld.controller;

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

@Schema(description = "The example request message")
public class GreetingRequest {

    @Schema(description = "The example message", example = "Hello, World!")
    private String message;

    // Getters and setters

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
package com.chandana.helloworld.controller;

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

public class GreetingResponse {

    @Schema(description = "The example response message")
    private String message;

    public GreetingResponse(String message) {
        this.message = message;
    }

    // Getters and setters

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Please refrain from copying content to other websites. You can download the Swagger Spring Boot Project source code from my GitHub repository.

Post a Comment