spring-boot-rest-api-standards について
Spring Boot 開発者向けの REST API 設計スキルです。エンドポイント、DTO、入力検証、エラー処理、ページネーション、安全ヘッダーを扱い、実装や設計レビューに使えます。
主な機能
- 01リソース URL と HTTP メソッドの規約
- 02ステータスコードとエラーレスポンス設計
- 03DTO と Jakarta 検証
- 04ページネーション、フィルタリング、安全ヘッダー
活用シーン
- 01REST エンドポイントと API ルートの作成
- 02DTO と API 契約の設計
- 03グローバルなエラー処理と入力検証の実装
- 04REST API アーキテクチャのレビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill spring-boot-rest-api-standardsインストール後、Claude Code で/spring-boot-rest-api-standardsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/architecture-patterns.mdexamples.mdhttp-reference.mdpagination-and-filtering.mdreferences.mdsecurity-headers.mdspring-web-annotations.md詳細
Spring Boot REST API 標準
概要
Spring Boot を使用した REST API の設計標準です。URL 設計、HTTP メソッド、ステータスコード、DTO、バリデーション、エラー処理、ページネーション、セキュリティヘッダーを扱います。
使用する場面
- 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 のレコードまたは Lombok
@Data/@Valueを使用します - Jakarta のバリデーションアノテーションを適用します
- 可能な場合は DTO を不変にします
-
バリデーションを実装する
@RequestBodyパラメーターに@Validアノテーションを使用します- バリデーション制約(
@NotBlank、@Email、@Sizeなど)を適用します MethodArgumentNotValidExceptionでバリデーションエラーを処理します
-
エラー処理を設定する
- グローバルな例外処理に
@RestControllerAdviceを使用します - ステータス、エラー、メッセージ、タイムスタンプを含む標準化されたエラーレスポンスを返します
- 特定の HTTP ステータスコードには
ResponseStatusExceptionを使用します
- グローバルな例外処理に
-
ページネーションを設定する
- 大規模なデータセットには Pageable を使用します
- page、size、sort の各パラメーターを含めます
- 総要素数や総ページ数などのメタデータを返します
-
セキュリティヘッダーを追加する
- 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 のレコードまたは @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 のバリデーションアノテーションを使用します
- 機密データを公開しないでください - パスワード、トークン、PII をログに記録したり、公開したりしないでください
参考資料
- HTTP ステータスコード、Spring アノテーション、詳細な例など、包括的な参考資料については、
references/ディレクトリを参照してください - コードレビューのガイドラインについては、
developer-kit-java:spring-boot-code-review-expertエージェントを参照してください - 依存性注入のパターンについては、
spring-boot-dependency-injection/SKILL.mdを確認してください - REST API のテストについては、
../spring-boot-test-patterns/SKILL.mdを確認してください
コメント
Markdown 対応