Why API Documentation Matters
You have built a fully functional blog API with authentication, file uploads, validation, and pagination. But there is a problem: how does anyone else know how to use it?
The Consumers of Your API
Your API has multiple consumers:
- Frontend developers building a React/Vue/Angular web app
- Mobile developers building Android and iOS apps
- Third-party integrators connecting their systems to yours
- Future you — six months from now, you will not remember every endpoint detail
Without documentation, these consumers must read your source code to understand the API. That is slow, error-prone, and impractical for external developers.
What Good API Documentation Includes
- Every endpoint with its URL, HTTP method, and description
- Request parameters (path variables, query parameters, headers)
- Request body schema with field types, constraints, and examples
- Response body schema for success and error cases
- Authentication requirements
- Interactive “try it out” functionality for testing
Manual Documentation is a Lie
You could write documentation in a wiki or a Markdown file. But manual documentation has a fatal flaw: it falls out of sync with the code. A developer adds a new field to the DTO, forgets to update the docs, and now the documentation lies. Lying documentation is worse than no documentation — it actively misleads consumers.
The solution: generate documentation from the code. The code is always correct (by definition), so documentation derived from it is always accurate.
OpenAPI Specification Overview
What is OpenAPI?
The OpenAPI Specification (formerly known as Swagger Specification) is a standard format for describing REST APIs. It is a machine-readable document (JSON or YAML) that describes every aspect of your API.
An OpenAPI document looks like this (simplified):
openapi: 3.0.3
info:
title: Blog API
version: 1.0.0
paths:
/api/posts:
get:
summary: List all posts
parameters:
- name: page
in: query
schema:
type: integer
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PostResponse'
You never write this by hand. Tools generate it from your code.
The Ecosystem
- OpenAPI Specification — The standard format (the “language”)
- SpringDoc OpenAPI — A library that scans your Spring Boot code and generates the OpenAPI document
- Swagger UI — A web interface that renders the OpenAPI document as interactive documentation
- Swagger Editor — A tool for editing OpenAPI documents manually
- Swagger Codegen — Generates client SDKs from an OpenAPI document
We use SpringDoc OpenAPI to generate the spec and Swagger UI to display it.
Setting Up SpringDoc OpenAPI
Add the Dependency
<!-- SpringDoc OpenAPI — generates OpenAPI spec + includes Swagger UI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
That is all. No annotations on the main class, no configuration beans (yet). SpringDoc automatically scans your controllers, DTOs, and annotations to generate the OpenAPI document.
What Happens After Adding the Dependency
SpringDoc registers three endpoints:
| URL | Purpose |
|---|---|
/swagger-ui.html |
Interactive Swagger UI |
/v3/api-docs |
OpenAPI spec in JSON format |
/v3/api-docs.yaml |
OpenAPI spec in YAML format |
Start your application and open http://localhost:8080/swagger-ui.html in your browser. You should see an interactive documentation page listing all your controllers and endpoints — with zero configuration.
Make Swagger Endpoints Public
Add these to your SecurityConfig so Swagger UI is accessible without authentication:
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html").permitAll()
Accessing Swagger UI
The Default Swagger UI
Open http://localhost:8080/swagger-ui.html and you will see:
Blog API
────────────────────────────────
auth-controller
POST /api/auth/register
POST /api/auth/login
POST /api/auth/refresh
post-controller
GET /api/posts
POST /api/posts
GET /api/posts/{id}
PUT /api/posts/{id}
DELETE /api/posts/{id}
PATCH /api/posts/{id}/publish
file-controller
GET /api/files/{filePath}
...
Each endpoint is expandable. Click on GET /api/posts and you see:
- Parameters (page, size, sort, direction, status)
- Response schema (PostResponse fields with types)
- A “Try it out” button that lets you execute the request from the browser
Customizing the URL
# Change the Swagger UI path (default: /swagger-ui.html)
springdoc.swagger-ui.path=/docs
# Change the API docs path (default: /v3/api-docs)
springdoc.api-docs.path=/api-docs
# Sort endpoints alphabetically
springdoc.swagger-ui.operationsSorter=alpha
# Sort tags alphabetically
springdoc.swagger-ui.tagsSorter=alpha
# Expand operations by default (none, list, full)
springdoc.swagger-ui.docExpansion=list
Now Swagger UI is at http://localhost:8080/docs.
Customizing API Info and Descriptions
The OpenAPI Configuration Bean
Create a configuration class to customize the API’s general information:
File: src/main/java/com/example/blogapi/config/OpenApiConfig.java
package com.example.blogapi.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 io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Blog REST API")
.description("""
A comprehensive blog platform API built with Spring Boot and MariaDB.
## Features
- User registration and JWT authentication
- CRUD operations for posts, comments, categories, and tags
- File upload for post cover images and user avatars
- Role-based access control (USER, AUTHOR, ADMIN)
- Pagination, sorting, and search
## Authentication
Most endpoints require a JWT token. Obtain one via `POST /api/auth/login`.
Then click the **Authorize** button above and enter: `Bearer <your-token>`.
""")
.version("1.0.0")
.contact(new Contact()
.name("Blog API Team")
.email("api@blog.example.com")
.url("https://github.com/example/blog-api"))
.license(new License()
.name("MIT License")
.url("https://opensource.org/licenses/MIT")))
.servers(List.of(
new Server()
.url("http://localhost:8080")
.description("Local development"),
new Server()
.url("https://api.blog.example.com")
.description("Production")
));
}
}
This metadata appears at the top of Swagger UI. The description supports Markdown, so you can include formatted text, lists, and links.
Documenting Endpoints with @Operation, @Parameter, @Schema
SpringDoc generates reasonable documentation automatically, but you can enrich it with annotations from the io.swagger.v3.oas.annotations package.
@Operation — Describing an Endpoint
@RestController
@RequestMapping("/api/posts")
@Tag(name = "Posts", description = "Blog post management") // Groups endpoints under "Posts" tag
public class PostController {
@Operation(
summary = "Create a new blog post",
description = """
Creates a new blog post with the specified title, content, and metadata.
The post is created in DRAFT status by default.
Requires AUTHOR or ADMIN role.
""",
responses = {
@ApiResponse(
responseCode = "201",
description = "Post created successfully",
content = @Content(schema = @Schema(implementation = PostResponse.class))
),
@ApiResponse(
responseCode = "400",
description = "Validation error — invalid input data",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))
),
@ApiResponse(
responseCode = "401",
description = "Authentication required"
),
@ApiResponse(
responseCode = "403",
description = "Insufficient permissions — requires AUTHOR or ADMIN role"
)
}
)
@PostMapping
public ResponseEntity<PostResponse> createPost(
@Valid @RequestBody CreatePostRequest request) {
// ...
}
}
@Parameter — Describing Parameters
@Operation(summary = "List posts with pagination and filtering")
@GetMapping
public Page<PostResponse> listPosts(
@Parameter(description = "Page number (0-indexed)", example = "0")
@RequestParam(defaultValue = "0") int page,
@Parameter(description = "Number of items per page", example = "10")
@RequestParam(defaultValue = "10") int size,
@Parameter(description = "Field to sort by", example = "createdAt",
schema = @Schema(allowableValues = {"createdAt", "title", "status", "publishedAt"}))
@RequestParam(defaultValue = "createdAt") String sort,
@Parameter(description = "Sort direction", example = "desc",
schema = @Schema(allowableValues = {"asc", "desc"}))
@RequestParam(defaultValue = "desc") String direction,
@Parameter(description = "Filter by status", example = "PUBLISHED",
schema = @Schema(allowableValues = {"DRAFT", "PUBLISHED", "ARCHIVED"}))
@RequestParam(required = false) String status) {
// ...
}
@Parameter for Path Variables
@Operation(summary = "Get a post by ID")
@GetMapping("/{id}")
public PostResponse getPost(
@Parameter(description = "Post ID", required = true, example = "1")
@PathVariable Long id) {
// ...
}
Documenting Request/Response Models
@Schema on DTOs
SpringDoc reads your DTO classes and generates schema documentation automatically. Enhance it with @Schema:
package com.example.blogapi.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.util.List;
@Schema(description = "Request body for creating a new blog post")
public class CreatePostRequest {
@Schema(
description = "The title of the blog post",
example = "Getting Started with Spring Boot",
minLength = 3,
maxLength = 500,
requiredMode = Schema.RequiredMode.REQUIRED
)
@NotBlank(message = "Title is required")
@Size(min = 3, max = 500)
private String title;
@Schema(
description = "The full content of the post (supports Markdown)",
example = "Spring Boot makes it easy to create stand-alone applications...",
minLength = 10,
requiredMode = Schema.RequiredMode.REQUIRED
)
@NotBlank(message = "Content is required")
@Size(min = 10)
private String content;
@Schema(
description = "A short summary displayed on list pages",
example = "A beginner-friendly guide to Spring Boot",
maxLength = 1000
)
@Size(max = 1000)
private String excerpt;
@Schema(description = "ID of the post author", example = "1",
requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull
@Positive
private Long authorId;
@Schema(description = "ID of the category (optional)", example = "2")
@Positive
private Long categoryId;
@Schema(description = "List of tag IDs to assign", example = "[1, 3, 5]")
private List<Long> tagIds;
// constructors, getters, setters...
public CreatePostRequest() { }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getExcerpt() { return excerpt; }
public void setExcerpt(String excerpt) { this.excerpt = excerpt; }
public Long getAuthorId() { return authorId; }
public void setAuthorId(Long authorId) { this.authorId = authorId; }
public Long getCategoryId() { return categoryId; }
public void setCategoryId(Long categoryId) { this.categoryId = categoryId; }
public List<Long> getTagIds() { return tagIds; }
public void setTagIds(List<Long> tagIds) { this.tagIds = tagIds; }
}
Documenting the Response Model
@Schema(description = "Blog post data returned by the API")
public class PostResponse {
@Schema(description = "Unique post identifier", example = "1")
private Long id;
@Schema(description = "Post title", example = "Getting Started with Spring Boot")
private String title;
@Schema(description = "URL-friendly slug", example = "getting-started-with-spring-boot")
private String slug;
@Schema(description = "Full post content")
private String content;
@Schema(description = "Short excerpt for list pages")
private String excerpt;
@Schema(description = "Publication status", example = "PUBLISHED",
allowableValues = {"DRAFT", "PUBLISHED", "ARCHIVED"})
private String status;
@Schema(description = "Author's display name", example = "Alice Johnson")
private String authorName;
@Schema(description = "Category name", example = "Tutorial")
private String categoryName;
@Schema(description = "List of tag names", example = "[\"Java\", \"Spring Boot\"]")
private List<String> tagNames;
@Schema(description = "Number of comments on this post", example = "12")
private int commentCount;
@Schema(description = "Cover image URL", example = "/api/files/posts/abc123.jpg")
private String coverImageUrl;
@Schema(description = "When the post was published", example = "2024-01-15T10:30:00")
private LocalDateTime publishedAt;
@Schema(description = "When the post was created", example = "2024-01-15T09:00:00")
private LocalDateTime createdAt;
// ... getters and setters
}
Documenting the Error Response
@Schema(description = "Standard error response format")
public class ErrorResponse {
@Schema(description = "HTTP status code", example = "404")
private int status;
@Schema(description = "Error type", example = "Not Found")
private String error;
@Schema(description = "Human-readable error message",
example = "Post not found with id: 999")
private String message;
@Schema(description = "Request path that caused the error",
example = "/api/posts/999")
private String path;
@Schema(description = "When the error occurred")
private LocalDateTime timestamp;
@Schema(description = "Field-level validation errors (only for validation failures)",
example = "{\"title\": [\"Title is required\"]}")
private Map<String, List<String>> validationErrors;
// ... getters and setters
}
Grouping APIs by Tags
Using @Tag to Organize Endpoints
Without tags, Swagger UI groups endpoints by controller name (post-controller, auth-controller). Tags let you create meaningful groups:
@RestController
@RequestMapping("/api/auth")
@Tag(name = "Authentication", description = "User registration, login, and token management")
public class AuthController {
// All endpoints in this controller are grouped under "Authentication"
}
@RestController
@RequestMapping("/api/posts")
@Tag(name = "Posts", description = "Blog post CRUD operations, publishing, and search")
public class PostController {
// All endpoints grouped under "Posts"
}
@RestController
@RequestMapping("/api/users")
@Tag(name = "Users", description = "User profile management and avatar upload")
public class UserController { }
@RestController
@RequestMapping("/api/files")
@Tag(name = "Files", description = "File serving and download")
public class FileController { }
Cross-Controller Grouping
A single endpoint can belong to multiple tags:
@PostMapping("/{postId}/comments")
@Operation(
summary = "Add a comment to a post",
tags = {"Posts", "Comments"} // Appears under both groups in Swagger UI
)
public ResponseEntity<CommentResponse> addComment(...) { }
Custom Tag Order
# Display tags in a specific order
springdoc.swagger-ui.tagsSorter=alpha
Or define the order programmatically in OpenApiConfig:
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(...)
.tags(List.of(
new io.swagger.v3.oas.models.tags.Tag()
.name("Authentication")
.description("Registration, login, and token management"),
new io.swagger.v3.oas.models.tags.Tag()
.name("Posts")
.description("Blog post operations"),
new io.swagger.v3.oas.models.tags.Tag()
.name("Users")
.description("User profile management"),
new io.swagger.v3.oas.models.tags.Tag()
.name("Files")
.description("File serving")
));
}
Tags appear in Swagger UI in the order they are listed here.
Securing Swagger with JWT
Adding JWT Authentication to Swagger UI
Configure Swagger UI to include a JWT bearer token input:
Update OpenApiConfig.java:
package com.example.blogapi.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
// Define the security scheme (JWT Bearer token)
final String securitySchemeName = "Bearer Authentication";
return new OpenAPI()
.info(new Info()
.title("Blog REST API")
.description("Blog platform API with JWT authentication.")
.version("1.0.0"))
.servers(List.of(
new Server().url("http://localhost:8080").description("Local")))
// Add the security scheme to the components
.components(new Components()
.addSecuritySchemes(securitySchemeName,
new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.description("Enter your JWT token. " +
"Obtain one via POST /api/auth/login.")))
// Apply the security scheme globally (all endpoints require auth by default)
.addSecurityItem(new SecurityRequirement()
.addList(securitySchemeName));
}
}
What This Does in Swagger UI
After adding this configuration, Swagger UI displays an “Authorize” button at the top of the page. When you click it:
- A dialog appears asking for a Bearer token
- You paste your JWT token (without the “Bearer ” prefix — Swagger adds it)
- Click “Authorize”
- All subsequent “Try it out” requests include the
Authorization: Bearerheader
Marking Public Endpoints
With the global security requirement, Swagger UI shows a lock icon on every endpoint. For public endpoints that do not need authentication, use @SecurityRequirements:
@Operation(summary = "List published posts")
@SecurityRequirements() // Empty — explicitly marks this endpoint as NOT requiring auth
@GetMapping
public Page<PostResponse> listPosts(...) { }
@Operation(summary = "Login and get JWT tokens")
@SecurityRequirements()
@PostMapping("/login")
public ResponseEntity<AuthResponse> login(...) { }
@Operation(summary = "Register a new account")
@SecurityRequirements()
@PostMapping("/register")
public ResponseEntity<AuthResponse> register(...) { }
Now public endpoints show an open lock icon, while protected endpoints show a closed lock.
Hands-on: Fully Document the Blog API
Let us apply all documentation features to the complete blog API.
Step 1: Annotate the Auth Controller
@RestController
@RequestMapping("/api/auth")
@Tag(name = "Authentication", description = "User registration, login, and token management")
public class AuthController {
private final AuthService authService;
public AuthController(AuthService authService) {
this.authService = authService;
}
@Operation(
summary = "Register a new user",
description = "Creates a new user account with ROLE_USER. Username and email must be unique.",
responses = {
@ApiResponse(responseCode = "201", description = "User registered successfully"),
@ApiResponse(responseCode = "400", description = "Validation error"),
@ApiResponse(responseCode = "409", description = "Username or email already exists")
}
)
@SecurityRequirements()
@PostMapping("/register")
public ResponseEntity<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
return ResponseEntity.status(HttpStatus.CREATED).body(authService.register(request));
}
@Operation(
summary = "Login and get JWT tokens",
description = "Authenticates a user and returns access + refresh tokens. " +
"The access token expires in 24 hours. Use the refresh token to get a new one.",
responses = {
@ApiResponse(responseCode = "200", description = "Login successful — tokens returned"),
@ApiResponse(responseCode = "400", description = "Invalid username or password")
}
)
@SecurityRequirements()
@PostMapping("/login")
public ResponseEntity<AuthResponse> login(@Valid @RequestBody LoginRequest request) {
return ResponseEntity.ok(authService.login(request));
}
@Operation(
summary = "Refresh access token",
description = "Exchange a valid refresh token for a new access token. " +
"The refresh token is not rotated — use the same one until it expires.",
responses = {
@ApiResponse(responseCode = "200", description = "New access token generated"),
@ApiResponse(responseCode = "400", description = "Invalid or expired refresh token")
}
)
@SecurityRequirements()
@PostMapping("/refresh")
public ResponseEntity<AuthResponse> refreshToken(@RequestBody Map<String, String> request) {
String refreshToken = request.get("refreshToken");
return ResponseEntity.ok(authService.refreshToken(refreshToken));
}
}
Step 2: Annotate Key Post Controller Endpoints
@RestController
@RequestMapping("/api/posts")
@Tag(name = "Posts", description = "Blog post management — CRUD, publishing, and search")
public class PostController {
@Operation(
summary = "Search posts by keyword",
description = "Searches post titles and content for the given keyword. " +
"Returns paginated results sorted by relevance."
)
@SecurityRequirements()
@GetMapping("/search")
public ResponseEntity<Page<PostResponse>> searchPosts(
@Parameter(description = "Search keyword (minimum 2 characters)",
required = true, example = "spring boot")
@RequestParam String keyword,
@Parameter(description = "Page number", example = "0")
@RequestParam(defaultValue = "0") int page,
@Parameter(description = "Page size", example = "10")
@RequestParam(defaultValue = "10") int size) {
// ...
}
@Operation(
summary = "Upload post cover image",
description = "Uploads a cover image for the specified post. " +
"Accepted formats: JPEG, PNG, GIF, WebP. Maximum size: 5MB. " +
"Replaces the existing cover image if one exists."
)
@PostMapping(value = "/{id}/cover-image", consumes = "multipart/form-data")
public ResponseEntity<FileUploadResponse> uploadCoverImage(
@Parameter(description = "Post ID") @PathVariable Long id,
@Parameter(description = "Image file to upload") @RequestParam("file") MultipartFile file,
Authentication authentication) {
// ...
}
}
Step 3: Verify the Documentation
Start the application and open http://localhost:8080/swagger-ui.html. Verify:
- API info — Title, description, version, server URLs appear at the top
- Tag groups — Endpoints are grouped by Authentication, Posts, Users, Files
- Authorize button — Clicking it shows the JWT token input
- Endpoint details — Each endpoint shows summary, description, parameters, and response schemas
- Schema models — At the bottom, all DTOs are listed with field descriptions and examples
- Try it out — You can execute requests directly from the browser
Step 4: Test the Interactive Flow
1. In Swagger UI, expand "Authentication" → "POST /api/auth/login"
2. Click "Try it out"
3. Enter: {"username": "alice", "password": "securepass123"}
4. Click "Execute"
5. Copy the accessToken from the response
6. Click the "Authorize" button (top of page)
7. Paste the token → click "Authorize"
8. Now expand "Posts" → "POST /api/posts"
9. Click "Try it out" → fill in the request body → click "Execute"
10. The request includes your JWT token automatically
Step 5: Export the OpenAPI Spec
The OpenAPI document is available at /v3/api-docs. You can use it to:
- Generate client SDKs (TypeScript, Kotlin, Swift, etc.)
- Import into Postman as a collection
- Validate API compliance in CI/CD
- Generate static documentation sites
# Download the OpenAPI spec as JSON
curl http://localhost:8080/v3/api-docs -o openapi.json
# Download as YAML
curl http://localhost:8080/v3/api-docs.yaml -o openapi.yaml
Step 6: Disable Swagger in Production (Optional)
If you do not want Swagger UI exposed in production:
# application-prod.properties
springdoc.swagger-ui.enabled=false
springdoc.api-docs.enabled=false
Or keep it enabled but protect it behind admin authentication.
Step 7: Exercises
- Document all DTOs: Add
@Schemaannotations with descriptions and examples toRegisterRequest,LoginRequest,CreateCommentRequest,CommentResponse, andFileUploadResponse. - Add error response examples: For each endpoint’s 400/404/409 error responses, add
content = @Content(schema = @Schema(implementation = ErrorResponse.class))so consumers can see the error format. - Create an API group: Use
springdoc.group-configsto create separate documentation for public endpoints (no auth required) and admin endpoints:
“properties springdoc.group-configs[0].group=public springdoc.group-configs[0].paths-to-match=/api/auth/,/api/posts/ springdoc.group-configs[1].group=admin springdoc.group-configs[1].paths-to-match=/api/admin/** “
- Generate a Postman collection: Download the OpenAPI JSON from
/v3/api-docs, import it into Postman, and verify all endpoints are correctly imported with parameters and request bodies. - Hide internal endpoints: Use
@Hiddenannotation to hide internal/debug endpoints from Swagger UI:
“java @Hidden @GetMapping("/api/internal/health") public String healthCheck() { return "OK"; } “
Summary
This lecture made your API self-documenting and interactive:
- Why documentation matters: API consumers need to know endpoints, parameters, schemas, and auth requirements. Manual docs go stale; generated docs stay accurate.
- OpenAPI Specification: The industry standard for describing REST APIs. Machine-readable (JSON/YAML), used by tools for UI generation, code generation, and validation.
- SpringDoc OpenAPI: One dependency auto-generates the OpenAPI spec from your Spring Boot code. Swagger UI provides interactive documentation at
/swagger-ui.html. - @Operation: Describes what an endpoint does — summary, description, and response codes.
- @Parameter: Describes query parameters, path variables, and headers — type, description, examples, allowed values.
- @Schema: Describes DTO fields — type, description, examples, constraints. Both on request and response models.
- @Tag: Groups related endpoints in Swagger UI. Apply at the controller level or per endpoint.
- JWT in Swagger: Configure a
SecuritySchemewithbearertype. Users click “Authorize,” paste their token, and all requests include it. Use@SecurityRequirements()on public endpoints. - OpenAPI export: The spec at
/v3/api-docscan generate client SDKs, Postman collections, and static documentation.
What is Next
In Lecture 15, we will write Tests for the Blog API — unit tests for the service layer with Mockito, repository tests with @DataJpaTest, controller tests with @WebMvcTest, integration tests with @SpringBootTest, and tests with TestContainers for a real MariaDB instance.
Quick Reference
| Concept | Description |
|---|---|
| OpenAPI | Industry standard for describing REST APIs (JSON/YAML format) |
| SpringDoc | Library that generates OpenAPI spec from Spring Boot code |
| Swagger UI | Interactive web interface for API documentation |
/swagger-ui.html |
URL for the Swagger UI page |
/v3/api-docs |
URL for the OpenAPI specification (JSON) |
@Tag |
Groups endpoints under a named category |
@Operation |
Describes an endpoint (summary, description, responses) |
@ApiResponse |
Documents a specific HTTP response code |
@Parameter |
Describes a method parameter (query, path, header) |
@Schema |
Describes a DTO field (type, example, constraints) |
@Content |
Specifies the response body schema in @ApiResponse |
@SecurityRequirements() |
Marks an endpoint as not requiring authentication |
@Hidden |
Hides an endpoint from Swagger UI |
SecurityScheme |
Configures authentication method in OpenAPI (Bearer JWT) |
springdoc.swagger-ui.enabled |
Enable/disable Swagger UI |
springdoc.group-configs |
Create multiple API documentation groups |
