API Documentation with Swagger

Generate Beautiful, Interactive API Docs Automatically

Why Document Your API?

Your API is useless if no one knows how to use it. Good documentation tells developers: what endpoints exist, what data to send, and what to expect back. Swagger generates this documentation automatically from your code.

Always Up-to-Date

Generated from code, so docs never become outdated.

Interactive Testing

Try API calls directly from the documentation page.

Client Generation

Generate SDKs for any language from OpenAPI spec.

Setup SpringDoc OpenAPI

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

That's it! Now visit:

  • Swagger UI: http://localhost:8080/swagger-ui.html
  • OpenAPI JSON: http://localhost:8080/v3/api-docs

Basic Configuration

# application.properties
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.swagger-ui.operationsSorter=method
springdoc.swagger-ui.tagsSorter=alpha
@Configuration
public class OpenAPIConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("User Management API")
                .version("1.0")
                .description("API for managing users and their profiles")
                .contact(new Contact()
                    .name("API Support")
                    .email("support@example.com")))
            .servers(List.of(
                new Server().url("http://localhost:8080").description("Development"),
                new Server().url("https://api.example.com").description("Production")
            ));
    }
}

Documenting Controllers

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

    @Operation(
        summary = "Get all users",
        description = "Returns a list of all registered users"
    )
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "Successfully retrieved users"),
        @ApiResponse(responseCode = "500", description = "Internal server error")
    })
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }

    @Operation(summary = "Get user by ID")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "User found"),
        @ApiResponse(responseCode = "404", description = "User not found")
    })
    @GetMapping("/{id}")
    public User getUser(
        @Parameter(description = "User ID", required = true, example = "1")
        @PathVariable Long id) {
        return userService.findById(id);
    }

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

Documenting Request/Response Objects

@Schema(description = "Request to create a new user")
public class CreateUserRequest {

    @Schema(description = "User's full name", example = "John Doe", required = true)
    @NotBlank
    private String name;

    @Schema(description = "User's email address", example = "john@example.com")
    @Email
    private String email;

    @Schema(description = "User's age", minimum = "18", maximum = "120")
    @Min(18)
    private Integer age;

    @Schema(description = "Account type", allowableValues = {"BASIC", "PREMIUM", "ADMIN"})
    private String accountType;
}

@Schema(description = "User response object")
public class UserResponse {

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

    @Schema(description = "User's display name")
    private String name;

    @Schema(description = "Account creation date", example = "2024-01-15")
    private LocalDate createdAt;
}

Authentication Documentation

@Configuration
public class OpenAPIConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info().title("Secure API").version("1.0"))
            .addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
            .components(new Components()
                .addSecuritySchemes("bearerAuth",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")
                        .description("Enter JWT token")));
    }
}

// In controller - mark endpoint as secured
@Operation(summary = "Get current user profile",
           security = @SecurityRequirement(name = "bearerAuth"))
@GetMapping("/profile")
public UserProfile getProfile() {
    return userService.getCurrentProfile();
}

// Or mark as public (no auth required)
@Operation(summary = "Health check")
@SecurityRequirements  // Empty = no security
@GetMapping("/health")
public String health() {
    return "OK";
}

Grouping APIs

@Configuration
public class OpenAPIConfig {

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

    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
            .group("admin")
            .pathsToMatch("/api/admin/**")
            .addOpenApiCustomizer(openApi ->
                openApi.info(new Info()
                    .title("Admin API")
                    .description("Administrative operations")))
            .build();
    }
}

Access at: /swagger-ui.html?group=public or /swagger-ui.html?group=admin

Common Annotations Reference

// Controller level
@Tag(name = "Users", description = "...")  // Group endpoints

// Method level
@Operation(summary = "...", description = "...")  // Describe endpoint
@ApiResponses({...})  // Document responses
@Hidden  // Hide from docs

// Parameter level
@Parameter(description = "...", required = true, example = "...")
@RequestBody(description = "...", required = true)

// Model level
@Schema(description = "...", example = "...", required = true)
@Schema(hidden = true)  // Hide field from docs

Build Professional REST APIs

Learn API design, documentation, and best practices.

Explore Full Stack Java Course