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

📦 製品サービス

Testing Status

製品サービスは、製品エンティティを包括的なCRUD操作と強力なバッチ処理機能で管理するための完全な REST API を提供します。NodeBlocks の関数型合成アプローチで構築され、MongoDB とシームレスに統合します。


🚀 クイックスタート

import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';

const { nodeBlocksErrorMiddleware } = middlewares;
const { productService } = services;
const { getMongoClient, createFileStorageDriver } = drivers;

const client = getMongoClient('mongodb://localhost:27017', 'dev');

// 画像アップロードURLエンドポイントで必須:
// GOOGLE_APPLICATION_CREDENTIALS が GCP サービスアカウント JSON に設定されていることを確認してください。
const fileStorageDriver = createFileStorageDriver(
'your-gcp-project-id',
'your-bucket-name'
);

express()
.use(
productService(
{
products: client.collection('products'),
identities: client.collection('identities'),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
},
{ fileStorageDriver }
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));

📋 エンドポイント概要

個別製品操作

メソッドパス説明認可
POST/products新しい製品を作成ベアラートークン必須(管理者のみ)
GET/products/:productIdIDで製品を取得不要
GET/products製品を一覧/フィルタ不要
PATCH/products/:productId製品を更新ベアラートークン必須(管理者のみ)
DELETE/products/:productId製品を削除ベアラートークン必須(管理者のみ)
POST/products/:productId/copy既存の製品をコピーベアラートークン必須(管理者のみ)

ファイルアップロード操作

メソッドパス説明認可
GET/products/:productId/image-upload-url製品画像アップロード用の署名付きURLを取得ベアラートークン必須(管理者のみ)

バッチ製品操作

メソッドパス説明認可
POST/products/batch複数の製品を作成ベアラートークン必須(管理者のみ)
PATCH/products/batch複数の製品を更新ベアラートークン必須(管理者のみ)
DELETE/products/batch複数の製品を削除ベアラートークン必須(管理者のみ)
POST/products/batch/copy複数の製品をコピーベアラートークン必須(管理者のみ)

🗄️ エンティティスキーマ

製品エンティティは、自動生成されるベースフィールドと製品固有のデータで構成されます:

{
"name": "string",
"description": "string",
"createdAt": "string (datetime)",
"id": "string",
"updatedAt": "string (datetime)"
}

フィールド詳細

フィールド自動生成必須説明
namestring製品名
descriptionstring製品説明
createdAtdatetime作成日時
idstring一意識別子(UUID)
updatedAtdatetime最終更新日時

📝 注意: 自動生成フィールドはサービス側で設定され、作成/更新リクエストに含めないでください。レスポンス内のフィールド順序は実際のAPI出力と一致します。


🔐 認証ヘッダー

保護されたエンドポイントでは、次のヘッダーを含めてください:

Authorization: Bearer <admin_access_token>
x-nb-fingerprint: <device_fingerprint>

⚠️ 重要: 認可時にフィンガープリントを指定した場合、認証済みのすべてのリクエストで x-nb-fingerprint ヘッダーが必須です。欠如している場合は 401 Unauthorized が返ります。


🔧 APIエンドポイント

1. 製品作成

提供された情報で新しい製品を作成します。

リクエスト:

  • メソッド: POST
  • パス: /products
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

リクエストボディ:

フィールド必須説明
namestring製品名
descriptionstring製品説明

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring製品名
descriptionstring製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: 自動強制(name、description必須)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X POST {{host}}/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"name": "Premium Widget",
"description": "High-quality widget for enterprise use"
}'

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}

エラーレスポンス:

リクエストボディに必須フィールドがない場合:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'name'",
"request body must have required property 'description'"
]
}
}

データベース挿入操作が失敗した場合:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Failed to create product"
}
}

2. IDで製品取得

一意のIDで特定の製品を取得します。

リクエスト:

  • メソッド: GET
  • パス: /products/:productId
  • 認可: 不要

URL パラメータ:

パラメータ必須説明
productIdstring一意の製品識別子

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring製品名
descriptionstring製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: パスパラメータ検証(productId必須)
  • ルートバリデーション: なし

リクエスト例:

curl {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}

エラーレスポンス:

指定IDの製品が存在しない場合:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Product not found"
}
}

3. 製品一覧

フィルタやページングを指定して製品の一覧を取得します。

リクエスト:

  • メソッド: GET
  • パス: /products
  • 認可: 不要

クエリパラメータ:

パラメータ必須説明
namestring製品名でフィルタ
descriptionstring製品説明でフィルタ
pagenumberページングのページ番号
limitnumber1ページあたりの件数

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring製品名
descriptionstring製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: クエリパラメータ検証(オプションのname、description、page、limit)
  • ルートバリデーション: なし

リクエスト例:

全件取得:

curl {{host}}/products

製品名でフィルタ:

curl "{{host}}/products?name=Premium%20Widget"

ページング指定:

curl "{{host}}/products?page=1&limit=10"

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

[
{
"name": "Premium Widget",
"description": "Updated high-quality widget for enterprise use",
"createdAt": "2025-06-24T06:39:17.101Z",
"id": "3d0e4b74-398c-43e2-a7b4-c9a180477322",
"updatedAt": "2025-06-24T06:39:17.101Z"
},
{
"name": "Product A",
"description": "Updated batch description",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "0e0dd6c7-c3d5-49e5-a1d8-20daa34d380a",
"updatedAt": "2025-06-24T06:39:55.720Z"
},
{
"name": "Product B",
"description": "Updated batch description",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "d5a60fdf-2a22-4fcc-8e40-a68cb89cce72",
"updatedAt": "2025-06-24T06:39:55.720Z"
}
]

4. 製品更新

部分更新で既存の製品を更新します。

リクエスト:

  • メソッド: PATCH
  • パス: /products/:productId
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

URL パラメータ:

パラメータ必須説明
productIdstring一意の製品識別子

リクエストボディ(全フィールド任意):

フィールド必須説明
namestring製品名
descriptionstring製品説明

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring更新後の製品名
descriptionstring更新後の製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: 自動強制(部分更新、全フィールド任意、追加プロパティ不許可)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X PATCH {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{"description": "Updated high-quality widget for enterprise use"}'

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "Updated high-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T14:22:15.789Z"
}

エラーレスポンス:

指定IDの製品が存在しない場合:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Product not found"
}
}

5. 製品削除

システムから製品を完全に削除します。

リクエスト:

  • メソッド: DELETE
  • パス: /products/:productId
  • ヘッダー: Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

URL パラメータ:

パラメータ必須説明
productIdstring一意の製品識別子

レスポンスボディ:

フィールド説明
なし-成功時はレスポンスボディなし

バリデーション:

  • スキーマ検証: パスパラメータ検証(productId必須)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X DELETE {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

HTTP/1.1 204 No Content

エラーレスポンス:

指定IDの製品が存在しない場合:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Product not found"
}
}

6. 製品コピー

既存の製品のコピーを新しいIDで作成します。

リクエスト:

  • メソッド: POST
  • パス: /products/:productId/copy
  • ヘッダー: Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

URL パラメータ:

パラメータ必須説明
productIdstringコピーする製品のID

レスポンスボディ:

フィールド説明
idstringコピーされた製品の一意識別子
namestring製品名(オリジナルからコピー)
descriptionstring製品説明(オリジナルからコピー)
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: パスパラメータ検証(productId必須)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X POST {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/copy \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "9abc123f-1cd8-4def-b123-456789abcdef",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T15:30:45.123Z",
"updatedAt": "2024-05-28T15:30:45.123Z"
}

エラーレスポンス:

指定IDの製品が存在しない場合:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Product not found"
}
}

🔄 バッチ製品操作

製品サービスは、複数の製品を効率的に管理するための強力なバッチ操作を提供します。

7. 複数製品作成

単一のリクエストで複数の製品を作成します。

リクエスト:

  • メソッド: POST
  • パス: /products/batch
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

リクエストボディ: 各々が namedescription を必要とする製品オブジェクトの配列。

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring製品名
descriptionstring製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: 自動強制(必須のnameおよびdescriptionを含む製品オブジェクトの配列)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X POST {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
{
"name": "Product A",
"description": "Description for Product A"
},
{
"name": "Product B",
"description": "Description for Product B"
}
]'

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

[
{
"name": "Product A",
"description": "Description for Product A",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "0e0dd6c7-c3d5-49e5-a1d8-20daa34d380a",
"updatedAt": "2025-06-24T06:39:45.378Z"
},
{
"name": "Product B",
"description": "Description for Product B",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "d5a60fdf-2a22-4fcc-8e40-a68cb89cce72",
"updatedAt": "2025-06-24T06:39:45.378Z"
}
]

8. 複数製品更新

単一のリクエストで複数の製品を同じデータで更新します。

リクエスト:

  • メソッド: PATCH
  • パス: /products/batch
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

リクエストボディ:

フィールド必須説明
idsarray of strings更新する製品IDの配列
dataobject全製品に適用する更新データ
data.namestring新しい製品名
data.descriptionstring新しい製品説明

レスポンスボディ:

フィールド説明
idstring一意の製品識別子
namestring更新後の製品名
descriptionstring更新後の製品説明
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: 自動強制(ids配列とdataオブジェクト必須)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X PATCH {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"ids": [
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
],
"data": {
"description": "Updated batch description"
}
}'

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

[
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Product A",
"description": "Updated batch description",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T15:45:12.789Z"
},
{
"id": "8fec096b-1bc7-5bfe-c827-3600e8fe2790",
"name": "Product B",
"description": "Updated batch description",
"createdAt": "2024-05-28T09:41:23.123Z",
"updatedAt": "2024-05-28T15:45:12.789Z"
}
]

9. 複数製品削除

単一のリクエストで複数の製品を削除します。

リクエスト:

  • メソッド: DELETE
  • パス: /products/batch
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

リクエストボディ: 削除する製品IDの配列。

レスポンスボディ:

フィールド説明
なし-成功時はレスポンスボディなし

バリデーション:

  • スキーマ検証: 自動強制(文字列の配列)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X DELETE {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
]'

成功レスポンス:

HTTP/1.1 204 No Content

10. 複数製品コピー

単一のリクエストで複数の製品のコピーを作成します。

リクエスト:

  • メソッド: POST
  • パス: /products/batch/copy
  • ヘッダー: Content-Type: application/json, Authorization: Bearer <access-token>
  • 認可: ベアラートークン必須(管理者のみ)

リクエストボディ: コピーする製品IDの配列。

レスポンスボディ:

フィールド説明
idstringコピーされた製品の一意識別子
namestring製品名(オリジナルからコピー)
descriptionstring製品説明(オリジナルからコピー)
createdAtstring作成日時
updatedAtstring最終更新日時

バリデーション:

  • スキーマ検証: 自動強制(文字列の配列)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl -X POST {{host}}/products/batch/copy \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
]'

成功レスポンス:

HTTP/1.1 200 OK
Content-Type: application/json

[
{
"id": "9abc123f-1cd8-4def-b123-456789abcdef",
"name": "Product A",
"description": "Description for Product A",
"createdAt": "2024-05-28T16:00:00.000Z",
"updatedAt": "2024-05-28T16:00:00.000Z"
},
{
"id": "def456a1-2e3f-4567-8901-23456789bcde",
"name": "Product B",
"description": "Description for Product B",
"createdAt": "2024-05-28T16:00:00.100Z",
"updatedAt": "2024-05-28T16:00:00.100Z"
}
]

11. 製品画像アップロードURL取得

製品画像を安全にアップロードするための署名付きURLを生成します。オブジェクトIDと一時的な署名付きURLを返します。

リクエスト:

  • メソッド: GET
  • パス: /products/:productId/image-upload-url
  • ヘッダー: Authorization: Bearer <token>
  • 認可: ベアラートークン必須(管理者のみ)

URL パラメータ:

パラメータ必須説明
productIdstring対象製品ID

クエリパラメータ:

パラメータ必須説明
contentTypestring画像MIMEタイプ(例: image/png
contentLengthnumberファイルサイズ(バイト単位、最大10MB)

レスポンスボディ:

フィールド説明
objectIdstring製品画像用の生成されたストレージオブジェクトID
urlstringファイルをアップロードするための署名付きURL

バリデーション:

  • スキーマ検証: 画像アップロードスキーマを使用(コンテンツタイプとサイズ制約)
  • ルートバリデーション:
    • 認証済みリクエスト(ベアラー)必須
    • 管理者ロール必須

リクエスト例:

curl "{{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/image-upload-url?contentType=image/webp&contentLength=2097152" \
-H "Authorization: Bearer <access-token>"

成功レスポンス:

{
"objectId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"url": "https://storage.googleapis.com/bucket/products/...&X-Goog-Expires=900&X-Goog-Signature=..."
}

⚙️ 設定オプション

サービス設定

interface ProductServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT 暗号化シークレット
authSignSecret: string; // JWT 署名シークレット
};
identity?: {
typeIds?: {
admin: string; // 管理者ユーザー種別識別子
guest: string; // ゲストユーザー種別識別子
regular: string; // 一般ユーザー種別識別子
};
};
}

設定詳細

製品サービスの設定は、セキュリティおよびユーザー種別管理の論理グループに整理されています。

🔐 セキュリティ設定

authSecrets - JWT トークンのセキュリティシークレット

  • : { authEncSecret: string; authSignSecret: string }
  • 説明: JWT の暗号化および署名に使用する秘密鍵(トークン検証に使用)
  • 必須: 本番環境では必須
  • 子プロパティ:
    • authEncSecret: JWT ペイロード暗号化の秘密鍵
    • authSignSecret: JWT 署名検証の秘密鍵

👥 ユーザー種別設定

user.typeIds - ユーザー種別識別子の設定

  • : { admin?: string; guest?: string; user?: string }
  • 説明: ロールベースアクセス制御のためのカスタムユーザー種別識別子
  • デフォルト: undefined(デフォルトの種別検証を使用)
  • 子プロパティ:
    • admin: 管理者ユーザー種別の識別子
      • : string
      • 説明: 管理者ユーザーのカスタム識別子
      • 利用例: 管理操作のロールベースアクセス制御
      • : "admin", "administrator", "superuser"
    • guest: ゲストユーザー種別の識別子
      • : string
      • 説明: ゲストユーザーのカスタム識別子
      • 利用例: 未認証/一時ユーザーの限定的アクセス
      • : "guest", "visitor", "anonymous"
    • user: 一般ユーザー種別の識別子
      • : string
      • 説明: 一般ユーザーのカスタム識別子
      • 利用例: 標準的なユーザー権限
      • : "user", "member", "customer"

設定例

const productConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
user: {
typeIds: {
admin: '100',
guest: '000',
user: '001'
}
}
};

🚨 エラーハンドリング

製品サービスのエラーは、適切なHTTPステータスコードとJSON形式で返されます:

代表的なエラーコード

ステータスエラーメッセージ説明
400Validation Errorリクエストボディ形式が無効または必須フィールドがない
400Failed to create productデータベース挿入操作が挿入されたIDを返せなかった
400Failed to update product更新操作でデータが変更されない(変更なし)
400Failed to create productsバッチ作成操作が失敗した
400Failed to update productsバッチ更新操作が失敗した
400Failed to delete productsバッチ削除操作が失敗した
400Failed to copy product製品コピー操作が失敗した
400Failed to copy productsバッチコピー操作が失敗した
401token could not be verified認可トークンがない/無効
403User is not authorized to access this resource必要な権限がない(管理者アクセス)
404Product not found要求された操作の対象製品が存在しない
500Failed to create product作成中のDB接続問題/予期せぬ失敗
500Failed to get product取得中のDB接続問題/予期せぬ失敗
500Failed to find products一覧取得中のDB接続問題/フィルタ構文不正/予期せぬ失敗
500Failed to update product更新中のDB接続問題/予期せぬ失敗
500Failed to delete product削除中のDB接続問題/予期せぬ失敗
500Failed to copy productコピー中のDB接続問題/予期せぬ失敗

エラーレスポンス形式

{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}

検証エラーには追加の詳細が含まれます:

{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'name'",
"request body must have required property 'description'"
]
}
}

🔗 関連ドキュメント