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

Image
This guide will walk you through how to use Poetry to manage dependencies and structure your project in FastAPI . It includes detailed explanations of Poetry's core concepts and commands to help prevent issues that can arise during team collaboration and deployment. 1. What is Poetry? Poetry is a dependency management and packaging tool for Python. It goes beyond simply installing libraries by allowing you to clearly declare the dependencies your project needs and ensuring that all developers on the project have the same library versions. Clarity in Dependency Management : Explicitly manage your project's basic information and required libraries through the pyproject.toml file. Reproducible Builds : By locking all dependency versions in the poetry.lock file, it fundamentally prevents "it works on my machine" problems. Integrated Development Environment : It automatically creates and manages isolated virtual environments for each project and handles mo...

A Comprehensive Guide to Spring Boot & Swagger (OpenAPI) Integration

swagger-openapi

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.

1. Adding Dependencies

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>

2. Basic Swagger & JWT Authentication Configuration

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);
    }
}

Configuration Explained:

  • 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.

3. Configuring 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

4. Spring Security Configuration

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();
    }
}

5. Documenting APIs with Annotations

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;
        }
    }
}

6. Accessing the Swagger UI & API Docs

After running your application, you can access the generated API documentation and UI at the following URLs:

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

7. Best Practices for API Documentation

  1. Add Clear Descriptions for All APIs: In @Operation, use summary for a concise description of what the API does and description for additional details or constraints.
  2. Explicitly Mark Secured APIs: Besides the global setting, you can require authentication for a specific API by adding @SecurityRequirement(name = "bearerAuth") to its method.
  3. Include Request/Response Examples: Add annotations like @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.
  4. Document All Possible Error Responses: Use @ApiResponses to specify not only success cases (2xx) but also all expected failure cases (4xx, 5xx) and their causes.
  5. Manage API Versions: When the API specification changes, update the .version() information in your SwaggerConfig to maintain a history of changes.

8. Security Considerations

  1. Restrict Access in Production: For security reasons, you must disable the Swagger UI page or restrict access to it in your production environment. This can be done by limiting access to specific IP addresses or users with a certain role (e.g., ADMIN). You can also use Spring Profiles (@Profile("!prod")) to prevent Swagger-related beans from being created in production.
  2. Manage Authentication Information: Be careful not to expose authentication tokens used for API testing.
  3. Minimize Information Exposure: Design your DTOs carefully to avoid including sensitive information (personal data, internal system paths, etc.) in API responses.

Comments

Popular posts from this blog

Resolving Key Exchange Failure When Connecting with SecureCRT to OpenSSH

SecureCRT] How to Back Up and Restore SecureCRT Settings on Windows

How to Set Up Vaultwarden (Bitwarden) on Synology NAS (Best Free Alternative to LastPass)