🛣️ 製品ルート
製品ルートは、Nodeblocksアプリケーションにおける製品管理操作のための事前設定されたHTTPエンドポイントを提供します。これらのルートは、ハンドラー、バリデーター、ミドルウェアを組み合わせて、適切な認証、認可、エラー処理を含む完全なAPIエンドポイントを作成します。
🎯 概要
製品ルートは以下の目的で設計されています:
- 製品管理操作のための完全なAPIエンドポイントを提供
- 安全な操作のためにハンドラーとバリデーターを組み合わせ
- 認証と認可のチェックを含む
- 関数合成パターンをサポート
- ロギングとエラー管理を自動的に処理
📋 ルート構造
各製品ルートは一貫したパターンに従います:
- HTTPメソッド: 操作タイプを定義(GET、POST、PATCH、DELETE)
- パス: パラメータ付きエンドポイントURLを指定
- ハンドラー: ビジネスロジックのための合成関数チェーン
- バリデーター: 認証と認可のチェック
🔧 利用可能な製品ルート
createProductRoute
新しい製品を作成し、作成されたリソースを返します。
目的: 完全なリソース取得を含む製品作成を処理
ルート詳細:
- Method:
POST - Path:
/products - 認証: 必須(Bearerトークン)
ハンドラー: createProduct, getProductById, normalizeProduct, orThrow
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createProductRoute);
findProductsRoute
正規化されたリスト形式ですべての製品を取得します。
目的: ページネーション付きで製品を一覧表示
ルート詳細:
- Method:
GET - Path:
/products - 認証: 不要
ハンドラー: findProducts, normalizeProductsListTerminator
バリデーター: None
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findProductsRoute);
createProductBatchRoute
バッチで複数の製品を作成し、作成されたリソースを返します。
目的: 検証を含むバッチ製品作成を処理
ルート詳細:
- Method:
POST - Path:
/products/batch - 認証: 必須(Bearerトークン)
ハンドラー: createProductBatch, getProductsByIds, normalizeProducts, orThrow
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createProductBatchRoute);
updateProductBatchRoute
バッチで複数の製品を更新し、更新されたリソースを返します。
目的: 検証を含むバッチ製品更新を処理
ルート詳細:
- Method:
PATCH - Path:
/products/batch - 認証: 必須(Bearerトークン)
ハンドラー: updateProductBatch, getProductsByIds, normalizeProductsListTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateProductBatchRoute);
deleteProductBatchRoute
バッチで複数の製品を削除します。
目的: 検証を含むバッチ製品削除を処理
ルート詳細:
- Method:
DELETE - Path:
/products/batch - 認証: 必須(Bearerトークン)
ハンドラー: deleteProductBatch, deleteBatchProductsTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteProductBatchRoute);
getProductRoute
IDで特定の製品を取得します。
目的: 製品データを取得
ルート詳細:
- Method:
GET - Path:
/products/:productId - 認証: 不要
ハンドラー: getProductById, normalizeProductTerminator
バリデーター: None
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getProductRoute);
updateProductRoute
既存の製品を更新し、更新されたリソースを返します。
目的: アクセス制御付きで製品データを変更
ルート詳細:
- Method:
PATCH - Path:
/products/:productId - 認証: 必須(Bearerトークン)
ハンドラー: updateProduct, getProductById, normalizeProductTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateProductRoute);
deleteProductRoute
自動画像クリーンアップ付きでIDで製品を削除します。
目的: アクセス制御付きで製品を削除し、ストレージから関連する画像をクリーンアップ
ルート詳細:
- Method:
DELETE - Path:
/products/:productId - 認証: 必須(Bearerトークン)
ブロック: deleteImagesOfProduct, deleteProduct
ターミネーター: 204ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
レスポンス (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.deleteProductRoute);
// Client usage:
const response = await fetch('/api/products/product-123', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 204) {
// Product and all its images deleted successfully
}
copyProductRoute
既存の製品のコピーを作成します。
目的: アクセス制御付きで製品を複製
ルート詳細:
- Method:
POST - Path:
/products/:productId/copy - 認証: 必須(Bearerトークン)
ハンドラー: copyProduct, getProductById, normalizeProductTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.copyProductRoute);
copyProductBatchRoute
バッチで複数の製品のコピーを作成します。
目的: 検証を含むバッチ製品コピーを処理
ルート詳細:
- Method:
POST - Path:
/products/batch/copy - 認証: 必須(Bearerトークン)
ハンドラー: copyProductBatch, getProductsByIds, normalizeProductsListTerminator
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.copyProductBatchRoute);
getProductImageUploadUrlRoute
GET /products/:productId/image-upload-url経由で製品画像をアップロードするための署名付きURLを生成します。
目的: 安全な製品画像アップロードのための事前署名付きURLを発行
ルート詳細:
- Method:
GET - Path:
/products/:productId/image-upload-url - 認証: 必須(Bearerトークン)
ブロック: generateProductImageUploadUrl
ターミネーター: orThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getProductImageUploadUrlRoute);
createProductImageRoute
POST /products/:productId/images経由で特定の製品の新しい製品画像を作成します。
目的: 既存の製品の画像配列に新しい画像を追加
ルート詳細:
- Method:
POST - Path:
/products/:productId/images - 認証: 必須(Bearerトークン)
ブロック: createProductImage, getProductImageById
ターミネーター: 201ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
リクエストボディ:
{
"objectId": "string (uuid)",
"type": "string"
}
レスポンス (201 Created):
{
"id": "string (uuid)",
"objectId": "string (uuid)",
"type": "string",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
エラーレスポンス:
404: 製品が見つからないか、作成後に画像が見つかりませんでした500: データベース操作が失敗しました
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createProductImageRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/images', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
objectId: '550e8400-e29b-41d4-a716-446655440000',
type: 'image/png'
})
});
deleteProductImageRoute
DELETE /products/:productId/images/:imageId経由で製品画像を削除します。
目的: 製品の画像配列から画像を削除し、ストレージからファイルを削除
ルート詳細:
- Method:
DELETE - Path:
/products/:productId/images/:imageId - 認証: 必須(Bearerトークン)
ブロック: deleteProductImage
ターミネーター: 204ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
レスポンス (204 No Content): 成功時の空のレスポンスボディ
エラーレスポンス:
404: 製品が見つからないか、製品内に画像が見つかりませんでした500: データベース操作が失敗したか、ファイルストレージの削除が失敗しました
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteProductImageRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/images/img-456', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 204) {
console.log('Image deleted successfully');
}
操作詳細:
- データベース内の製品の画像配列から画像を削除
- ファイルストレージから実際の画像ファイルを削除
- 製品の
updatedAtタイムスタンプを更新 - 成功時に204 No Contentを返す
createProductVariantRoute
POST /products/:productId/variants経由で新しい製品バリアントを作成します。
目的: 完全な検証と正規化を含む既存の製品に新しいバリアントを追加
ルート詳細:
- Method:
POST - Path:
/products/:productId/variants - 認証: 必須(Bearerトークン)
ブロック: createProductVariant, getProductVariantById, normalizeRawDocument
ターミネーター: 201ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
リクエストボディ:
{
"title": "string (required)",
"description": "string (optional)",
"sku": "string (optional)",
"imageIds": ["string"] (optional),
"price": {
"amount": "number (optional)",
"currency": "string (optional)",
"taxIncluded": "boolean (optional)",
"taxable": "boolean (optional)"
}
}
レスポンス (201 Created):
{
"id": "string (uuid)",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"imageIds": ["string"],
"price": {
"amount": "number",
"currency": "string",
"taxIncluded": "boolean",
"taxable": "boolean"
},
"delFlg": 0,
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
エラーレスポンス:
400 Bad Request: 無効なリクエストボディまたは必須フィールドが不足しています404 Not Found: 作成後に製品バリアントが見つかりませんでした500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- リクエストボディとパスパラメータを検証
- 自動生成されたIDとタイムスタンプでデータベースに製品バリアントを作成
- 作成されたバリアントを取得して作成の成功を確認
- MongoDB
_idフィールドを削除してレスポンスを正規化 - 正規化されたバリアントデータで201 Createdを返す
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createProductVariantRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/variants', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Blue Baseball Cap',
sku: 'BBC-BLUE',
price: {
amount: 2999,
currency: 'USD',
taxIncluded: false,
taxable: true
},
imageIds: ['img-456', 'img-789']
})
});
const variant = await response.json();
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認チェックを追加
createProductVariantBulkRoute
POST /product/:productId/variants/bulk経由で複数の製品バリアントを一括作成します。
目的: 包括的な検証と正規化を含む単一の操作で複数の製品バリアントを効率的に作成します。
ルート詳細:
- Method:
POST - Path:
/product/:productId/variants/bulk - 認証: 必須(Bearerトークン)
ブロック: createProductVariantBulk, buildFilterToGetProductVariantsByIds, findProductVariants, normalizeDocuments
ターミネーター: 201ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
パスパラメータ:
productId: string- すべてのバリアントを関連付ける製品ID(URLパスから)
リクエストボディ(配列):
[
{
"title": "string (required)",
"description": "string (optional)",
"sku": "string (optional)",
"price": {
"amount": "number (optional)",
"currency": "string (optional)"
},
"imageIds": ["string"] (optional),
"isActive": "boolean (optional)"
}
]
レスポンス (201 Created):
[
{
"id": "string (uuid)",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"price": {
"amount": "number",
"currency": "string"
},
"imageIds": ["string"],
"isActive": "boolean",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
]
制約:
- リクエストごとに最大100バリアント
- リクエストごとに最小1バリアント
- 各バリアントには
productIdとtitleが必要です
エラーレスポンス:
400 Bad Request: 無効なリクエストボディ、必須フィールドの不足、または制約違反401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーが一括作成を試行しています500 Internal Server Error: データベース操作が失敗したか、一括書き込みエラーが発生しました
ハンドラープロセス:
- 認証、パスパラメータ、リクエストボディ配列を検証
- 製品関連付けを含むバッチデータベース操作で複数の製品バリアントを作成
- 生成されたIDで作成されたバリアントを取得
- MongoDB
_idフィールドを削除してレスポンスを正規化 - 正規化されたバリアントデータの配列で201 Createdを返す
主な機能:
- 一括効率: 複数のバリアントに対する単一のデータベース操作
- アトミック操作: すべてのバリアントが成功するか、すべてが失敗
- エラー特異性: 一括書き込み失敗の詳細なエラー報告
- データ正規化: レスポンスでの自動MongoDBフィールドクリーンアップ
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認チェックを追加
- TODO: 各バリアントの製品所有権検証を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createProductVariantBulkRoute);
// Client usage:
const response = await fetch('/api/product/prod-123/variants/bulk', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify([
{
title: 'Small - Red',
sku: 'S-RED',
price: { amount: 1999, currency: 'USD' }
},
{
title: 'Medium - Blue',
sku: 'M-BLUE',
price: { amount: 2099, currency: 'USD' }
}
])
});
const variants = await response.json();
updateProductVariantBulkRoute
PATCH /product/:productId/variants/bulk経由で複数の製品バリアントを一括更新します。
目的: 包括的な検証とデータ正規化を含む単一の操作で複数の製品バリアントを効率的に更新します。
ルート詳細:
- Method:
PATCH - Path:
/product/:productId/variants/bulk - 認証: 必須(Bearerトークン)
ブロック: updateProductVariantBulk, buildFilterToGetProductVariantsByIds, findProductVariants, normalizeDocuments
ターミネーター: 200ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
パスパラメータ:
productId: string- バリアントを関連付ける製品ID(URLパスから)
リクエストボディ:
{
"ids": ["string"],
"data": {
"description": "string (optional)",
"sku": "string (optional)",
"price": {
"amount": "number (optional)",
"currency": "string (optional)"
},
"imageIds": ["string"] (optional),
"title": "string (optional)"
}
}
レスポンス(200 OK):
[
{
"id": "string",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"price": {
"amount": "number",
"currency": "string"
},
"imageIds": ["string"],
"createdAt": "string",
"updatedAt": "string"
}
]
制約:
- リクエストごとに最大100バリアントID
- リクエストごとに最小1バリアントID
- 各IDは既存のバリアントに対応している必要があります
エラーレスポンス:
400 Bad Request: 無効なリクエストボディ、必須フィールドの不足、または制約違反401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーが一括更新を試行しています404 Not Found: 1つ以上の製品バリアントが見つかりませんでした500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- 認証、パスパラメータ、リクエストボディ構造を検証
- バッチデータベース操作で指定されたすべてのバリアントを更新
- IDで更新されたバリアントを取得
- MongoDB
_idフィールドを削除してレスポンスを正規化 - 正規化されたバリアントデータの配列で200 OKを返す
主な機能:
- 一括効率: 複数のバリアント更新に対する単一のデータベース操作
- アトミック操作: すべての更新が成功するか、操作全体が失敗
- データ正規化: レスポンスでの自動MongoDBフィールドクリーンアップ
- 柔軟な更新: 任意のバリアントフィールドの組み合わせを更新
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認要件を追加
- TODO: 各バリアントの製品所有権検証を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateProductVariantBulkRoute);
// Client usage:
const response = await fetch('/api/product/prod-123/variants/bulk', {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
ids: ['var-123', 'var-456', 'var-789'],
data: {
description: 'Updated description for all variants',
price: { amount: 2999, currency: 'USD' }
}
})
});
const variants = await response.json();
deleteProductVariantBulkRoute
POST /product/:productId/variants/bulk-delete経由で複数の製品バリアントを一括削除します。
目的: 包括的な検証とエラー処理を含む単一の操作で複数の製品バリアントを効率的に削除します。
ルート詳細:
- Method:
POST - Path:
/product/:productId/variants/bulk-delete - 認証: 必須(Bearerトークン)
ブロック: deleteProductVariantBulk, normalizeEmptyBody
ターミネーター: 204ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
パスパラメータ:
productId: string- バリアントを関連付ける製品ID(URLパスから)
リクエストボディ:
["string", "string", "string"]
レスポンス (204 No Content): 削除成功時の空のレスポンスボディ
制約:
- リクエストごとに最大100バリアントID
- リクエストごとに最小1バリアントID
- 各IDは既存のバリアントに対応している必要があります
エラーレスポンス:
400 Bad Request: 無効なリクエストボディ、必須フィールドの不足、または制約違反401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーが一括削除を試行しています500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- 認証、パスパラメータ、リクエストボディ構造を検証
- バッチデータベース操作で指定されたすべてのバリアントを削除
- 少なくとも1つのバリアントが削除されたことを検証
- 削除成功時に204 No Contentを返す
主な機能:
- 一括効率: 複数のバリアント削除に対する単一のデータベース操作
- アトミック操作: すべての削除が成功するか、操作全体が失敗
- 検証: 成功を返す前に少なくとも1つのバリアントが削除されることを保証
- クリーンなレスポンス: 成功したバッチ削除に対して204 No Contentを返す
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認要件を追加
- TODO: 各バリアントの製品所有権検証を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteProductVariantBulkRoute);
// Client usage:
const response = await fetch('/api/product/prod-123/variants/bulk-delete', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify([
'var-123',
'var-456',
'var-789'
])
});
// 204 No Content on success
if (response.status === 204) {
console.log('All variants deleted successfully');
}
getProductVariantRoute
GET /products/:productId/variants/:productVariantId経由で製品バリアントを取得します。
目的: データ正規化を含む特定の製品バリアントの詳細情報を取得
ルート詳細:
- Method:
GET - Path:
/products/:productId/variants/:productVariantId - 認証: 必須(Bearerトークン)
ブロック: getProductVariantById, normalizeRawDocument
ターミネーター: 200ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated
レスポンス(200 OK):
{
"id": "string (uuid)",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"imageIds": ["string"],
"price": {
"amount": "number",
"currency": "string",
"taxIncluded": "boolean",
"taxable": "boolean"
},
"delFlg": 0,
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
エラーレスポンス:
401 Unauthorized: 認証が失敗しました404 Not Found: 製品バリアントが見つからないか、指定された製品に属していません500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- 認証とパスパラメータを検証
- 製品スコープ付きでデータベースから製品バリアントを取得
- MongoDB
_idフィールドを削除してレスポンスを正規化 - 正規化されたバリアントデータで200 OKを返す
認可に関する注意:
- 認証のみが必要です(現在、ロール制限なし)
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認チェックを追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getProductVariantRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/variants/var-456', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const variant = await response.json();
// 製品バリアントの詳細で200 OKを返す
updateProductVariantRoute
PATCH /products/:productId/variants/:productVariantId経由で製品バリアントを更新します。
目的: 完全な検証と正規化を含む既存の製品バリアントデータを変更
ルート詳細:
- Method:
PATCH - Path:
/products/:productId/variants/:productVariantId - 認証: 必須(Bearerトークン)
ブロック: updateProductVariant, getProductVariantById, normalizeRawDocument
ターミネーター: 200ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
リクエストボディ:
{
"title": "string (optional)",
"description": "string (optional)",
"sku": "string (optional)",
"imageIds": ["string"] (optional),
"price": {
"amount": "number (optional)",
"currency": "string (optional)",
"taxIncluded": "boolean (optional)",
"taxable": "boolean (optional)"
}
}
レスポンス(200 OK):
{
"id": "string (uuid)",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"imageIds": ["string"],
"price": {
"amount": "number",
"currency": "string",
"taxIncluded": "boolean",
"taxable": "boolean"
},
"delFlg": 0,
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
エラーレスポンス:
400 Bad Request: 無効なリクエストボディまたは追加プロパティ401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーが更新を試行しています404 Not Found: 製品バリアントが見つかりませんでした500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- 認証とパスパラメータを検証
- オプションの制約付きでデータベース内の製品バリアントを更新
- 更新されたバリアントを取得して変更の成功を確認
- MongoDB
_idフィールドを削除してレスポンスを正規化 - 正規化された更新されたバリアントデータで200 OKを返す
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認チェックを追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateProductVariantRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/variants/var-456', {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
price: {
amount: 2499,
currency: 'USD'
},
sku: 'BBC-BLUE-UPDATED'
})
});
const updatedVariant = await response.json();
// 更新された製品バリアントで200 OKを返す
deleteProductVariantRoute
DELETE /products/:productId/variants/:productVariantId経由で製品バリアントを削除します。
目的: 適切な検証とエラー処理を含むデータベースから製品バリアントを削除
ルート詳細:
- Method:
DELETE - Path:
/products/:productId/variants/:productVariantId - 認証: 必須(Bearerトークン)
ブロック: deleteProductVariant, normalizeEmptyBody
ターミネーター: 204ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
レスポンス (204 No Content): 削除成功時の空のレスポンスボディ
エラーレスポンス:
401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーが削除を試行しています500 Internal Server Error: データベース操作が失敗したか、バリアントが見つかりませんでした
ハンドラープロセス:
- 認証とパスパラメータを検証
- IDでデータベースから製品バリアントを削除
- 空のレスポンスボディを正規化
- 削除成功時に204 No Contentを返す
認可に関する注意:
- 現在、管理者ユーザーのみに制限されています
- TODO: 組織ベースのアクセス制御を追加
- TODO: メール確認チェックを追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteProductVariantRoute);
// Client usage:
const response = await fetch('/api/products/prod-123/variants/var-456', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 204) {
// Product variant deleted successfully
}
findProductVariantsRoute
GET /products/:productId/variants経由で特定の製品の製品バリアントを取得します。
目的: ページネーションと適切なデータ正規化を含む特定の製品のすべての製品バリアントを一覧表示
ルート詳細:
- Method:
GET - Path:
/products/:productId/variants - 認証: 不要(TODO: 認証と認可を追加)
ブロック: buildFilterToGetProductVariantsByProductId, findProductVariants, normalizeDocuments
ターミネーター: 組み込みのページネーションとレスポンスフォーマット
バリデーター: 現在なし(TODO: 製品の存在検証を追加)
レスポンス(200 OK):
{
"data": [
{
"id": "string",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"imageIds": ["string"],
"price": {
"amount": "number",
"currency": "string"
},
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
クエリパラメータ:
page?: number- ページネーションのページ番号(デフォルト: 1)limit?: number- 1ページあたりのアイテム数(デフォルト: 10)sort?: string- ソートするフィールドorder?: "asc" | "desc"- ソート順序の方向
エラーレスポンス:
500 Internal Server Error: データベース操作が失敗しました
ハンドラープロセス:
- 製品IDで製品バリアントを取得するためのフィルタを構築
- ページネーション付きで製品バリアントをデータベースにクエリ
- MongoDB
_idフィールドを削除してドキュメントを正規化 - データとページネーションメタデータでレスポンスをフォーマット
- ページネーション付きのバリアントリストで200 OKを返す
認可に関する注意:
- 現在、認証または認可は不要
- TODO: 製品の存在検証を追加
- TODO: 組織ベースのアクセス制御を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findProductVariantsRoute);
// Client usage with pagination:
const response = await fetch('/api/products/prod-123/variants?page=1&limit=5');
const result = await response.json();
// result.data contains array of product variants
// result.metadata.pagination contains pagination info
findProductsByOrganizationIdRoute
GET /products/organizations/:organizationId経由で組織IDで製品を取得します。
目的: ページネーション、画像正規化、適切な認証制御を含む特定の組織にスコープされた製品を一覧表示します。
ルート詳細:
- Method:
GET - Path:
/products/organizations/:organizationId - 認証: 必須(Bearerトークン)
ブロック: buildOrganizationIdFilter, buildWithoutMongoIdFindOptions, findProductResources, normalizeImagesOfProducts, normalizeProducts
ターミネーター: 200ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, hasOrgRole(['owner', 'admin', 'member'], path to organizationId)
クエリパラメータ:
page?: number- ページネーションのページ番号(デフォルト: 1)limit?: number- 1ページあたりのアイテム数(デフォルト: 10)sort?: string- ソートするフィールドorder?: "asc" | "desc"- ソート順序の方向
レスポンス(200 OK):
{
"data": [
{
"id": "prod-123",
"organizationId": "org-456",
"name": "Premium Widget",
"description": "High-quality widget for professionals",
"images": [
{
"id": "img-789",
"objectId": "abc123...",
"type": "image/jpeg",
"url": "https://storage.googleapis.com/bucket/abc123..."
}
],
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
パスパラメータ:
organizationId: string- 製品取得をスコープするための組織識別子
制約:
- ユーザーは組織メンバーシップ(オーナー、管理者、またはメンバーロール)を持っている必要があります
- マルチテナントサポートのために製品は組織IDでフィルタリングされます
- 画像正規化にはファイルストレージドライバーの設定が必要です
エラーレスポンス:
401 Unauthorized: 認証が失敗しました403 Forbidden: ユーザーが組織にアクセスできません500 Internal Server Error: データベース操作が失敗したか、ファイルストレージエラーが発生しました
ハンドラープロセス:
- 認証と組織アクセス権限を検証
- 製品クエリ用の組織固有のフィルタを構築
_idフィールド投影なしでMongoDB findオプションを設定- ページネーション付きリソース取得を使用して製品をクエリ
- 署名付きURLで製品画像を正規化
- APIレスポンス用に製品データをフォーマットおよび正規化
- ページネーション付き製品リストとメタデータで200 OKを返す
主な機能:
- 組織スコープ: ユーザーが自分の組織内の製品にのみアクセスできることを保証
- 画像正規化: 製品画像の自動URL生成
- ページネーションサポート: 設定可能な制限とソートを含む組み込みページネーション
- データ正規化: MongoDBフィールドクリーンアップとURL強化
- 認可: 組織メンバーシップ検証を含むロールベースアクセス制御
認可に関する注意:
- 認証と組織メンバーシップが必要です
- アクセス用にオーナー、管理者、メンバーロールをサポート
- TODO: メール確認要件を追加
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findProductsByOrganizationIdRoute);
// Client usage with organization scoping:
const response = await fetch('/api/products/organizations/org-123?page=1&limit=5', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const result = await response.json();
// result.data contains organization-scoped products
// result.metadata.pagination contains pagination info
getProductLikersRoute
GET /products/:productId/likers経由で製品のいいねしたユーザーを取得します。
目的: ページネーション、アバター正規化、適切な認証制御を含む特定の製品をいいねしたユーザーを一覧表示します。
ルート詳細:
- Method:
GET - Path:
/products/:productId/likers - 認証: 必須(Bearerトークン)
ブロック: getProductByIdBlock, buildProductLikersByLikeProductIdQuery, buildWithoutMongoIdFindOptions, findProfiles, normalizeFollowers
ターミネーター: 200ステータスコード付きorThrowによる組み込みの成功/エラーマッピング
バリデーター: isAuthenticated, checkIdentityType(['admin'])
クエリパラメータ:
page?: number- ページネーションのページ番号(デフォルト: 1)limit?: number- 1ページあたりのアイテム数(デフォルト: 10)sort?: string- ソートするフィールドorder?: "asc" | "desc"- ソート順序の方向
レスポンス(200 OK):
{
"data": [
{
"id": "user-123",
"name": "John Doe",
"avatar": {
"id": "avatar-456",
"objectId": "abc123...",
"type": "image/jpeg",
"url": "https://storage.googleapis.com/bucket/abc123..."
}
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
パスパラメータ:
productId: string- いいねユーザーを取得するための製品識別子
制約:
- 製品はデータベースに存在する必要があります
- ユーザープロファイルは製品いいね関係でフィルタリングされます
- アバター正規化にはファイルストレージドライバーの設定が必要です
- セキュリティのための管理者専用アクセス
エラーレスポンス:
401 Unauthorized: 認証が失敗しました403 Forbidden: 管理者以外のユーザーがいいねユーザーを表示しようとしています404 Not Found: 製品が見つかりませんでした500 Internal Server Error: データベース操作が失敗したか、ファイルストレージエラーが発生しました
ハンドラープロセス:
- 認証と管理者認証を検証
- データベース内の製品の存在を確認
- 製品をいいねしたユーザー用のクエリフィルタを構築
_idフィールド投影なしでMongoDB findオプションを設定- ページネーションサポート付きでユーザープロフィールをクエリ
- 署名付きURLでユーザーアバターを正規化
- ユーザーデータとページネーションメタデータでレスポンスをフォーマット
- ページネーション付きのいいねユーザーリストで200 OKを返す
主な機能:
- ソーシャルエンゲージメント: 製品をいいねしたユーザーを表示
- アバター正規化: ユーザーアバターの自動URL生成
- ページネーションサポート: 設定可能な制限とソートを含む組み込みページネーション
- データ正規化: MongoDBフィールドクリーンアップとURL強化
- 管理者セキュリティ: プライバシー保護のために管理者ユーザーに制限
認可に関する注意:
- 現在、プライバシー保護のために管理者ユーザーのみに制限されています
- TODO: 製品所有権の検証を追加
- TODO: 製品所有者へのパブリックアクセスを検討
使用例:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getProductLikersRoute);
// Client usage with product likers retrieval:
const response = await fetch('/api/products/prod-123/likers?page=1&limit=5', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const result = await response.json();
// result.data contains user profiles who liked the product
// result.metadata.pagination contains pagination info