ストーリー
高橋アーキテクトが要件書を渡した。
ミッション概要
タスク管理アプリ「TaskFlow」のREST APIを設計します。
| ミッション | テーマ | 難易度 |
|---|---|---|
| Mission 1 | リソース設計 | 初級 |
| Mission 2 | エンドポイント一覧の作成 | 初級 |
| Mission 3 | リクエスト・レスポンス設計 | 中級 |
| Mission 4 | エラーレスポンス設計 | 中級 |
| Mission 5 | 認証・認可の設計 | 上級 |
| Mission 6 | ページネーション・フィルタ設計 | 上級 |
Mission 1: リソース設計(10分)
以下の要件を読み、APIのリソースを洗い出してください。
要件
- ユーザーはアカウントを作成してログインできる
- ユーザーはプロジェクトを作成できる
- プロジェクトにはタスクを追加できる
- タスクにはラベル(複数)を付けられる
- タスクにはコメントを投稿できる
- ユーザーをプロジェクトのメンバーとして招待できる
期待する成果
リソース一覧と、それぞれの関係(親子関係)をリストアップしてください。
解答
// リソース一覧
// 1. Users(ユーザー)
// 2. Projects(プロジェクト)
// 3. Tasks(タスク)-- Projects のサブリソース
// 4. Labels(ラベル)-- Projects のサブリソース
// 5. Comments(コメント)-- Tasks のサブリソース
// 6. Members(メンバー)-- Projects のサブリソース
// リソースの関係
// Users ──┬── Projects(ユーザーはプロジェクトを作成)
// │ ├── Tasks(プロジェクトにタスク)
// │ │ └── Comments(タスクにコメント)
// │ ├── Labels(プロジェクトにラベル)
// │ └── Members(プロジェクトにメンバー)
// └── (ユーザー自身のプロフィール情報)
Mission 2: エンドポイント一覧の作成(15分)
Mission 1で洗い出したリソースに対して、CRUDのエンドポイントを設計してください。
要件
- すべてのリソースに対してCRUD操作を定義
- URLのパスは
api/v1で始める - RESTの規約に従う(複数形、名詞、HTTPメソッド)
解答
// === ユーザー ===
POST /api/v1/users // ユーザー登録
GET /api/v1/users/me // 自分の情報取得
PATCH /api/v1/users/me // 自分の情報更新
// === 認証 ===
POST /api/v1/auth/login // ログイン
POST /api/v1/auth/logout // ログアウト
POST /api/v1/auth/refresh // トークンリフレッシュ
// === プロジェクト ===
GET /api/v1/projects // プロジェクト一覧
POST /api/v1/projects // プロジェクト作成
GET /api/v1/projects/:projectId // プロジェクト詳細
PATCH /api/v1/projects/:projectId // プロジェクト更新
DELETE /api/v1/projects/:projectId // プロジェクト削除
// === メンバー(プロジェクトのサブリソース)===
GET /api/v1/projects/:projectId/members // メンバー一覧
POST /api/v1/projects/:projectId/members // メンバー招待
DELETE /api/v1/projects/:projectId/members/:userId // メンバー削除
// === タスク(プロジェクトのサブリソース)===
GET /api/v1/projects/:projectId/tasks // タスク一覧
POST /api/v1/projects/:projectId/tasks // タスク作成
GET /api/v1/tasks/:taskId // タスク詳細
PATCH /api/v1/tasks/:taskId // タスク更新
DELETE /api/v1/tasks/:taskId // タスク削除
// === ラベル(プロジェクトのサブリソース)===
GET /api/v1/projects/:projectId/labels // ラベル一覧
POST /api/v1/projects/:projectId/labels // ラベル作成
PATCH /api/v1/labels/:labelId // ラベル更新
DELETE /api/v1/labels/:labelId // ラベル削除
// === コメント(タスクのサブリソース)===
GET /api/v1/tasks/:taskId/comments // コメント一覧
POST /api/v1/tasks/:taskId/comments // コメント投稿
PATCH /api/v1/comments/:commentId // コメント編集
DELETE /api/v1/comments/:commentId // コメント削除
Mission 3: リクエスト・レスポンス設計(20分)
主要なエンドポイントのリクエスト・レスポンスのJSON形式を設計してください。
要件
以下の4つのエンドポイントの入出力を設計すること。
- タスク作成
POST /api/v1/projects/:projectId/tasks - タスク一覧取得
GET /api/v1/projects/:projectId/tasks - タスク更新
PATCH /api/v1/tasks/:taskId - タスク詳細取得
GET /api/v1/tasks/:taskId
解答
// 1. タスク作成
// POST /api/v1/projects/proj_123/tasks
// Request:
{
"title": "ログイン画面のUI改善",
"description": "モバイル対応のレスポンシブデザインに修正",
"assigneeId": "usr_456",
"priority": "high",
"dueDate": "2025-02-28T23:59:59Z",
"labelIds": ["lbl_001", "lbl_003"]
}
// Response: 201 Created
// Location: /api/v1/tasks/tsk_789
{
"data": {
"id": "tsk_789",
"title": "ログイン画面のUI改善",
"description": "モバイル対応のレスポンシブデザインに修正",
"status": "todo",
"priority": "high",
"assignee": {
"id": "usr_456",
"name": "鈴木花子"
},
"labels": [
{ "id": "lbl_001", "name": "UI", "color": "#3b82f6" },
{ "id": "lbl_003", "name": "改善", "color": "#10b981" }
],
"dueDate": "2025-02-28T23:59:59Z",
"createdAt": "2025-01-15T09:00:00Z",
"updatedAt": "2025-01-15T09:00:00Z"
}
}
// 2. タスク一覧取得
// GET /api/v1/projects/proj_123/tasks?status=todo&sort=-priority&page=1&perPage=20
// Response: 200 OK
{
"data": [
{
"id": "tsk_789",
"title": "ログイン画面のUI改善",
"status": "todo",
"priority": "high",
"assignee": { "id": "usr_456", "name": "鈴木花子" },
"dueDate": "2025-02-28T23:59:59Z",
"createdAt": "2025-01-15T09:00:00Z"
}
],
"meta": {
"totalCount": 42,
"currentPage": 1,
"perPage": 20,
"totalPages": 3
}
}
// 3. タスク更新
// PATCH /api/v1/tasks/tsk_789
// Request:
{
"status": "in_progress",
"priority": "medium"
}
// Response: 200 OK
{
"data": {
"id": "tsk_789",
"title": "ログイン画面のUI改善",
"status": "in_progress",
"priority": "medium",
"updatedAt": "2025-01-16T10:30:00Z"
}
}
// 4. タスク詳細取得
// GET /api/v1/tasks/tsk_789
// Response: 200 OK
{
"data": {
"id": "tsk_789",
"title": "ログイン画面のUI改善",
"description": "モバイル対応のレスポンシブデザインに修正",
"status": "in_progress",
"priority": "medium",
"assignee": { "id": "usr_456", "name": "鈴木花子" },
"labels": [
{ "id": "lbl_001", "name": "UI", "color": "#3b82f6" },
{ "id": "lbl_003", "name": "改善", "color": "#10b981" }
],
"project": { "id": "proj_123", "name": "TaskFlow v2" },
"commentCount": 5,
"dueDate": "2025-02-28T23:59:59Z",
"createdAt": "2025-01-15T09:00:00Z",
"updatedAt": "2025-01-16T10:30:00Z"
}
}
Mission 4: エラーレスポンス設計(15分)
以下のエラーケースに対するレスポンスを設計してください。
- 存在しないタスクへのアクセス
- バリデーションエラー(タイトルが空、優先度が不正)
- プロジェクトメンバーでないユーザーがタスクを作成しようとした
- レート制限超過
解答
// 1. 存在しないタスク: 404 Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "指定されたタスクが見つかりません",
"traceId": "req_abc123"
}
}
// 2. バリデーションエラー: 422 Unprocessable Entity
{
"error": {
"code": "VALIDATION_ERROR",
"message": "入力内容に問題があります",
"details": [
{ "field": "title", "message": "タイトルは必須です" },
{ "field": "priority", "message": "priority は low, medium, high のいずれかを指定してください", "value": "urgent" }
],
"traceId": "req_def456"
}
}
// 3. 権限エラー: 403 Forbidden
{
"error": {
"code": "FORBIDDEN",
"message": "このプロジェクトのメンバーではないため、タスクを作成できません",
"traceId": "req_ghi789"
}
}
// 4. レート制限超過: 429 Too Many Requests
// Headers: Retry-After: 3600
{
"error": {
"code": "RATE_LIMITED",
"message": "リクエスト数が制限を超えました。3600秒後に再試行してください。",
"retryAfter": 3600,
"traceId": "req_jkl012"
}
}
Mission 5: 認証・認可の設計(15分)
TaskFlow APIの認証・認可の方式を設計してください。
要件
- JWT ベースの認証
- ロールは owner, admin, member, viewer の4種類
- プロジェクトごとにロールが異なる
解答
// 認証フロー
// 1. ログイン → JWTトークン取得
POST /api/v1/auth/login
Request: { "email": "tanaka@example.com", "password": "..." }
Response: {
"data": {
"accessToken": "eyJhbG...",
"refreshToken": "ref_abc...",
"expiresIn": 900
}
}
// 2. APIリクエストにトークンを付与
GET /api/v1/projects
Authorization: Bearer eyJhbG...
// ロール定義と権限マトリクス
// | 操作 | owner | admin | member | viewer |
// |---------------|-------|-------|--------|--------|
// | プロジェクト削除 | o | | | |
// | メンバー管理 | o | o | | |
// | タスク作成/更新 | o | o | o | |
// | タスク閲覧 | o | o | o | o |
// | コメント投稿 | o | o | o | |
// JWTペイロード
{
"sub": "usr_123",
"name": "田中太郎",
"iat": 1705305600,
"exp": 1705306500
}
// プロジェクトメンバーシップ(DBで管理)
interface ProjectMembership {
projectId: string;
userId: string;
role: 'owner' | 'admin' | 'member' | 'viewer';
joinedAt: string;
}
// 認可ミドルウェア
function requireProjectRole(...allowedRoles: string[]) {
return async (req: Request, res: Response, next: NextFunction) => {
const { projectId } = req.params;
const userId = req.user.id;
const membership = await db.projectMembers.findOne({ projectId, userId });
if (!membership || !allowedRoles.includes(membership.role)) {
return res.status(403).json({
error: { code: 'FORBIDDEN', message: 'この操作の権限がありません' }
});
}
next();
};
}
// 使用例
app.post('/api/v1/projects/:projectId/tasks',
authenticate,
requireProjectRole('owner', 'admin', 'member'),
createTask
);
Mission 6: ページネーション・フィルタ設計(15分)
タスク一覧APIのフィルタリング・ソート・ページネーションを設計してください。
解答
// タスク一覧のクエリパラメータ設計
GET /api/v1/projects/:projectId/tasks
?status=todo,in_progress // ステータスで絞り込み(カンマ区切りで複数)
&priority=high // 優先度で絞り込み
&assigneeId=usr_456 // 担当者で絞り込み
&labelId=lbl_001 // ラベルで絞り込み
&search=ログイン // タイトル・説明文の部分一致検索
&dueBefore=2025-02-28 // 期限日の範囲(以前)
&dueAfter=2025-01-01 // 期限日の範囲(以降)
&sort=-priority,createdAt // ソート(-で降順)
&page=1 // ページ番号
&perPage=20 // 1ページあたりの件数
// TypeScript の型定義
interface TaskListQuery {
status?: string; // カンマ区切り
priority?: 'low' | 'medium' | 'high';
assigneeId?: string;
labelId?: string;
search?: string;
dueBefore?: string; // ISO 8601 date
dueAfter?: string; // ISO 8601 date
sort?: string; // デフォルト: '-createdAt'
page?: number; // デフォルト: 1
perPage?: number; // デフォルト: 20, 最大: 100
}
// レスポンス
{
"data": [...],
"meta": {
"totalCount": 42,
"currentPage": 1,
"perPage": 20,
"totalPages": 3
},
"links": {
"self": "/api/v1/projects/proj_123/tasks?page=1&perPage=20",
"next": "/api/v1/projects/proj_123/tasks?page=2&perPage=20",
"last": "/api/v1/projects/proj_123/tasks?page=3&perPage=20"
}
}
達成度チェック
| ミッション | テーマ | 完了 |
|---|---|---|
| Mission 1 | リソース設計 | [ ] |
| Mission 2 | エンドポイント一覧 | [ ] |
| Mission 3 | リクエスト・レスポンス設計 | [ ] |
| Mission 4 | エラーレスポンス設計 | [ ] |
| Mission 5 | 認証・認可の設計 | [ ] |
| Mission 6 | ページネーション・フィルタ設計 | [ ] |
まとめ
| ポイント | 内容 |
|---|---|
| リソース設計 | ユースケースからリソースを洗い出し、関係を整理する |
| エンドポイント | RESTの規約に従い、一貫したURL構造を設計する |
| レスポンス形式 | data + meta の統一構造、プレフィックス付きID |
| エラー設計 | 適切なステータスコード + 構造化エラー情報 |
| 認証・認可 | JWT + ロールベースのアクセス制御 |
チェックリスト
- 要件からリソースを洗い出し、関係を整理できた
- RESTful なエンドポイント一覧を設計できた
- リクエスト・レスポンスのJSON構造を設計できた
- エラーケースに対する適切なレスポンスを設計できた
- 認証・認可の方式を選択し、権限マトリクスを定義できた
次のステップへ
お疲れさまでした。RESTful APIの設計を実践しました。
次はStep 2のチェックポイントです。 リソース設計、HATEOAS、認証、レート制限の知識を確認しましょう。
推定所要時間: 90分