spring-boot-rest-api-standards
Spring BootプロジェクトにおけるREST APIの設計標準とベストプラクティスを提供します。RESTエンドポイント、DTO、エラーハンドリング、ページネーション、セキュリティヘッダー、HATEOAS、アーキテクチャパターンの作成またはレビューを行う際に使用してください。
description の原文を見る
Provides REST API design standards and best practices for Spring Boot projects. Use when creating or reviewing REST endpoints, DTOs, error handling, pagination, security headers, HATEOAS and architecture patterns.
SKILL.md 本文
Spring Boot REST API 標準
概要
URL設計、HTTPメソッド、ステータスコード、DTO、検証、エラーハンドリング、ページネーション、セキュリティヘッダーをカバーする Spring Boot 用の REST API 設計標準です。
使用するとき
- REST エンドポイントと API ルートの作成
- DTO と API コントラクトの設計
- エラーハンドリングと検証の実装
- ページネーションとフィルタリングのセットアップ
- セキュリティヘッダーと CORS の設定
- REST API アーキテクチャのレビュー
説明
RESTful API エンドポイントの構築方法
よく設計された REST API エンドポイントを作成するには、以下の手順に従ってください:
-
リソースベースの URL の設計
- リソース名に複数形の名詞を使用
- REST 規約に従う: GET /users、POST /users、PUT /users/{id}
- /getUserList のようなアクションベースの URL は避ける
-
適切な HTTP メソッドの実装
- GET: リソースの取得(安全、べき等)
- POST: リソースの作成(べき等ではない)
- PUT: リソース全体の置換(べき等)
- PATCH: 部分的な更新(べき等ではない)
- DELETE: リソースの削除(べき等)
-
適切なステータスコードの使用
- 200 OK: 成功した GET/PUT/PATCH
- 201 Created: Location ヘッダ付きの成功した POST
- 204 No Content: 成功した DELETE
- 400 Bad Request: 無効なリクエストデータ
- 404 Not Found: リソースが存在しない
- 409 Conflict: リソースの重複
- 500 Internal Server Error: 予期しないエラー
-
リクエスト/レスポンス DTO の作成
- API コントラクトをドメインエンティティから分離
- Java records または Lombok の
@Data/@Valueを使用 - Jakarta 検証アノテーションを適用
- 可能な限り DTO をイミュータブルに保つ
-
検証の実装
@RequestBodyパラメータに@Validアノテーションを使用- 検証制約を適用(
@NotBlank、@Email、@Sizeなど) MethodArgumentNotValidExceptionで検証エラーを処理
-
エラーハンドリングのセットアップ
- グローバル例外ハンドリングに
@RestControllerAdviceを使用 - ステータス、エラー、メッセージ、タイムスタンプを含む標準化されたエラーレスポンスを返す
- 特定の HTTP ステータスコードに
ResponseStatusExceptionを使用
- グローバル例外ハンドリングに
-
ページネーションの設定
- 大規模なデータセットに Pageable を使用
- page、size、sort パラメータを含める
- 合計要素数、totalPages などのメタデータを返す
-
セキュリティヘッダーの追加
- CORS ポリシーの設定
- コンテンツセキュリティポリシーの設定
- X-Frame-Options、X-Content-Type-Options を含める
検証チェックポイント:
- ステップ 1-2 後: URL 構造が REST 規約に従っていることを確認(/getUsers ではなく /users)
- ステップ 3 後: 各エンドポイントが正しいステータスコードを返すことをテスト
- ステップ 4-5 後: curl または HTTPie で DTO を検証してから先に進む
- ステップ 6 後: エラーレスポンスが標準化されたフォーマットと一致することを確認
例
基本的な CRUD コントローラ
@RestController
@RequestMapping("/v1/users")
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<Page<UserResponse>> getAllUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int pageSize) {
log.debug("Fetching users page {} size {}", page, pageSize);
Page<UserResponse> users = userService.getAll(page, pageSize);
return ResponseEntity.ok(users);
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getUserById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getById(id));
}
@PostMapping
public ResponseEntity<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
UserResponse created = userService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@PutMapping("/{id}")
public ResponseEntity<UserResponse> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
return ResponseEntity.ok(userService.update(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
リクエスト/レスポンス DTO
// Request DTO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateUserRequest {
@NotBlank(message = "User name cannot be blank")
private String name;
@Email(message = "Valid email required")
private String email;
}
// Response DTO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserResponse {
private Long id;
private String name;
private String email;
private LocalDateTime createdAt;
}
グローバル例外ハンドラ
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
MethodArgumentNotValidException ex, WebRequest request) {
String errors = ex.getBindingResult().getFieldErrors().stream()
.map(f -> f.getField() + ": " + f.getDefaultMessage())
.collect(Collectors.joining(", "));
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
"Validation Error",
"Validation failed: " + errors,
request.getDescription(false).replaceFirst("uri=", "")
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ResponseStatusException.class)
public ResponseEntity<ErrorResponse> handleResponseStatusException(
ResponseStatusException ex, WebRequest request) {
ErrorResponse error = new ErrorResponse(
ex.getStatusCode().value(),
ex.getStatusCode().toString(),
ex.getReason(),
request.getDescription(false).replaceFirst("uri=", "")
);
return new ResponseEntity<>(error, ex.getStatusCode());
}
}
ベストプラクティス
1. コンストラクタインジェクションを使用
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
}
2. イミュータブル DTO を優先(Java Records または @Value)
public record UserResponse(Long id, String name, String email) {}
3. 適切なトランザクション管理の実装
@Service
@Transactional
public class UserService {
@Transactional(readOnly = true)
public Optional<User> findById(Long id) { return userRepository.findById(id); }
@Transactional
public User create(User user) { return userRepository.save(user); }
}
制約と警告
- エンティティを直接公開しない - DTO を使用して API コントラクトをドメインモデルから分離
- REST 規約に従う - リソースに名詞を使用(/users)、正しい HTTP メソッド、複数形の名前、適切なステータスコード
- すべての例外をグローバルに処理 -
@RestControllerAdviceを使用し、生の例外がバブルアップしないようにする - 大規模な結果セットは常にページネーション - パフォーマンスの問題と DDoS 脆弱性を防止
- すべての入力データを検証 - リクエスト DTO に Jakarta 検証アノテーションを使用
- 機密データを公開しない - パスワード、トークン、個人識別情報をログに出力したり公開したりしない
参考資料
references/ディレクトリで HTTP ステータスコード、Spring アノテーション、詳細な例を含む包括的な参考資料を参照- コードレビューガイドラインについては
developer-kit-java:spring-boot-code-review-expertエージェントを参照 - 依存性注入パターンについては
spring-boot-dependency-injection/SKILL.mdを確認 - REST API のテストについては
../spring-boot-test-patterns/SKILL.mdをチェック
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。