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

🛒 注文サービス

Testing Status

Order Serviceは、CRUD操作で注文エンティティを管理するための完全なREST APIを提供します。Nodeblocksの関数型コンポジションアプローチを使用して構築され、MongoDBとシームレスに統合されます。


🚀 クイックスタート

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

const { nodeBlocksErrorMiddleware } = middlewares;
const { orderService } = services;
const { withMongo } = drivers;

const connectToDatabase = withMongo('mongodb://localhost:27017', 'dev', 'user', 'password');

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

📋 エンドポイント概要

注文操作

MethodPath説明認証が必要
POST/orders新しい注文を作成✅ 必須
GET/orders/:orderIdIDで注文を取得✅ 必須
GET/orders注文をリスト/フィルタ✅ 必須
GET/orders/organizations/:organizationId組織の注文をリスト✅ 必須
PATCH/orders/:orderId注文を更新✅ 必須
DELETE/orders/:orderId注文を削除✅ 必須

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

注文エンティティは、基本フィールド(自動生成)とアイテム配列や価格設定を含む複雑な注文固有のデータを組み合わせます:

{
"items": [
{
"productId": "string (uuid)",
"quantity": "number",
"price": "number"
}
],
"total": "number",
"subtotal": "number",
"tax": "number",
"currency": "string",
"status": "string",
"identityId": "string (uuid)",
"organizationId": "string (uuid)",
"createdAt": "string (datetime)",
"id": "string",
"updatedAt": "string (datetime)"
}

フィールド詳細

FieldType自動生成必須説明
itemsarray商品詳細を含む注文アイテムの配列
totalnumber注文合計金額(最小値0)
subtotalnumber税込前小計(最小値0)
taxnumber税額(最小値0)
currencystring通貨コード(例:"USD"、"EUR")
statusstring注文ステータス(例:"pending"、"completed")
identityIdstring (uuid)注文を出したアイデンティティ
organizationIdstring (uuid)注文に関連付けられた組織
createdAtdatetime作成タイムスタンプ
idstring一意の識別子(UUID)
updatedAtdatetime最終更新タイムスタンプ

アイテム配列スキーマ

items配列の各アイテムには以下が含まれている必要があります:

FieldType必須Validation説明
productIdstring (uuid)UUID形式商品識別子
quantitynumber最小値1注文数量
pricenumber最小値0単価

📝 注記: スキーマはadditionalProperties: falseを強制するため、定義されたフィールドのみが許可されます。自動生成フィールドはサービスによって設定され、作成/更新リクエストに含めるべきではありません。


🔐 認証ヘッダー

すべてのエンドポイントで、次のヘッダーを含めてください:

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

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


🔧 APIエンドポイント

1. 注文の作成

提供された情報でアイテム配列と価格詳細を含む新しい注文を作成します。

リクエスト:

  • Method: POST
  • Path: /orders
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要

リクエストボディ:

FieldType必須説明
itemsarray注文アイテムの配列(アイテムスキーマを参照)
totalnumber注文合計金額
identityIdstring (uuid)注文を出したアイデンティティ
subtotalnumber税込前小計
taxnumber税額
currencystring通貨コード
statusstring注文ステータス
organizationIdstring (uuid)注文に関連付けられた組織

レスポンスボディ:

FieldType説明
itemsarray商品詳細を含む注文アイテムの配列
items[].productIdstring商品識別子
items[].quantitynumber注文数量
items[].pricenumber単価
totalnumber注文合計金額
subtotalnumber税込前小計
taxnumber税額
currencystring通貨コード
statusstring注文ステータス
identityIdstring注文を出したアイデンティティ
organizationIdstring注文に関連付けられた組織
createdAtstring作成タイムスタンプ
idstring一意の注文識別子
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: 自動的に強制されます(items、total、identityId必須)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは自己(注文所有者)が必要

認可に関する注意: 注文を作成する際、リクエストボディのidentityIdフィールドは、アクセストークンに関連付けられたidentityId一致する必要があります。別のアイデンティティの注文を作成しようとすると、403 Forbiddenエラーが返されます。

管理者ユーザーは、バックエンドのバリデーターロジックを変更してこれを許可しない限り、他のユーザーの注文を作成できません。

リクエスト例:

curl -X POST http://localhost:8089/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{
"identityId": "30000000-0000-4000-a000-000000000001",
"items": [
{
"productId": "10000000-0000-4000-a000-000000000001",
"quantity": 2,
"price": 50
},
{
"productId": "10000000-0000-4000-a000-000000000002",
"quantity": 1,
"price": 25
}
],
"subtotal": 125,
"tax": 12.5,
"total": 137.5,
"currency": "USD",
"status": "pending",
"organizationId": "20000000-0000-4000-a000-000000000001"
}'

成功レスポンス:

HTTP/1.1 201 Created
Content-Type: application/json

{
"currency": "USD",
"items": [
{
"productId": "10000000-0000-4000-a000-000000000001",
"quantity": 2,
"price": 50
},
{
"productId": "10000000-0000-4000-a000-000000000002",
"quantity": 1,
"price": 25
}
],
"organizationId": "20000000-0000-4000-a000-000000000001",
"identityId": "30000000-0000-4000-a000-000000000001",
"subtotal": 125,
"tax": 12.5,
"total": 137.5,
"status": "pending",
"createdAt": "2025-07-04T01:59:20.084Z",
"id": "10283907-d41a-4647-a235-18ec63f3369a",
"updatedAt": "2025-07-04T01:59:20.084Z"
}

エラーレスポンス:

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

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

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

認証が失敗した場合:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": {
"message": "token could not be verified"
}
}

認可が失敗した場合:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "User is not authorized to access this order"
}
}

2. IDで注文を取得

一意のIDで特定の注文を取得します。

リクエスト:

  • Method: GET
  • Path: /orders/:orderId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要

URLパラメータ:

ParameterType必須説明
orderIdstring一意の注文識別子

レスポンスボディ:

FieldType説明
itemsarray商品詳細を含む注文アイテムの配列
items[].productIdstring商品識別子
items[].quantitynumber注文数量
items[].pricenumber単価
totalnumber注文合計金額
subtotalnumber税込前小計
taxnumber税額
currencystring通貨コード
statusstring注文ステータス
identityIdstring注文を出したアイデンティティ
organizationIdstring注文に関連付けられた組織
createdAtstring作成タイムスタンプ
idstring一意の注文識別子
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: なし(GETリクエスト)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは注文所有権が必要

リクエスト例:

curl http://localhost:8089/orders/10283907-d41a-4647-a235-18ec63f3369a \
-H "Authorization: Bearer <access_token>"

成功レスポンス:

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

{
"currency": "USD",
"items": [
{
"productId": "10000000-0000-4000-a000-000000000001",
"quantity": 2,
"price": 50
},
{
"productId": "10000000-0000-4000-a000-000000000002",
"quantity": 1,
"price": 25
}
],
"organizationId": "20000000-0000-4000-a000-000000000001",
"identityId": "30000000-0000-4000-a000-000000000001",
"subtotal": 125,
"tax": 12.5,
"total": 137.5,
"status": "completed",
"createdAt": "2025-07-04T01:59:20.084Z",
"id": "10283907-d41a-4647-a235-18ec63f3369a",
"updatedAt": "2025-07-07T08:11:16.176Z"
}

エラーレスポンス:

指定されたIDの注文が存在しない場合:

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

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

3. 注文のリスト取得

オプションのフィルタリングとページネーションで注文のリストを取得します。

リクエスト:

  • Method: GET
  • Path: /orders
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要

クエリパラメータ:

ParameterType必須説明
currencystring通貨でフィルタ
organizationIdstring組織でフィルタ
statusstringステータスでフィルタ
subtotalnumber小計でフィルタ(最小値0)
taxnumber税額でフィルタ(最小値0)
totalnumber合計金額でフィルタ(最小値0)
identityIdstringidentityIdでフィルタ
pagenumberページネーションのページ番号(1-1000)
limitnumberページあたりの項目数(1-50)

レスポンスボディ: 注文配列とメタデータを含むページネーション付きレスポンス。

レスポンス構造:

{
"data": [
{
"id": "string",
"items": [
{
"productId": "string",
"quantity": number,
"price": number
}
],
"total": number,
"subtotal": number,
"tax": number,
"currency": "string",
"status": "string",
"identityId": "string",
"organizationId": "string",
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}

バリデーション:

  • スキーマバリデーション: なし(GETリクエスト)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは自己が必要

リクエスト例:

すべての注文をリスト:

curl http://localhost:8089/orders \
-H "Authorization: Bearer <access_token>"

ステータスでフィルタ:

curl "http://localhost:8089/orders?status=completed" \
-H "Authorization: Bearer <access_token>"

通貨でフィルタ:

curl "http://localhost:8089/orders?currency=USD" \
-H "Authorization: Bearer <access_token>"

成功レスポンス:

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

{
"data": [
{
"currency": "USD",
"items": [
{
"productId": "10000000-0000-4000-a000-000000000001",
"quantity": 2,
"price": 50
},
{
"productId": "10000000-0000-4000-a000-000000000002",
"quantity": 1,
"price": 25
}
],
"organizationId": "20000000-0000-4000-a000-000000000001",
"identityId": "30000000-0000-4000-a000-000000000001",
"subtotal": 125,
"tax": 12.5,
"total": 137.5,
"status": "completed",
"createdAt": "2025-07-04T01:59:20.084Z",
"id": "10283907-d41a-4647-a235-18ec63f3369a",
"updatedAt": "2025-07-07T08:11:16.176Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 1,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}

ページネーション付きリクエスト例:

curl "http://localhost:8089/orders?page=1&limit=10" \
-H "Authorization: Bearer <access_token>"

4. 注文の更新

部分的なデータで既存の注文を更新します。

リクエスト:

  • Method: PATCH
  • Path: /orders/:orderId
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要

URLパラメータ:

ParameterType必須説明
orderIdstring一意の注文識別子

リクエストボディ(すべてのフィールドはオプション):

FieldType必須説明
itemsarray注文アイテムの配列
totalnumber注文合計金額
subtotalnumber税込前小計
taxnumber税額
currencystring通貨コード
statusstring注文ステータス
identityIdstring (uuid)注文を出したアイデンティティ
organizationIdstring (uuid)注文に関連付けられた組織

レスポンスボディ:

FieldType説明
itemsarray商品詳細を含む注文アイテムの配列
items[].productIdstring商品識別子
items[].quantitynumber注文数量
items[].pricenumber単価
totalnumber更新された注文合計金額
subtotalnumber更新された税込前小計
taxnumber更新された税額
currencystring更新された通貨コード
statusstring更新された注文ステータス
identityIdstring注文を出したアイデンティティ
organizationIdstring更新された注文に関連付けられた組織
createdAtstring作成タイムスタンプ
idstring一意の注文識別子
updatedAtstring最終更新タイムスタンプ

バリデーション:

  • スキーマバリデーション: 自動的に強制されます(部分更新、すべてのフィールドはオプション)
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは注文所有権が必要

リクエスト例:

curl -X PATCH http://localhost:8089/orders/10283907-d41a-4647-a235-18ec63f3369a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"status": "completed"}'

成功レスポンス:

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

{
"currency": "USD",
"items": [
{
"productId": "10000000-0000-4000-a000-000000000001",
"quantity": 2,
"price": 50
},
{
"productId": "10000000-0000-4000-a000-000000000002",
"quantity": 1,
"price": 25
}
],
"organizationId": "20000000-0000-4000-a000-000000000001",
"identityId": "30000000-0000-4000-a000-000000000001",
"subtotal": 125,
"tax": 12.5,
"total": 137.5,
"status": "completed",
"createdAt": "2025-07-04T01:59:20.084Z",
"id": "10283907-d41a-4647-a235-18ec63f3369a",
"updatedAt": "2025-07-07T08:11:16.176Z"
}

エラーレスポンス:

指定されたIDの注文が存在しない場合:

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

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

5. 注文の削除

システムから注文を永続的に削除します。

リクエスト:

  • Method: DELETE
  • Path: /orders/:orderId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要

URLパラメータ:

ParameterType必須説明
orderIdstring一意の注文識別子

レスポンスボディ:

FieldType説明
レスポンスボディなし-削除エンドポイントは成功時にレスポンスボディを返しません

バリデーション:

  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • 管理者ロールまたは注文所有権が必要

リクエスト例:

curl -X DELETE http://localhost:8089/orders/10283907-d41a-4647-a235-18ec63f3369a \
-H "Authorization: Bearer <access_token>"

成功レスポンス:

HTTP/1.1 204 No Content

エラーレスポンス:

指定されたIDの注文が存在しない場合:

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

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

6. 組織IDで注文をリスト

組織メンバーシップとロール権限に基づく自動アクセス制御により、特定の組織にスコープされた注文のページネーション付きリストを取得します。

リクエスト:

  • Method: GET
  • Path: /orders/organizations/:organizationId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearerトークンが必要(owner/admin/memberロールを持つ組織メンバー)

URLパラメータ:

ParameterType必須説明
organizationIdstring注文を取得する組織の一意の識別子

クエリパラメータ:

ParameterType必須説明
pagenumberページネーションのページ番号(1-1000)
limitnumberページあたりの項目数(1-50)

レスポンスボディ: 注文配列とメタデータを含むページネーション付きレスポンス。

レスポンス構造:

{
"data": [
{
"id": "string",
"items": [
{
"productId": "string",
"quantity": number,
"price": number
}
],
"total": number,
"subtotal": number,
"tax": number,
"currency": "string",
"status": "string",
"identityId": "string",
"organizationId": "string",
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}

バリデーション:

  • スキーマバリデーション: 組織IDパスパラメータとページネーションクエリパラメータ
  • ルートバリデーター:
    • 認証済みリクエストが必要(bearerトークン)
    • owner、admin、またはmemberロールを持つ組織メンバーシップが必要

リクエスト例:

curl "http://localhost:8089/orders/organizations/org-123?page=1&limit=10" \
-H "Authorization: Bearer <token>" \
-H "x-nb-fingerprint: <device-fingerprint>"

成功レスポンス:

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

{
"data": [
{
"id": "order-456",
"organizationId": "org-123",
"currency": "USD",
"status": "confirmed",
"items": [
{
"productId": "prod-789",
"quantity": 2,
"price": 29.99
}
],
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 1,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}

エラーレスポンス:

Unauthorized (401):

{
"error": {
"message": "token could not be verified"
}
}

Forbidden (403):

{
"error": {
"message": "Identity is not a member of the organization"
}
}

Internal Server Error (500):

{
"error": {
"message": "Failed to find orders"
}
}

ユースケース:

  • 組織管理者が組織のすべての注文を表示
  • 組織固有の注文データの財務レポートと分析
  • カスタマーサービスチームが組織内の注文履歴にアクセス
  • 組織スコープのデータアクセスに関するコンプライアンスと監査要件

⚙️ 設定オプション

サービス設定

interface OrderServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT encryption secret
authSignSecret: string; // JWT signing secret
};
identity?: {
typeIds?: {
admin: string; // Admin user type identifier
guest: string; // Guest user type identifier
regular: string; // Regular user type identifier
};
};
}

設定詳細

注文サービスの設定は、セキュリティとユーザータイプ管理のための論理的なグループに整理されています。

🔐 セキュリティ設定

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

  • Type: { authEncSecret: string; authSignSecret: string }
  • 説明: JWT暗号化と署名のためのシークレットキー(トークン検証に使用)
  • 必須: はい(本番環境の場合)
  • 子プロパティ:
    • authEncSecret: JWTペイロード暗号化のためのシークレットキー
    • authSignSecret: JWT署名検証のためのシークレットキー

👥 ユーザータイプ設定

identity.typeIds - ユーザータイプ識別子設定

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

設定例

const orderConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
identity: {
typeIds: {
admin: 'administrator',
guest: 'visitor',
regular: 'member'
}
}
};

🚨 エラーハンドリング

すべての注文サービスエラーは、適切なHTTPステータスコードと共にJSON形式で返されます:

一般的なエラーコード

StatusError Message説明
400Validation Error無効なリクエストボディ形式または必須フィールドの欠落
400request body must have required property 'identityId'リクエストボディにidentityIdフィールドがない
400request body must have required property 'items'リクエストボディにitems配列がない
400request body must have required property 'total'リクエストボディにtotalフィールドがない
400request body must NOT have additional propertiesリクエストにサポートされていないフィールドが含まれている
400Failed to create orderデータベース挿入操作が挿入されたIDを返さなかった
400Failed to update order更新操作がデータを変更しなかった(変更が検出されなかった)
400Failed to delete orderデータベース削除操作が失敗した
401token could not be verified認証トークンが欠落しているか無効
401Authentication failed認証トークンが欠落しているか無効
401Token fails security checkトークンのセキュリティ検証が失敗しました
403User is not authorized to access this orderユーザーに必要な権限がありません(管理者/所有者アクセス)
403User is not authorized to access this resourceユーザーに必要な権限がありません(管理者アクセス)
404Order not foundリクエストされた操作に対して注文が存在しません
500Failed to create order作成中のデータベース接続の問題または予期しない失敗
500Failed to get order取得中のデータベース接続の問題または予期しない失敗
500Failed to find ordersリスト取得中のデータベース接続の問題、無効なフィルタ構文、または予期しない失敗
500Failed to update order更新中のデータベース接続の問題または予期しない失敗
500Failed to delete order削除中のデータベース接続の問題または予期しない失敗

エラーレスポンス形式

{
"error": {
"message": "エラーメッセージの説明",
"data": ["追加のエラー詳細"]
}
}

バリデーションエラーには追加の詳細が含まれます:

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

🔗 関連ドキュメント