🛣️ ユーザールート
ユーザールートは、Nodeblocksアプリケーションでユーザー管理操作のための事前設定されたHTTPエンドポイントを提供します。これらのルートは、ハンドラー、バリデーター、ミドルウェアを組み合わせて、適切な認証、認可、エラー処理を含む完全なAPIエンドポイントを作成します。
🎯 概要
ユーザールートは以下の目的で設計されています:
- 完全なAPIエンドポイントの提供 - ユーザー管理操作用
- ハンドラーとバリデーターの組み合わせ - セキュアな操作のため
- 認証と認可チェックの含める - 認証と認可のチェックを含む
- 関数型コンポジションパターンのサポート - 関数型コンポジションパターンをサポート
- ロギングとエラー管理の自動処理 - ロギングとエラー管理を自動的に処理
📋 ルート構造
各ユーザールートは一貫したパターンに従います:
- HTTP Method: 操作タイプを定義(GET、POST、PATCH、DELETE)
- Path: パラメータ付きエンドポイントURLを指定
- ハンドラー: ビジネスロジック用のコンポーズされた関数チェーン
- バリデーター: 認証と認可チェック
🔧 利用可能なユーザールート
createUserRoute
新しいユーザーを作成し、作成されたリソースを返します。
目的: ユーザー登録を処理します
ルート詳細:
- Method:
POST - Path:
/users - Authentication: 必須(Bearerトークン)
ハンドラー: createUser, getUserById, normalizeAvatarOfOwner, normalizeUser, orThrow
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'identityId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createUserRoute);
getUserRoute
IDで特定のユーザーを取得します。
目的: アクセス制御付きでユーザープロフィールデータを取得します
ルート詳細:
- Method:
GET - Path:
/users/:profileId - Authentication: 必須(Bearerトークン)
ハンドラー: getUserById, normalizeAvatarOfOwner, normalizeUser, orThrow
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), ownsProfile(['params', 'requestParams', 'profileId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getUserRoute);
findUsersRoute
正規化されたリスト形式で全てのユーザーを取得します。
目的: ページネーションと管理者専用アクセスでユーザーをリスト表示します
ルート詳細:
- Method:
GET - Path:
/users - Authentication: 必須(Bearerトークン)
ハンドラー: findUsers, normalizeAvatarsOfOwners, normalizeUsers, orThrow
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findUsersRoute);
updateUserRoute
既存のユーザーを更新し、更新されたリソースを返します。
目的: アクセス制御付きでユーザーデータを変更します
ルート詳細:
- Method:
PATCH - Path:
/users/:profileId - Authentication: 必須(Bearerトークン)
ハンドラー: getUserById, updateUser, getUserById, deleteAvatarIfReplaced, normalizeAvatarOfOwner, normalizeUser, orThrow
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), ownsProfile(['params', 'requestParams', 'profileId']))
レスポンス (200 OK): 正規化されたアバターURLを含む更新されたユーザーオブジェクト
エラーレスポンス:
401 Unauthorized: 認証に失敗しました403 Forbidden: 所有権なしで更新を試みる非管理者ユーザー404 Not Found: ユーザーが見つかりません500 Internal Server Error: データベース操作、アバタークリーンアップ、またはアバター正規化に失敗しました
ハンドラープロセス:
- 認証とパスパラメータをバリデーションします
- 更新前にユーザーデータを取得します
- データベース内のユーザーデータを更新します
- アバターが置き換えられた場合、ストレージから古いアバターファイルを削除します
- 新しいアバターの署名付きURLを生成します(存在する場合)
- アバターURLを含む正規化されたユーザーデータを返します
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateUserRoute);
deleteUserRoute
IDでユーザーを削除し、自動的にアバターをクリーンアップします。
目的: アクセス制御付きでユーザーアカウントを削除し、ストレージから関連するアバターファイルをクリーンアップします
ルート詳細:
- Method:
DELETE - Path:
/users/:profileId - Authentication: 必須(Bearerトークン)
ブロック: getUserById, deleteUser, deleteAvatar
ターミネーター: deleteUserTerminator
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), ownsProfile(['params', 'requestParams', 'profileId']))
レスポンス (204 No Content): 削除成功時の空のレスポンスボディ
エラーレスポンス:
401 Unauthorized: 認証に失敗しました403 Forbidden: 削除を試みる非管理者ユーザー404 Not Found: ユーザーが見つかりません500 Internal Server Error: データベース操作またはアバタークリーンアップに失敗しました
ハンドラープロセス:
- 認証とパスパラメータをバリデーションします
- アバター情報にアクセスするためにユーザーデータを取得します
- データベースからユーザーを削除します
- 関連するアバターファイルをストレージから削除します(存在する場合)
- 削除成功時に204 No Contentを返します
認可に関する注意:
- 現在、管理者ユーザーまたはプロフィール所有者に制限されています
- TODO: 組織ベースのアクセス制御を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteUserRoute);
// Client usage:
const response = await fetch('/api/users/user-123', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 204) {
// User and avatar deleted successfully
}
getAvatarUploadUrlRoute
GET /user-profiles/:profileId/avatar-upload-url経由でアバター画像をアップロードするための署名付きURLを返します。
目的: 自動UUIDファイル名生成付きでセキュアなアバターファイルアップロード用の事前署名付きURLを生成します
ルート詳細:
- Method:
GET - Path:
/user-profiles/:profileId/avatar-upload-url - Authentication: 必須(Bearerトークン)
ブロック: generateSignedAvatarUploadUrl, orThrow
バリデーター: isAuthenticated, some(checkIdentityType(['admin']), ownsProfile(['params', 'requestParams', 'profileId']))
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Use in feature composition:
export const getAvatarUploadUrlFeature = compose(getAvatarUploadUrlSchema, getAvatarUploadUrlRoute);
findProfilesByIdentityIdRoute
アバター正規化と自己アクセス制御付きでGET /profiles/identities/:identityId経由でID別にページネーションされたプロフィールを取得します。
ルート設定:
- Method: GET
- Path:
/profiles/identities/:identityId - ハンドラー: buildIdentityIdFilter, buildWithoutMongoIdFindOptions, findProfiles, normalizeAvatarsOfOwners, applySpec, orThrow
- バリデーター: isAuthenticated, isSelf(['params', 'requestParams', 'identityId'])
ハンドラープロセス:
- 入力: Identity IDパスパラメータ、認証トークン
- プロセス: 自己アクセスをバリデーションし、フィルターを構築し、プロフィールをクエリし、アバターを正規化し、ページネーションメタデータを適用します
- 出力: アバターURLとページネーションメタデータを含むページネーションされたプロフィールデータ
- エラー: ProfileDbBlockError (500), AvatarBlockError (500), 認証エラー (401), アクセス拒否 (403)
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Use in feature composition:
export const findProfilesByIdentityIdFeature = compose(findProfilesByIdentityIdSchema, findProfilesByIdentityIdRoute);
// Register route with Express app
app.use('/api', routes.findProfilesByIdentityIdRoute);
リクエスト:
GET /api/profiles/identities/identity-123?page=1&limit=10
Authorization: Bearer <access-token>
レスポンス (200):
{
"data": [
{
"id": "profile-456",
"name": "John Doe",
"avatar": {
"url": "https://cdn.example.com/avatars/profile-456.jpg",
"type": "image/jpeg"
},
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"metadata": {
"pagination": {
"hasNext": false,
"hasPrev": false,
"limit": 10,
"page": 1,
"total": 1,
"totalPages": 1
}
}
}
エラーレスポンス:
401 Unauthorized: 認証トークンが欠落しているか無効です403 Forbidden: 別のIDのプロフィールにアクセスしようとしています500 Internal Server Error: データベースまたはアバター処理エラー