Skillversitas

API Documentation (Swagger/OpenAPI)

What Is OpenAPI/Swagger?

OpenAPI is a standard for describing REST APIs. SpringDoc OpenAPI automatically generates interactive documentation from Spring Boot code.

Swagger UI provides a web page for viewing and testing the API directly from a browser.

Adding the Dependency

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

Once added, restart the application. Swagger UI is available at:

http://localhost:8080/swagger-ui.html

Basic Configuration

# application.properties
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.filter=true
springdoc.packages-to-scan=com.example.controller
@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("My Spring Boot API")
                .version("1.0.0")
                .description("API for the Spring Boot tutorial application")
                .contact(new Contact()
                    .name("Luthfi")
                    .email("[email protected]")))
            .addTagsItem(new Tag()
                .name("User Management")
                .description("CRUD operations for users"));
    }
}

The @Operation Annotation

Describe each endpoint:

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

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    @Operation(summary = "Get all users", description = "Fetch the list of all users")
    public ResponseEntity<List<UserResponseDTO>> getAllUsers() {
        return ResponseEntity.ok(userService.getAllUsers());
    }

    @GetMapping("/{id}")
    @Operation(summary = "Get user by ID", description = "Fetch user data by ID")
    public ResponseEntity<UserResponseDTO> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }

    @PostMapping
    @Operation(summary = "Create user", description = "Create a new user")
    public ResponseEntity<UserResponseDTO> createUser(
            @RequestBody @Valid UserRequestDTO request) {
        UserResponseDTO response = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

The @ApiResponse Annotation

Document the possible responses:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/{id}")
    @Operation(summary = "Get user by ID")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "User found",
            content = @Content(schema = @Schema(implementation = UserResponseDTO.class))),
        @ApiResponse(responseCode = "404", description = "User not found",
            content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
        @ApiResponse(responseCode = "500", description = "Internal server error")
    })
    public ResponseEntity<UserResponseDTO> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }

    @PostMapping
    @Operation(summary = "Create new user")
    @ApiResponses({
        @ApiResponse(responseCode = "201", description = "User created successfully"),
        @ApiResponse(responseCode = "400", description = "Validation failed")
    })
    public ResponseEntity<UserResponseDTO> createUser(
            @RequestBody @Valid UserRequestDTO request) {
        UserResponseDTO response = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

The @Schema Annotation

Describe the properties of a DTO:

public class UserRequestDTO {

    @Schema(description = "User full name", example = "John Smith", required = true)
    private String name;

    @Schema(description = "Email user", example = "[email protected]", required = true)
    private String email;

    @Schema(description = "Password user", example = "secretpass123", required = true)
    private String password;

    // getters, setters
}

public class UserResponseDTO {

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

    @Schema(description = "User full name", example = "John Smith")
    private String name;

    @Schema(description = "Email user", example = "[email protected]")
    private String email;

    @Schema(description = "Account creation time", example = "2024-01-15T10:30:00")
    private LocalDateTime createdAt;

    // getters, setters
}

Hiding Endpoints

Hide an endpoint from the documentation:

@Hidden
@GetMapping("/internal/metrics")
public ResponseEntity<Map<String, Object>> getInternalMetrics() {
    return ResponseEntity.ok(metricsService.getMetrics());
}

Parameter Documentation

@GetMapping("/search")
@Operation(summary = "Search users")
public ResponseEntity<List<UserResponseDTO>> searchUsers(
        @Parameter(description = "User name", example = "Mike")
        @RequestParam(required = false) String name,

        @Parameter(description = "Page", example = "0")
        @RequestParam(defaultValue = "0") int page,

        @Parameter(description = "Page size", example = "10")
        @RequestParam(defaultValue = "10") int size) {

    return ResponseEntity.ok(userService.search(name, page, size));
}

Testing the API via Swagger

Swagger UI provides a Try it out feature:

  1. Open http://localhost:8080/swagger-ui.html
  2. Click the endpoint you want to test
  3. Click the Try it out button
  4. Fill in the required parameters
  5. Click Execute
  6. See the response directly

Additional features:

Feature Description
Authorize Set a bearer token or basic auth
Try it out Test directly from the UI
Schema View the request/response structure
Download Export the OpenAPI spec (JSON/YAML)

Exporting the OpenAPI Spec

# Download the JSON spec
curl http://localhost:8080/v3/api-docs -o openapi.json

# Download the YAML spec
curl http://localhost:8080/v3/api-docs?format=yaml -o openapi.yaml

You can use this spec for:

  • Generating a client SDK (OpenAPI Generator)
  • Importing into Postman
  • Importing into other testing tools

Spring Security + Swagger

If you use Security, allow access to Swagger:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
            .anyRequest().authenticated()
        );
    return http.build();
}

With Swagger/OpenAPI, your API documentation is always up to date because it's generated from code. In the next chapter, we'll learn about Deployment of Spring Boot applications.