mcpField
S
springdoc-openapi

springdoc-openapi

github.com/claude-dev-suite開発4656 回インストール2 日前に更新
リポジトリ

springdoc-openapi について

Spring Boot の Java プロジェクト向けに、springdoc-openapi を使った API ドキュメントと Swagger UI の生成・設定方法を案内するスキルです。エンドポイント、モデル、セキュリティ要件、API グループの記述を扱います。

主な機能

  1. 01API ドキュメントと Swagger UI の設定
  2. 02アノテーションによるエンドポイントとモデルの記述
  3. 03セキュリティとレスポンスの文書化
  4. 04タグやパスによる API のグループ化
  5. 05内部エンドポイントの非表示
  6. 06設定上の一般的な問題の調査

活用シーン

  1. 01Spring Boot API への OpenAPI ドキュメント追加
  2. 02DTO フィールドと列挙型の説明
  3. 03公開・内部エンドポイントの整理
  4. 04Swagger UI やスキーマの問題の診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill springdoc-openapi

インストール後、Claude Code で/springdoc-openapiを入力して読み込まれたか確認します。

詳細

Springdoc OpenAPI(Swagger)

詳細な知識:包括的なドキュメントを参照するには、technology に springdoc-openapi を指定して mcp__documentation__fetch_docs を使用してください。

Maven の設定

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

アプリケーションの設定

springdoc:
  api-docs:
    path: /v3/api-docs
    enabled: true
  swagger-ui:
    path: /swagger-ui.html
    enabled: true
    operationsSorter: method
    tagsSorter: alpha
    displayRequestDuration: true
    filter: true
  packages-to-scan: com.example.controller
  paths-to-match: /api/**

OpenAPI の設定

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("My API")
                .version("1.0.0")
                .description("REST API Documentation")
                .contact(new Contact()
                    .name("API Support")
                    .email("[email protected]"))
                .license(new License()
                    .name("MIT")
                    .url("https://opensource.org/licenses/MIT")))
            .externalDocs(new ExternalDocumentation()
                .description("Wiki Documentation")
                .url("https://wiki.example.com"))
            .addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
            .components(new Components()
                .addSecuritySchemes("bearerAuth",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")
                        .description("JWT token authentication")));
    }
}

コントローラーのドキュメント

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

    private final UserService userService;

    @Operation(
        summary = "Get all users",
        description = "Returns a paginated list of all users"
    )
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "Success",
            content = @Content(schema = @Schema(implementation = PageUserResponse.class))),
        @ApiResponse(responseCode = "401", description = "Unauthorized",
            content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping
    public ResponseEntity<Page<UserResponse>> findAll(
            @Parameter(description = "Page number (0-indexed)")
            @RequestParam(defaultValue = "0") int page,
            @Parameter(description = "Page size")
            @RequestParam(defaultValue = "10") int size) {
        return ResponseEntity.ok(userService.findAll(page, size));
    }

    @Operation(summary = "Get user by ID")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "User found"),
        @ApiResponse(responseCode = "404", description = "User not found")
    })
    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> findById(
            @Parameter(description = "User ID", required = true, example = "1")
            @PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    @Operation(summary = "Create new user")
    @ApiResponses({
        @ApiResponse(responseCode = "201", description = "User created"),
        @ApiResponse(responseCode = "400", description = "Invalid input")
    })
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ResponseEntity<UserResponse> create(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                description = "User creation data",
                required = true,
                content = @Content(schema = @Schema(implementation = CreateUserRequest.class)))
            @Valid @RequestBody CreateUserRequest dto) {
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.create(dto));
    }
}

スキーマのドキュメント

@Data
@Schema(description = "User creation request")
public class CreateUserRequest {

    @Schema(
        description = "User's full name",
        example = "John Doe",
        minLength = 2,
        maxLength = 100,
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotBlank
    @Size(min = 2, max = 100)
    private String name;

    @Schema(
        description = "User's email address",
        example = "[email protected]",
        format = "email",
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotBlank
    @Email
    private String email;

    @Schema(
        description = "User's password",
        example = "SecurePass123!",
        minLength = 8,
        requiredMode = Schema.RequiredMode.REQUIRED,
        accessMode = Schema.AccessMode.WRITE_ONLY
    )
    @NotBlank
    @Size(min = 8)
    private String password;

    @Schema(
        description = "User's role",
        example = "USER",
        defaultValue = "USER",
        allowableValues = {"ADMIN", "MANAGER", "USER"}
    )
    private UserRole role;
}

@Data
@Builder
@Schema(description = "User response")
public class UserResponse {

    @Schema(description = "User ID", example = "1")
    private Long id;

    @Schema(description = "User's name", example = "John Doe")
    private String name;

    @Schema(description = "User's email", example = "[email protected]")
    private String email;

    @Schema(description = "User's role", example = "USER")
    private UserRole role;

    @Schema(description = "Account status", example = "ACTIVE")
    private UserStatus status;

    @Schema(description = "Creation timestamp", example = "2024-01-15T10:30:00")
    private LocalDateTime createdAt;
}

Enum のドキュメント

@Schema(description = "User roles")
public enum UserRole {
    @Schema(description = "System administrator with full access")
    ADMIN,

    @Schema(description = "Department manager")
    MANAGER,

    @Schema(description = "Regular user")
    USER
}

セキュリティのドキュメント

// Mark endpoint as public (no auth required)
@Operation(summary = "Login", security = {})
@PostMapping("/auth/login")
public ResponseEntity<AuthResponse> login(@RequestBody LoginRequest request) {
    return ResponseEntity.ok(authService.login(request));
}

// Require specific roles in documentation
@Operation(
    summary = "Delete user",
    security = @SecurityRequirement(name = "bearerAuth")
)
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}

API をタグでグループ化する

@Configuration
public class OpenApiConfig {

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
            .group("public")
            .pathsToMatch("/api/v1/public/**")
            .build();
    }

    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
            .group("admin")
            .pathsToMatch("/api/v1/admin/**")
            .build();
    }
}

エンドポイントを非表示にする

@Hidden  // Hide entire controller
@RestController
public class InternalController { }

// Hide specific endpoint
@Operation(hidden = true)
@GetMapping("/internal")
public void internal() { }

主なアノテーション

アノテーション目的
@Tagエンドポイントをグループ化する
@Operationエンドポイントを説明する
@Parameterパス/クエリパラメーターをドキュメント化する
@Schemaモデル/フィールドをドキュメント化する
@ApiResponseレスポンスをドキュメント化する
@Hiddenドキュメントから非表示にする
@SecurityRequirementセキュリティスキーム

このスキルを使用しない場合

  • 一般的な OpenAPI 仕様の作成(openapi スキルを使用)
  • GraphQL API のドキュメント作成(graphql スキルを使用)
  • Spring Boot 以外の Java プロジェクト
  • フロントエンド向け OpenAPI クライアントの生成(openapi-codegen スキルを使用)
  • Node.js/TypeScript API(openapi またはフレームワーク固有のスキルを使用)

アンチパターン

アンチパターン問題点解決策
エンドポイントに @Operation がないドキュメントの質が低く、説明もないすべてのエンドポイントに @Operation を追加する
@Schema に例がないAPI の理解が難しいすべてのスキーマに例の値を追加する
@Schema を付けずに DTO を公開するフィールドの説明が不足するすべての DTO フィールドを @Schema でドキュメント化する
内部エンドポイントを非表示にしない実装の詳細が公開される内部エンドポイントには @Hidden を使用する
セキュリティ要件がない認証要件が不明確になる必要な箇所に @SecurityRequirement を追加する
エラーレスポンスのドキュメントがないAPI コントラクトが不完全になるすべての 4xx/5xx レスポンスをドキュメント化する
エンティティクラスを API モデルとして使用するデータベース構造が漏えいする専用の DTO クラスを作成する
API 情報をコードにハードコードする設定が外部化されないAPI メタデータには application.yml を使用する
@Parameter の説明がないAPI の使いやすさが損なわれるすべてのパス/クエリパラメーターをドキュメント化する

すぐに試せるトラブルシューティング

問題考えられる原因解決策
Swagger UI が読み込まれないspringdoc の設定が正しくないapplication.yml の springdoc.swagger-ui.path を確認する
エンドポイントが表示されないコントローラーがスキャン対象パスにないspringdoc.packages-to-scan を確認する
スキーマにフィールドがないフィールドが private で、getter がないgetter を追加するか、フィールドに @Schema を使用する
UI でセキュリティが機能しないセキュリティスキームが設定されていない設定に @SecurityScheme を追加する
UI のベースパスが誤っているサーバー URL が設定されていないOpenAPI の設定で servers を設定する
生成されたスキーマに型エラーがあるDTO フィールドの型がサポートされていない@Schema を使用して形式を指定する
循環参照エラーが発生するDTO が自己参照している@Schema(ref = "#/components/schemas/X") を使用する
enum の値が不足しているenum がドキュメント化されていないenum フィールドに @Schema を追加する
/v3/api-docs で 404 が発生するspringdoc が有効になっていないspringdoc の依存関係を追加し、api-docs.enabled を確認する

参考ドキュメント

コメント