メインコンテンツまでスキップ
バージョン: 0.9.0 (最新)

🛣️ ユーザールート

ユーザールートは、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: データベース操作、アバタークリーンアップ、またはアバター正規化に失敗しました

ハンドラープロセス:

  1. 認証とパスパラメータをバリデーションします
  2. 更新前にユーザーデータを取得します
  3. データベース内のユーザーデータを更新します
  4. アバターが置き換えられた場合、ストレージから古いアバターファイルを削除します
  5. 新しいアバターの署名付きURLを生成します(存在する場合)
  6. アバター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: データベース操作またはアバタークリーンアップに失敗しました

ハンドラープロセス:

  1. 認証とパスパラメータをバリデーションします
  2. アバター情報にアクセスするためにユーザーデータを取得します
  3. データベースからユーザーを削除します
  4. 関連するアバターファイルをストレージから削除します(存在する場合)
  5. 削除成功時に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: データベースまたはアバター処理エラー