API Documentation with OpenAPI and Swagger UI
A REST API without documentation is hard to use. springdoc-openapi reads your controllers and generates an OpenAPI specification and an interactive Swagger UI, with no manual writing.
Setup
<!-- springdoc 2.x is for Spring Boot 3.x. For Spring Boot 4 use the springdoc 3.x line. Check the compatibility table. -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.13</version>
</dependency>Swagger UI : http://localhost:8080/swagger-ui.html
OpenAPI (JSON) : http://localhost:8080/v3/api-docs
OpenAPI (YAML) : http://localhost:8080/v3/api-docs.yamlHow it works
Application startup
└─ springdoc scans: @RestController classes, @RequestMapping methods, parameter and return types, validation annotations
└─ builds the OpenAPI model ─► /v3/api-docs (JSON)
Browser opens swagger-ui.html ─► loads /v3/api-docs ─► draws forms; "Try it out" sends real requestsGlobal information and JWT security scheme
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info().title("Shop API").version("1.0").description("Products and orders"))
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
.components(new Components().addSecuritySchemes("bearerAuth",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
}
}Describe controllers and models
@RestController
@RequestMapping("/api/products")
@Tag(name = "Products", description = "Product management")
public class ProductController {
@Operation(summary = "Get a product by id", description = "Returns 404 if the product does not exist")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Found"),
@ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = ProblemDetail.class)))
})
@GetMapping("/{id}")
public ProductResponse get(@Parameter(description = "Product id", example = "42") @PathVariable Long id) {
return service.get(id);
}
@Operation(summary = "Create a product")
@PostMapping
public ResponseEntity<ProductResponse> create(@Valid @RequestBody ProductRequest request) { /* ... */ return null; }
}
@Schema(description = "Data to create a product")
public record ProductRequest(
@Schema(example = "Laptop", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String name,
@Schema(example = "55000.00") @Positive BigDecimal price) { }Configuration
springdoc.swagger-ui.path=/docs
springdoc.swagger-ui.operations-sorter=method
springdoc.paths-to-match=/api/**
springdoc.packages-to-scan=com.example.shop
# disable in production
springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=falseUse profiles to turn documentation off in production, or protect it with Spring Security. If you use Spring Security, permit these paths for the documentation: /swagger-ui/**, /swagger-ui.html and /v3/api-docs/**.
Groups and generating a client
@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/**").build();
}# generate a typed client from the specification (example with OpenAPI Generator)
npx @openapitools/openapi-generator-cli generate -i http://localhost:8080/v3/api-docs -g typescript-fetch -o ./clientCommon mistake: Exposing Swagger UI on production without authentication. It shows your whole API surface (including internal endpoints) to attackers. Disable it or protect it.
Interview questions
Swagger or OpenAPI?
OpenAPI is the specification (a JSON or YAML format). Swagger UI is the tool that shows it. springdoc generates the OpenAPI file, and Swagger UI displays it.
How do I hide an endpoint from the documentation?
Use @Hidden on the method or class, or restrict with paths-to-match.
Design first or code first?
Code first (springdoc) is fast for teams that own the API. Design first (write the YAML, generate interfaces) is better when many teams agree on a contract before coding.