Why this matters
- API documentation that drifts from implementation is worse than no documentation — springdoc generates specs from annotations automatically.
- Swagger UI lets frontend teams and QA explore endpoints without reading source code.
- OpenAPI specs enable client code generation and contract testing in CI pipelines.
Add springdoc
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.4</version>
</dependency>
Start BookStore and visit:
Documentation URLs
- Swagger UI:
http://127.0.0.1:8080/swagger-ui.html - Raw spec:
http://127.0.0.1:8080/v3/api-docs
No configuration needed for basic usage — springdoc discovers all @RestController endpoints.
Enriching documentation
@RestController
@RequestMapping("/api/books")
@Tag(name = "Books", description = "BookStore catalog operations")
public class BookController {
@Operation(summary = "Get book by ID",
description = "Returns a single book from the catalog")
@ApiResponse(responseCode = "200", description = "Book found")
@ApiResponse(responseCode = "404", description = "Book not found")
@GetMapping("/{id}")
public BookResponse get(@Parameter(description = "Book ID") @PathVariable Long id) {
return BookResponse.from(bookService.findById(id));
}
}
Annotations from io.swagger.v3.oas.annotations appear in the generated spec and Swagger UI.
Useful OpenAPI annotations
@Tag— Group endpoints under a named section in Swagger UI.@Operation— Summary and description for a single endpoint.@ApiResponse— Document possible HTTP status codes.@Parameter— Describe path variables and query parameters.@Schema— Document DTO fields with examples and constraints.
Documenting DTOs
@Schema(description = "Request to create a new book")
public record CreateBookRequest(
@Schema(example = "Clean Code", description = "Book title")
@NotBlank String title,
@Schema(example = "9780132350884", description = "ISBN-13 without hyphens")
@NotBlank String isbn,
@Schema(example = "38.50", description = "Price in USD")
@Positive BigDecimal price
) {}
Validation annotations (@NotBlank, @Positive) also appear in the spec as required/constraint metadata.
Global API info
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI bookStoreOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("BookStore API")
.version("1.0.0")
.description("REST API for the BookStore learning project")
.contact(new Contact().name("BookStore Team")))
.servers(List.of(
new Server().url("http://127.0.0.1:8080").description("Local"),
new Server().url("https://api.bookstore.example.com").description("Production")
));
}
}
Customising paths
springdoc:
api-docs:
path: /api-docs
swagger-ui:
path: /docs
operations-sorter: method
tags-sorter: alpha
Swagger UI moves to /docs; the raw JSON spec to /api-docs.
Grouping APIs
For larger BookStore deployments with admin and public APIs:
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public")
.pathsToMatch("/api/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.pathsToMatch("/admin/**")
.build();
}
Each group gets its own spec at /v3/api-docs/{group}.
Exporting the spec in CI
# Start app, fetch spec, stop app
./mvnw spring-boot:run &
sleep 10
curl -o openapi.json http://127.0.0.1:8080/v3/api-docs
kill %1
Commit openapi.json or use it for contract testing with tools like Dredd or Schemathesis.
Quick recall
Everything you need if you only revisit this box.
springdoc-openapi-starter-webmvc-uiauto-generates OpenAPI 3 specs from controller annotations.- Swagger UI at
/swagger-ui.htmlprovides interactive API exploration. @Tag,@Operation,@ApiResponseenrich the generated documentation.@Schemaon DTO fields adds examples and descriptions to the spec.- Configure API info, servers, and grouping via
OpenAPIbean andGroupedOpenApi. - Disable or protect Swagger UI in production deployments.
Test yourself
Answer these before moving on — recall is what makes it stick.