api-design
RESTful API の設計を行います。エンドポイント定義、リクエスト/レスポンス仕様、エラーハンドリング、ScalarDBトランザクション例外のマッピングを含みます。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
RESTful API の設計を行います。エンドポイント定義、リクエスト/レスポンス仕様、エラーハンドリング、ScalarDBトランザクション例外のマッピングを含みます。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
ScalarDBを前提としたデータベース設計を行います。スキーマ設計、トランザクション設計、マルチストレージ構成を対話形式で決定し、スキーマファイルと設計書を生成します。
DDDに基づいたドメインモデルを設計します。戦略的設計(境界コンテキスト、ユビキタス言語)と戦術的設計(エンティティ、値オブジェクト、集約、ドメインサービス、ドメインイベント)を定義し、ヘキサゴナルアーキテクチャとの統合を行います。ScalarDBのトランザクション境界や管理テーブル分類の考慮事項を含みます。中間状態はresearch/に記録されます。
設計ドキュメントに基づいて実装計画を生成します。ScalarDB特有のスキーマ定義、トランザクション実装、統合テストを含む実装可能なタスク指示書を作成し、フェーズ別の実装ロードマップを提供します。
Kubernetes、Kong API Gateway、ScalarDB Cluster v3.17を使用したインフラストラクチャ設計を行います。マニフェストファイルと設定ファイルを生成します。
ScalarDBの制約を考慮したデータモデル設計を行います。Partition Key・Clustering Key・Secondary Index の設計、ホットスポット評価、メタデータオーバーヘッド見積もり、バックエンドDB選定を含みます。ワークフローStep 04(データモデル設計)で使用します。
ScalarDBのトランザクション設計を行います。トランザクション境界定義、パターン選定(単一集約内/2PC/Saga/ハイブリッド)、OCC競合率評価、バッチ処理設計、v3.17最適化適用計画を含みます。ワークフローStep 05(トランザクション設計)で使用します。
| name | api-design |
| description | RESTful API の設計を行います。エンドポイント定義、リクエスト/レスポンス仕様、エラーハンドリング、ScalarDBトランザクション例外のマッピングを含みます。 |
システムのRESTful APIを設計し、以下を定義します:
| ドキュメント | パス | 説明 |
|---|---|---|
| API設計手順 | workflow/06_api_interface_design.md | API設計の詳細ステップ |
| データアクセスパターン | research/08_transparent_data_access.md | ScalarDBの透過的データアクセス設計 |
| マイクロサービスアーキテクチャ | research/01_microservice_architecture.md | MSAパターンとサービス分割 |
| パラメータ | 必須 | 説明 | デフォルト |
|---|---|---|---|
| projectName | Yes | プロジェクト名 | - |
| apiVersion | No | APIバージョン | v1 |
| baseUrl | No | ベースURL | /api/v1 |
| authType | No | 認証方式 | Bearer |
| 原則 | 説明 | 例 |
|---|---|---|
| リソース指向 | 名詞でリソースを表現 | /users, /audit-sets |
| HTTPメソッド | 操作をメソッドで表現 | GET=取得, POST=作成 |
| ステートレス | セッション状態を持たない | トークン認証 |
| 統一インターフェース | 一貫したURL設計 | /resources/{id} |
| メソッド | 操作 | 成功コード | べき等性 |
|---|---|---|---|
| GET | 取得 | 200 | Yes |
| POST | 作成 | 201 | No |
| PUT | 全体更新 | 200 | Yes |
| PATCH | 部分更新 | 200 | No |
| DELETE | 削除 | 204 | Yes |
ScalarDBのトランザクション例外をHTTPステータスコードに適切にマッピングし、クライアントに対して適切なリトライ戦略を提供します。
| ScalarDB例外 | HTTPステータス | エラーコード | リトライ戦略 |
|---|---|---|---|
CrudConflictException | 409 Conflict | SCALARDB_001 | Exponential backoff でリトライ推奨 |
CommitConflictException | 409 Conflict | SCALARDB_002 | Exponential backoff でリトライ推奨 |
レスポンス例:
{
"error": {
"code": "SCALARDB_001",
"message": "データ競合が発生しました。リトライしてください",
"details": {
"exception": "CrudConflictException",
"retryable": true,
"retryStrategy": "exponential_backoff",
"recommendedWaitMs": 1000
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
| ScalarDB例外 | HTTPステータス | エラーコード | リトライ戦略 |
|---|---|---|---|
UnknownTransactionStatusException | 500 Internal Server Error | SCALARDB_003 | べき等性を確認してからリトライ |
レスポンス例:
{
"error": {
"code": "SCALARDB_003",
"message": "トランザクションの状態が不明です",
"details": {
"exception": "UnknownTransactionStatusException",
"retryable": true,
"retryStrategy": "idempotent_retry",
"guidance": "操作がべき等であることを確認してからリトライしてください",
"checkEndpoint": "/api/v1/transactions/{transactionId}/status"
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
| ScalarDB例外 | HTTPステータス | エラーコード | 説明 |
|---|---|---|---|
CommitException | 500 Internal Server Error | SCALARDB_004 | トランザクションのコミット失敗 |
UnsatisfiedConditionException | 422 Unprocessable Entity | SCALARDB_005 | 条件付き更新の条件不一致 |
UnsatisfiedConditionException のレスポンス例:
{
"error": {
"code": "SCALARDB_005",
"message": "更新条件が満たされていません",
"details": {
"exception": "UnsatisfiedConditionException",
"retryable": false,
"reason": "Expected version does not match current version",
"expectedCondition": {
"field": "version",
"expectedValue": 5,
"actualValue": 6
}
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
クライアント側のリトライ実装
サーバー側の実装
モニタリング
ScalarDB のChange Data Capture (CDC)機能で使用される内部メタデータカラムをAPIレスポンスから除外します。
| カラム名 | 説明 | フィルタリング理由 |
|---|---|---|
tx_state | トランザクション状態 | 内部管理用、クライアントに不要 |
tx_id | トランザクションID | 内部管理用、クライアントに不要 |
tx_prepared_at | トランザクション準備時刻 | 内部管理用、クライアントに不要 |
tx_committed_at | トランザクションコミット時刻 | 内部管理用、クライアントに不要 |
tx_version | トランザクションバージョン | 内部管理用、クライアントに不要 |
before_tx_id | CDC用の前トランザクションID | CDC内部用 |
before_state | CDC用の前状態 | CDC内部用 |
before_version | CDC用の前バージョン | CDC内部用 |
before_prepared_at | CDC用の前準備時刻 | CDC内部用 |
before_committed_at | CDC用の前コミット時刻 | CDC内部用 |
1. DTOレイヤーでのフィルタリング
@JsonIgnoreProperties(value = {
"tx_state", "tx_id", "tx_prepared_at", "tx_committed_at", "tx_version",
"before_tx_id", "before_state", "before_version",
"before_prepared_at", "before_committed_at"
})
public class UserResponse {
private String id;
private String email;
private String name;
// ビジネスフィールドのみ
}
2. マッパーでの明示的フィルタリング
public class UserMapper {
public UserResponse toResponse(Result result) {
return UserResponse.builder()
.id(result.getValue("id").get().getAsString())
.email(result.getValue("email").get().getAsString())
.name(result.getValue("name").get().getAsString())
// CDCメタデータは意図的に除外
.build();
}
}
3. 共通フィルタークラス
public class CdcMetadataFilter {
private static final Set<String> CDC_METADATA_COLUMNS = Set.of(
"tx_state", "tx_id", "tx_prepared_at", "tx_committed_at", "tx_version",
"before_tx_id", "before_state", "before_version",
"before_prepared_at", "before_committed_at"
);
public static Map<String, Object> filterCdcMetadata(Map<String, Object> data) {
return data.entrySet().stream()
.filter(entry -> !CDC_METADATA_COLUMNS.contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
}
フィルタリング前(NG):
{
"id": "user-001",
"email": "user@example.com",
"name": "山田太郎",
"tx_state": "COMMITTED",
"tx_id": "tx-12345",
"tx_version": 3,
"before_tx_id": "tx-12344"
}
フィルタリング後(OK):
{
"id": "user-001",
"email": "user@example.com",
"name": "山田太郎",
"createdAt": "2026-02-17T10:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}
ScalarDB 2PC(Two-Phase Commit)を利用したマイクロサービス間の分散トランザクション設計。
サービス間の分散トランザクションをオーケストレーターが調整。
[Order Service] (Orchestrator)
|
├─> [Inventory Service] (Participant)
├─> [Payment Service] (Participant)
└─> [Shipping Service] (Participant)
実装例:
// Order Service (Orchestrator)
public class OrderOrchestrator {
@POST
@Path("/orders")
public Response createOrder(OrderRequest request) {
TwoPhaseCommitTransaction tx = manager.start();
try {
// 1. 在庫予約(Participant 1)
inventoryClient.reserve(tx.getId(), request.getItems());
// 2. 支払い処理(Participant 2)
paymentClient.process(tx.getId(), request.getPayment());
// 3. 配送手配(Participant 3)
shippingClient.arrange(tx.getId(), request.getAddress());
// 4. 注文作成(Coordinator)
Order order = createOrderRecord(tx, request);
tx.prepare();
tx.commit();
return Response.status(201).entity(order).build();
} catch (CrudConflictException | CommitConflictException e) {
tx.rollback();
return Response.status(409).entity(new ConflictError(e)).build();
} catch (Exception e) {
tx.rollback();
return Response.status(500).entity(new ServerError(e)).build();
}
}
}
各サービスがローカルトランザクションを実行し、補償トランザクションで整合性を保つ。
Order Created → Reserve Inventory → Process Payment → Arrange Shipping
↓ ↓ ↓ ↓
Rollback ← Cancel Reservation ← Refund ← Cancel Shipping
ヘッダーでの伝播:
POST /api/v1/inventory/reserve
Authorization: Bearer {token}
X-Transaction-Id: tx-12345-67890
X-Request-Id: req-abc-def
Content-Type: application/json
{
"items": [
{"productId": "prod-001", "quantity": 2}
]
}
分散トランザクションでのリトライに備えてべき等性を実装。
@POST
@Path("/inventory/reserve")
@Idempotent
public Response reserveInventory(
@HeaderParam("X-Transaction-Id") String txId,
ReservationRequest request) {
// 既に処理済みかチェック
if (reservationRepository.exists(txId, request.getProductId())) {
return Response.status(200).build(); // べき等性
}
// 予約処理
reservation = reservationService.reserve(txId, request);
return Response.status(201).entity(reservation).build();
}
| 操作タイプ | タイムアウト | 理由 |
|---|---|---|
| Prepare | 30秒 | 各サービスの準備完了待ち |
| Commit | 60秒 | 全サービスのコミット完了待ち |
| Rollback | 30秒 | ロールバックは速やかに完了すべき |
| サービス間HTTP | 10秒 | ネットワーク遅延を考慮 |
Participant側のエラーレスポンス:
{
"error": {
"code": "INVENTORY_INSUFFICIENT",
"message": "在庫が不足しています",
"details": {
"productId": "prod-001",
"requested": 10,
"available": 5,
"transactionId": "tx-12345"
},
"retryable": false
}
}
Orchestrator側のエラーハンドリング:
try {
inventoryClient.reserve(txId, items);
} catch (InsufficientInventoryException e) {
// ビジネスエラー: リトライせずロールバック
tx.rollback();
return Response.status(422).entity(toErrorResponse(e)).build();
} catch (ServiceUnavailableException e) {
// 一時的エラー: リトライ可能
tx.rollback();
return Response.status(503).entity(toRetryableError(e)).build();
}
Circuit Breaker の実装
分散トレーシング
非同期処理の活用
部分的な失敗への対処
1.1 コントローラーの調査
- エンドポイント一覧
- リクエスト/レスポンス型
- 認証・認可設定
1.2 問題点の特定
- REST原則違反
- 命名規則の不一致
- バージョニングの欠如
- ScalarDB例外の不適切なマッピング
- CDCメタデータの漏洩
2.1 リソースの特定
- ドメインモデルからの抽出
- 集約ルートの特定
- サブリソースの定義
2.2 URL設計
- 階層構造の設計
- クエリパラメータの設計
- フィルタリング・ソート
3.1 CRUD操作
- 一覧取得 (GET /resources)
- 詳細取得 (GET /resources/{id})
- 作成 (POST /resources)
- 更新 (PUT/PATCH /resources/{id})
- 削除 (DELETE /resources/{id})
3.2 カスタムアクション
- アクション系 (POST /resources/{id}/actions)
- バッチ操作 (POST /resources/batch)
3.3 サービス間通信エンドポイント
- 2PC参加エンドポイント
- トランザクション状態確認
4.1 リクエスト設計
- パスパラメータ
- クエリパラメータ
- リクエストボディ
- ヘッダー(X-Transaction-Id等)
4.2 レスポンス設計
- 成功レスポンス
- エラーレスポンス(ScalarDB例外含む)
- ページネーション
- CDCメタデータのフィルタリング
5.1 HTTPステータスコード
- 2xx: 成功
- 4xx: クライアントエラー
- 5xx: サーバーエラー
5.2 ScalarDB例外のマッピング
- CrudConflictException → 409
- CommitConflictException → 409
- UnknownTransactionStatusException → 500
- CommitException → 500
- UnsatisfiedConditionException → 422
5.3 エラーレスポンス形式
- エラーコード体系
- リトライ戦略の提示
- 詳細情報
output/phase2/06_api_interface_design.md
# API設計書
## 概要
| 項目 | 値 |
|------|-----|
| APIバージョン | v1 |
| ベースURL | /api/v1 |
| 認証方式 | Bearer Token (JWT) |
| コンテンツタイプ | application/json |
## 設計原則
### URL設計規則
- リソース名は複数形(kebab-case)
- IDはUUID形式
- ネストは2階層まで
- クエリパラメータはcamelCase
### 認証・認可
- すべてのエンドポイントで認証必須(一部除く)
- JWT Bearer Token をAuthorizationヘッダーで送信
- ロールベースアクセス制御(RBAC)
### ScalarDB固有の設計
- トランザクション例外の適切なHTTPマッピング
- CDCメタデータのフィルタリング
- 分散トランザクションのためのトランザクションID伝播
## リソース一覧
| # | リソース | ベースパス | 説明 |
|---|---------|-----------|------|
| 1 | Users | /api/v1/users | ユーザー管理 |
| 2 | AuditSets | /api/v1/audit-sets | 監査セット |
| 3 | EventLogs | /api/v1/event-logs | イベントログ |
## 共通仕様
### リクエストヘッダー
| ヘッダー | 必須 | 説明 |
|---------|------|------|
| Authorization | Yes | Bearer {token} |
| Content-Type | Yes | application/json |
| Accept-Language | No | レスポンス言語 |
| X-Request-ID | No | リクエスト追跡ID |
| X-Transaction-Id | No* | 分散トランザクションID(2PC使用時必須) |
### ページネーション
```json
{
"data": [...],
"pagination": {
"page": 1,
"pageSize": 20,
"totalItems": 100,
"totalPages": 5
}
}
| パラメータ | 説明 | 例 |
|---|---|---|
| page | ページ番号 | ?page=1 |
| pageSize | 1ページの件数 | ?pageSize=20 |
| sort | ソート項目 | ?sort=createdAt:desc |
| filter | フィルタ条件 | ?filter[status]=active |
| エラーコード | ScalarDB例外 | HTTPステータス | リトライ |
|---|---|---|---|
| SCALARDB_001 | CrudConflictException | 409 | Yes (Exponential backoff) |
| SCALARDB_002 | CommitConflictException | 409 | Yes (Exponential backoff) |
| SCALARDB_003 | UnknownTransactionStatusException | 500 | Yes (べき等確認後) |
| SCALARDB_004 | CommitException | 500 | No |
| SCALARDB_005 | UnsatisfiedConditionException | 422 | No |
以下のカラムはAPIレスポンスから除外されます:
tx_state, tx_id, tx_prepared_at, tx_committed_at, tx_versionbefore_tx_id, before_state, before_version, before_prepared_at, before_committed_atトランザクションの準備フェーズ
トランザクションのコミット
トランザクションのロールバック
すべてのサービス間通信でX-Transaction-Idヘッダーを使用してトランザクションIDを伝播します。
説明: ユーザー一覧を取得
認可: ADMIN, MANAGER
クエリパラメータ:
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
| page | integer | No | ページ番号 (default: 1) |
| pageSize | integer | No | 件数 (default: 20, max: 100) |
| status | string | No | ステータスフィルタ |
レスポンス (200):
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "山田太郎",
"status": "active",
"createdAt": "2026-01-15T09:00:00Z"
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalItems": 45,
"totalPages": 3
}
}
注意: tx_stateなどのCDCメタデータは除外されています。
{
"error": {
"code": "SCALARDB_001",
"message": "データ競合が発生しました。リトライしてください",
"details": {
"exception": "CrudConflictException",
"retryable": true,
"retryStrategy": "exponential_backoff",
"recommendedWaitMs": 1000
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
{
"error": {
"code": "SCALARDB_005",
"message": "更新条件が満たされていません",
"details": {
"exception": "UnsatisfiedConditionException",
"retryable": false,
"expectedCondition": {
"field": "version",
"expectedValue": 5,
"actualValue": 6
}
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
{
"error": {
"code": "SCALARDB_003",
"message": "トランザクションの状態が不明です",
"details": {
"exception": "UnknownTransactionStatusException",
"retryable": true,
"retryStrategy": "idempotent_retry",
"guidance": "操作がべき等であることを確認してからリトライしてください",
"checkEndpoint": "/api/v1/transactions/{transactionId}/status"
},
"timestamp": "2026-02-17T10:00:00Z",
"traceId": "abc-123-def"
}
}
## API設計チェックリスト
### URL設計
- [ ] リソース名が複数形になっている
- [ ] URLにアクション動詞が含まれていない
- [ ] 一貫したケース規則(kebab-case)
- [ ] 適切な階層構造
### HTTPメソッド
- [ ] 適切なメソッドが使用されている
- [ ] べき等性が考慮されている
- [ ] 適切なステータスコードを返す
### リクエスト/レスポンス
- [ ] 一貫したJSON構造
- [ ] 適切なバリデーション
- [ ] ページネーションの実装
- [ ] 適切なエラーハンドリング
- [ ] CDCメタデータのフィルタリング
### ScalarDB固有
- [ ] トランザクション例外の適切なマッピング
- [ ] リトライ戦略の明示
- [ ] トランザクションIDの伝播(2PC使用時)
- [ ] べき等性の実装(分散トランザクション)
### セキュリティ
- [ ] 認証が必要なエンドポイントの保護
- [ ] 認可の実装
- [ ] 入力値のサニタイズ
## 使用例
Skill: api-design
プロジェクト名: scalar-auditor-for-box APIバージョン: v1 ベースURL: /api/v1 認証方式: Bearer (JWT)
## 注意事項
- 既存のAPIとの後方互換性を考慮する
- バージョニング戦略を事前に決定する
- APIドキュメントは常に最新に保つ
- セキュリティレビューを実施する
- ScalarDBのトランザクション例外を適切にHTTPステータスコードにマッピングする
- CDCメタデータは必ずAPIレスポンスから除外する
- 分散トランザクションではトランザクションIDを確実に伝播する
- べき等性を実装してリトライに対応する