Managing FastAPI Projects with Poetry: A Step-by-Step Guide

This guide provides a detailed walkthrough for integrating Swagger UI (with OpenAPI 3.0) into your Spring Boot project. It covers everything from initial dependency setup to handling authentication and following best practices to effectively automate and manage your API documentation.
First, add the necessary springdoc-openapi
dependencies to your pom.xml
file.
springdoc-openapi-starter-webmvc-ui
: This is the core library that automatically generates the OpenAPI 3.0 specification by analyzing your Spring Boot application. It also provides the embedded Swagger UI.springdoc-openapi-maven-plugin
: (Optional) This plugin extracts the API documentation into a static file (e.g., openapi.json
) during the Maven build process. It's useful for CI/CD pipelines, sharing API specs with other teams, or generating client-side code.<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version> </dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>generate-openapi-spec</id>
<phase>integration-test</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl>
<outputFileName>openapi.json</outputFileName>
<outputDir>${project.build.directory}</outputDir>
</configuration>
</plugin>
</plugins>
</build>
To properly document and test your APIs, especially those requiring authentication, you need to configure Swagger. If you use JWT (JSON Web Token) based authentication, it's crucial to add a UI component that allows users to input their authentication token.
Create a SwaggerConfig
class to manage global OpenAPI settings.
// SwaggerConfig.java
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 org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
// Define API metadata
Info info = new Info()
.title("User Service API")
.description("API documentation for the User Service features.")
.version("v1.0.0");
// Define the security scheme (JWT Bearer Token)
// "bearerAuth" is an arbitrary name,
// but it must be used in the SecurityRequirement.
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
.in(SecurityScheme.In.HEADER).name("Authorization");
// Define the security requirement
// This applies authentication globally to all APIs.
SecurityRequirement securityRequirement = new SecurityRequirement()
.addList("bearerAuth");
return new OpenAPI()
.components(new Components()
.addSecuritySchemes("bearerAuth", securityScheme))
.addSecurityItem(securityRequirement)
.info(info);
}
}
Info
: Defines the metadata for your API documentation, such as the title, description, and version.SecurityScheme
: Defines the authentication method. Here, we've configured the Bearer Token
method, which uses the Authorization
header.SecurityRequirement
: Defines the security requirements for your APIs. By using .addSecurityItem()
, we apply this authentication setting globally to all endpoints.@Configuration
: Marks this class as a Spring configuration file.This setup adds an "Authorize" button to the top-right corner of the Swagger UI. Clicking it will open a dialog where you can enter a JWT (including the Bearer
prefix), allowing you to test secured endpoints successfully.
application.yml
You can fine-tune the behavior of Swagger UI in your application.yml
file.
# application.yml
springdoc:
swagger-ui:
# The path for the Swagger UI page
path: /swagger-ui.html
# The sorting order for API endpoints (method: by HTTP method, alpha: alphabetically)
operations-sorter: method
# The sorting order for tags (controllers)
tags-sorter: alpha
# Disable the default API docs URL
disable-swagger-default-url: true
api-docs:
# The path for the API documentation (JSON)
path: /v3/api-docs
If you are using Spring Security, you must permit access to the Swagger UI-related paths. Otherwise, you will encounter a 403 Forbidden error and be unable to access the UI.
// SpringSecurityConfig.java
@Configuration
@EnableMethodSecurity // In Spring Security 6.1+, this is included in @EnableWebSecurity
@AllArgsConstructor
public class SpringSecurityConfig {
private final FirebaseAuthenticationFilter firebaseAuthenticationFilter;
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity)
throws Exception {
httpSecurity
.csrf(csrf -> csrf.disable()) // Disable CSRF protection
.sessionManagement(session ->
// Use stateless sessions
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
// Permit access to Swagger UI
.requestMatchers(
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**"
).permitAll()
// Permit specific paths like signup/login without authentication
.requestMatchers(
"/api/v1/auth/**"
).permitAll()
// Require authentication for all other requests
.anyRequest().authenticated()
);
// Add our custom Firebase auth filter before
// the standard UsernamePasswordAuthenticationFilter
httpSecurity.addFilterBefore(firebaseAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
}
Use annotations in your controllers and DTOs to make your API documentation more detailed and clear.
@Tag
: Defines a name and description for a controller group (a collection of APIs).@Operation
: Adds a summary and a detailed description for each API endpoint.@ApiResponses
, @ApiResponse
: Specifies the possible response codes (e.g., 200, 404, 500) and their meanings.@Parameter
: Defines the description, required status, and example for a request parameter.@Schema
: Used to add descriptions or example values for DTOs (Data Transfer Objects) or model objects.// UserController.java
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
@Tag(name = "User", description = "User management APIs")
@RestController
@RequestMapping("/api/v1/users")
@AllArgsConstructor
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
private final UserService userService;
@Operation(summary = "User Signup", description = "Creates a new user and registers them in the system.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Signup successful", content = @Content(schema = @Schema(implementation = UserDto.class))),
@ApiResponse(responseCode = "400", description = "Invalid request format."),
@ApiResponse(responseCode = "409", description = "User already exists (email conflict).")
})
@PostMapping
public ResponseEntity<UserDto> createUser(
@Parameter(description = "User information required for signup", required = true, schema = @Schema(implementation = UserDto.class))
@RequestBody UserDto userDto
) {
log.info("Received signup request: {}", userDto);
try {
UserDto created = userService.addUser(userDto);
log.info("Signup successful: {}", created);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
} catch (Exception e) {
log.error("Error during signup: {}", e.getMessage(), e);
throw e;
}
}
}
After running your application, you can access the generated API documentation and UI at the following URLs:
http://localhost:8080/swagger-ui.html
http://localhost:8080/v3/api-docs
@Operation
, use summary
for a concise description of what the API does and description
for additional details or constraints.@SecurityRequirement(name = "bearerAuth")
to its method.@Schema(description = "User's name", example = "John Doe")
to fields in your DTO classes. This greatly improves readability by showing example values in the API documentation.@ApiResponses
to specify not only success cases (2xx) but also all expected failure cases (4xx, 5xx) and their causes..version()
information in your SwaggerConfig
to maintain a history of changes.@Profile("!prod")
) to prevent Swagger-related beans from being created in production.
Comments
Post a Comment