0

[Java Backend Zero to Hello] [Phase 6] BÀI 6.2: API DOCUMENTATION (OPENAPI/SWAGGER)

📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 6: REST API & Best Practices 📖 Nội dung: BÀI 6.2: API DOCUMENTATION (OPENAPI/SWAGGER) 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.


BÀI 6.2: API DOCUMENTATION (OPENAPI/SWAGGER)

Mục tiêu

  • Sử dụng SpringDoc OpenAPI
  • Tạo API documentation tự động
  • Tùy chỉnh Swagger UI
  • Mô tả API chi tiết

1. OPENAPI LÀ GÌ?

OpenAPI (trước đây là Swagger) là chuẩn mô tả API, cho phép:

  • Tự động generate documentation
  • Test API trực tiếp trên browser
  • Generate client code
  • Validate request/response

2. DEPENDENCY

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.3.0</version>
</dependency>

Truy cập:

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

3. CẤU HÌNH CƠ BẢN

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("My API")
                .version("1.0.0")
                .description("API documentation for MyApp")
                .contact(new Contact()
                    .name("Support")
                    .email("support@example.com"))
                .license(new License()
                    .name("MIT")
                    .url("https://opensource.org/licenses/MIT")))
            .servers(List.of(
                new Server().url("http://localhost:8080").description("Local"),
                new Server().url("https://api.example.com").description("Production")
            ));
    }
}

4. ANNOTATION TRÊN CONTROLLER

@RestController
@RequestMapping("/api/users")
@Tag(name = "User", description = "User management APIs")
public class UserController {

    @Operation(
        summary = "Get all users",
        description = "Returns a list of all users with pagination"
    )
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "Success"),
        @ApiResponse(responseCode = "401", description = "Unauthorized")
    })
    @GetMapping
    public Page<UserResponse> getAll(
        @Parameter(description = "Page number", example = "0")
        @RequestParam(defaultValue = "0") int page,

        @Parameter(description = "Page size", example = "10")
        @RequestParam(defaultValue = "10") int size
    ) {
        return userService.findAll(page, size);
    }

    @Operation(summary = "Get user by ID")
    @GetMapping("/{id}")
    public UserResponse getById(
        @Parameter(description = "User ID", required = true)
        @PathVariable Long id
    ) {
        return userService.findById(id);
    }

    @Operation(summary = "Create new user")
    @PostMapping
    public ResponseEntity<UserResponse> create(
        @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "User to create",
            required = true,
            content = @Content(schema = @Schema(implementation = CreateUserRequest.class))
        )
        @RequestBody @Valid CreateUserRequest request
    ) {
        UserResponse created = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

5. ANNOTATION TRÊN DTO

@Schema(description = "User creation request")
public record CreateUserRequest(

    @Schema(description = "User name", example = "An", requiredMode = RequiredMode.REQUIRED)
    @NotBlank String name,

    @Schema(description = "Email address", example = "an@example.com")
    @Email String email,

    @Schema(description = "Age", example = "25", minimum = "0", maximum = "150")
    @Min(0) @Max(150) Integer age
) {}

6. JWT AUTHENTICATION TRONG SWAGGER

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        final String securitySchemeName = "bearerAuth";

        return new OpenAPI()
            .info(new Info().title("My API").version("1.0"))
            .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
            .components(new Components()
                .addSecuritySchemes(securitySchemeName,
                    new SecurityScheme()
                        .name(securitySchemeName)
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")));
    }
}

7. NHÓM API VỚI @TAG

@Tag(name = "Authentication", description = "Login, register APIs")
@RestController
@RequestMapping("/api/auth")
public class AuthController { ... }

@Tag(name = "User", description = "User management APIs")
@RestController
@RequestMapping("/api/users")
public class UserController { ... }

8. CẤU HÌNH SWAGGER UI

springdoc:
  swagger-ui:
    path: /swagger-ui.html
    operations-sorter: alpha
    tags-sorter: alpha
    display-request-duration: true
    filter: true
  api-docs:
    path: /v3/api-docs
  show-actuator: false
  packages-to-scan: com.example.controller

9. BẢO MẬT SWAGGER UI

@Configuration
public class SwaggerSecurityConfig {

    @Bean
    public SecurityFilterChain swaggerSecurity(HttpSecurity http) throws Exception {
        http.securityMatcher("/swagger-ui/**", "/v3/api-docs/**")
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/v3/api-docs/**").permitAll()
                .requestMatchers("/swagger-ui/**").hasRole("ADMIN")
            )
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

10. CUSTOM ENDPOINT

@Hidden  // Ẩn khỏi Swagger
@GetMapping("/internal")
public String internal() { ... }

11. VÍ DỤ HOÀN CHỈNH

@RestController
@RequestMapping("/api/v1/products")
@Tag(name = "Product", description = "Product management APIs")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    @GetMapping
    @Operation(summary = "List all products")
    public Page<ProductResponse> list(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String category) {
        return productService.findAll(page, size, category);
    }

    @GetMapping("/{id}")
    @Operation(summary = "Get product by ID")
    public ProductResponse getById(@PathVariable Long id) {
        return productService.findById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    @Operation(summary = "Create new product")
    public ProductResponse create(@RequestBody @Valid CreateProductRequest request) {
        return productService.create(request);
    }

    @PutMapping("/{id}")
    @Operation(summary = "Update product")
    public ProductResponse update(@PathVariable Long id,
                                   @RequestBody @Valid UpdateProductRequest request) {
        return productService.update(id, request);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @Operation(summary = "Delete product")
    public void delete(@PathVariable Long id) {
        productService.delete(id);
    }
}

12. BÀI TẬP THỰC HÀNH

Bài 1: Document User API

Thêm Swagger annotations cho UserController.

Bài 2: JWT Security

Cấu hình JWT authentication trong Swagger UI.

Bài 3: Custom Info

Tùy chỉnh thông tin API (title, version, contact).


13. TÓM TẮT

Annotation Mô tả
@Tag Nhóm API
@Operation Mô tả endpoint
@ApiResponse Mô tả response
@Parameter Mô tả parameter
@Schema Mô tả schema
@Hidden Ẩn endpoint
springdoc.swagger-ui.path Đường dẫn UI

Bài tiếp theo: 6.3 DTO & Mapper


🧭 Điều hướng bài học

⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí