🏷️ 属性サービス
Attribute Serviceは、キーと値のペアを持つ属性グループを管理するための完全なREST APIを提供します。Nodeblocksの関数型コンポジションアプローチとMongoDB統合を使用して、製品属性、カテゴリプロパティ、その他の構造化メタデータを処理するように設計されています。
🚀 クイックスタート
import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { attributesService } = services;
const { withMongo } = drivers;
const connectToDatabase = withMongo('mongodb://localhost:27017', 'dev', 'user', 'password');
express()
.use(
attributesService(
{
...(await connectToDatabase('attributes')),
...(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'));
📋 エンドポイント概要
属性グループ操作
| Method | Path | 説明 | 認証が必要 |
|---|---|---|---|
POST | /attributes | 新しい属性グループを作成 | ✅ Admin |
GET | /attributes/:attributeId | IDで属性グループを取得 | ❌ None |
GET | /attributes | 属性グループをリスト/フィルタ | ❌ None |
PATCH | /attributes/:attributeId | 属性グループを更新 | ✅ Admin |
DELETE | /attributes/:attributeId | 属性グループを削除 | ✅ Admin |
🗄️ エンティティスキーマ
属性グループエンティティは、基本フィールド(自動生成)と属性固有のデータを組み合わせたものです:
{
"name": "string",
"items": [
{
"key": "string",
"value": "string"
}
],
"createdAt": "string (datetime)",
"id": "string",
"updatedAt": "string (datetime)"
}
フィールド詳細
| Field | Type | 自動生成 | 必須 | 説明 |
|---|---|---|---|---|
name | string | ❌ | ✅ | 属性グループ名 |
items | array | ❌ | ✅ | キーと値のペアの配列(最小1項目) |
items[].key | string | ❌ | ✅ | 属性キー/名前 |
items[].value | string | ❌ | ✅ | 属性値 |
createdAt | datetime | ✅ | ✅ | 作成タイムスタンプ |
id | string | ✅ | ✅ | 一意の識別子(UUID) |
updatedAt | datetime | ✅ | ✅ | 最終更新タイムスタンプ |
📝 注意: 自動生成フィールドはサービスによって設定され、作成/更新リクエストに含めるべきではありません。
items配列には少なくとも1つのキーと値のペアが含まれている必要があります。
🔐 認証ヘッダー
保護されたエンドポイントでは、次のヘッダーを含めてください:
Authorization: Bearer <admin_access_token>
x-nb-fingerprint: <device_fingerprint>
⚠️ 重要:
x-nb-fingerprintヘッダーは、認証時にフィンガープリントが指定された場合、すべての認証済みリクエストで必須です。これがない場合、リクエストは401 Unauthorizedを返します。
🔧 APIエンドポイント
1. 属性グループの作成
提供された名前とキーと値のペアで新しい属性グループを作成します。
リクエスト:
- Method:
POST - Path:
/attributes - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- Authorization: 管理者ロールが必要
リクエストボディ:
| Field | Type | 必須 | 説明 |
|---|---|---|---|
name | string | ✅ | 属性グループ名 |
items | array | ✅ | キーと値のペアの配列(最小1項目) |
items[].key | string | ✅ | 属性キー/名前 |
items[].value | string | ✅ | 属性値 |
レスポンスボディ:
| Field | Type | 説明 |
|---|---|---|
name | string | 属性グループ名 |
items | array | キーと値のペアの配列 |
items[].key | string | 属性キー/名前 |
items[].value | string | 属性値 |
createdAt | string | 作成タイムスタンプ |
id | string | 一意の属性グループ識別子 |
updatedAt | string | 最終更新タイムスタンプ |
バリデーション:
-
スキーマバリデーション: 自動的に強制されます(name、items必須、追加プロパティなし)
-
ルートバリデーター:
- 認証済みリクエストが必要(bearerトークン)
- 管理者ロールが必要
-
アイテムバリデーション: 少なくとも1項目を含み、それぞれに必須のキーと値が必要
リクエスト例:
curl -X POST {{host}}/attributes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin_token>" \
-H "x-nb-fingerprint: test-device-fingerprint" \
-d '{
"name": "Product Specifications",
"items": [
{
"key": "Color",
"value": "Blue"
},
{
"key": "Size",
"value": "Large"
},
{
"key": "Material",
"value": "Cotton"
}
]
}'
成功レスポンス:
HTTP/1.1 201 Created
Content-Type: application/json
{
"name": "Product Specifications",
"items": [
{
"key": "Color",
"value": "Blue"
},
{
"key": "Size",
"value": "Large"
},
{
"key": "Material",
"value": "Cotton"
}
],
"createdAt": "2025-07-07T08:52:49.796Z",
"id": "69b013c9-cb20-4a7e-9c1f-59a55db1d949",
"updatedAt": "2025-07-07T08:52:49.796Z"
}
エラーレスポンス:
必須フィールドがリクエストボディにない場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'items'"
]
}
}
items配列が空の場合:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must NOT have fewer than 1 items"
]
}
}
認証が失敗した場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
2. IDで属性グループを取得
一意のIDで特定の属性グループを取得します。
リクエスト:
- Method:
GET - Path:
/attributes/:attributeId - Headers: なし
- Authorization: 不要
URLパラメータ:
| Parameter | Type | 必須 | 説明 |
|---|---|---|---|
attributeId | string | ✅ | 一意の属性グループ識別子 |
レスポンスボディ:
| Field | Type | 説明 |
|---|---|---|
name | string | 属性グループ名 |
items | array | キーと値のペアの配列 |
items[].key | string | 属性キー/名前 |
items[].value | string | 属性値 |
createdAt | string | 作成タイムスタンプ |
id | string | 一意の属性グループ識別子 |
updatedAt | string | 最終更新タイムスタンプ |
バリデーション:
- スキーマバリデーション: attributeIdのパスパラメータ検証
- ルートバリデーター: なし
リクエスト例:
curl {{host}}/attributes/69b013c9-cb20-4a7e-9c1f-59a55db1d949
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"name": "Product Specifications",
"items": [
{
"key": "Color",
"value": "Blue"
},
{
"key": "Size",
"value": "Large"
},
{
"key": "Material",
"value": "Cotton"
}
],
"createdAt": "2025-07-07T08:52:49.796Z",
"id": "69b013c9-cb20-4a7e-9c1f-59a55db1d949",
"updatedAt": "2025-07-07T08:52:49.796Z"
}
エラーレスポンス:
提供されたIDの属性グループが存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
3. 属性グループのリスト取得
オプションのフィルタリングとページネーションを使用して属性グループのリストを取得します。
リクエスト:
- Method:
GET - Path:
/attributes - Headers: なし
- Authorization: 不要
クエリパラメータ:
| Parameter | Type | 必須 | 説明 |
|---|---|---|---|
name | string | ❌ | 属性グループ名でフィルタ |
page | number | ❌ | ページネーションのページ番号(1-1000) |
limit | number | ❌ | ページあたりの項目数(1-50) |
レスポンスボディ: 属性グループの配列とメタデータを含むページネーション付きレスポンス。
レスポンス構造:
{
"data": [
{
"name": "string",
"items": [
{
"key": "string",
"value": "string"
}
],
"createdAt": "string",
"id": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}
バリデーション:
- スキーマバリデーション: 名前とページネーション(page、limit)のクエリパラメータ検証
- ルートバリデーター: なし
リクエスト例:
すべての属性グループをリスト:
curl {{host}}/attributes
名前でフィルタ:
curl "{{host}}/attributes?name=Product"
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"name": "Product Specifications",
"items": [
{
"key": "Color",
"value": "Blue"
},
{
"key": "Size",
"value": "Large"
}
],
"createdAt": "2025-07-07T08:52:49.796Z",
"id": "69b013c9-cb20-4a7e-9c1f-59a55db1d949",
"updatedAt": "2025-07-07T08:52:49.796Z"
},
{
"name": "Technical Details",
"items": [
{
"key": "Weight",
"value": "2.5kg"
},
{
"key": "Dimensions",
"value": "30x20x15cm"
}
],
"createdAt": "2025-07-07T08:20:45.456Z",
"id": "b2c3d4e5-f6g7-8901-bcde-f23456789012",
"updatedAt": "2025-07-07T08:20:45.456Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 2,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}
ページネーション付きリクエスト例:
curl "{{host}}/attributes?page=1&limit=10"
4. 属性グループの更新
既存の属性グループを更新します。注意: スキーマによると、nameフィールドのみを更新できます - items配列は更新エンドポイントを通じて変更できません。
リクエスト:
- Method:
PATCH - Path:
/attributes/:attributeId - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- Authorization: 管理者ロールが必要
URLパラメータ:
| Parameter | Type | 必須 | 説明 |
|---|---|---|---|
attributeId | string | ✅ | 一意の属性グループ識別子 |
リクエストボディ:
| Field | Type | 必須 | 説明 |
|---|---|---|---|
name | string | ❌ | 新しい属性グループ名 |
レスポンスボディ:
| Field | Type | 説明 |
|---|---|---|
name | string | 更新された属性グループ名 |
items | array | キーと値のペアの配列(変更なし) |
items[].key | string | 属性キー/名前 |
items[].value | string | 属性値 |
createdAt | string | 作成タイムスタンプ |
id | string | 一意の属性グループ識別子 |
updatedAt | string | 最終更新タイムスタンプ |
バリデーション:
- スキーマバリデーション: 自動的に強制されます(nameフィールドのみ許可、追加プロパティなし)
- ルートバリデーター:
- 認証済みリクエストが必要(bearerトークン)
- 管理者ロールが必要
⚠️ 重要: 更新スキーマでは
nameフィールドのみの更新が許可されています。items配列を変更するには、属性グループを削除して再作成する必要があります。
リクエスト例:
curl -X PATCH {{host}}/attributes/69b013c9-cb20-4a7e-9c1f-59a55db1d949 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin_token>" \
-H "x-nb-fingerprint: test-device-fingerprint" \
-d '{"name": "Updated Product Specifications"}'
成功レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
{
"name": "Updated Product Specifications",
"items": [
{
"key": "Color",
"value": "Blue"
},
{
"key": "Size",
"value": "Large"
},
{
"key": "Material",
"value": "Cotton"
}
],
"createdAt": "2025-07-07T08:52:49.796Z",
"id": "69b013c9-cb20-4a7e-9c1f-59a55db1d949",
"updatedAt": "2025-07-07T08:54:07.406Z"
}
エラーレスポンス:
提供されたIDの属性グループが存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
認証が失敗した場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
5. 属性グループの削除
システムから属性グループを永続的に削除します。
リクエスト:
- Method:
DELETE - Path:
/attributes/:attributeId - Headers:
Authorization: Bearer <token>x-nb-fingerprint: <device-fingerprint>
- Authorization: 管理者ロールが必要
URLパラメータ:
| Parameter | Type | 必須 | 説明 |
|---|---|---|---|
attributeId | string | ✅ | 一意の属性グループ識別子 |
レスポンスボディ:
| Field | Type | 説明 |
|---|---|---|
| レスポンスボディなし | - | 削除エンドポイントは成功時にレスポンスボディを返しません |
バリデーション:
- スキーマバリデーション: attributeIdのパスパラメータ検証
- ルートバリデーター:
- 認証済みリクエストが必要(bearerトークン)
- 管理者ロールが必要
リクエスト例:
curl -X DELETE {{host}}/attributes/69b013c9-cb20-4a7e-9c1f-59a55db1d949 \
-H "Authorization: Bearer <admin_token>" \
-H "x-nb-fingerprint: test-device-fingerprint"
成功レスポンス:
HTTP/1.1 204 No Content
エラーレスポンス:
提供されたIDの属性グループが存在しない場合:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
認証が失敗した場合:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
⚙️ 設定オプション
サービス設定
interface AttributesServiceConfiguration {
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 } - Description: JWT暗号化と署名のためのシークレットキー(トークン検証に使用)
- Required: はい(本番環境用)
- 子プロパティ:
authEncSecret: JWTペイロード暗号化のためのシークレットキーauthSignSecret: JWT署名検証のためのシークレットキー
👥 ユーザータイプ設定
identity.typeIds - ユーザータイプ識別子設定
- Type:
{ admin?: string; guest?: string; regular?: string } - Description: ロールベースアクセス制御のためのカスタムユーザータイプ識別子
- Default:
undefined(デフォルトのタイプ検証を使用) - 子プロパティ:
admin: 管理者ユーザータイプ識別子- Type:
string - Description: 管理者ユーザーのカスタム識別子
- 使用例: 管理操作のためのロールベースアクセス制御
- 例:
"admin","administrator","superuser"
- Type:
guest: ゲストユーザータイプ識別子- Type:
string - Description: ゲストユーザーのカスタム識別子
- 使用例: 未認証または一時的なユーザーの限定アクセス
- 例:
"guest","visitor","anonymous"
- Type:
regular: 通常ユーザータイプ識別子- Type:
string - Description: 通常ユーザーのカスタム識別子
- 使用例: 標準的なユーザーアクセス権限
- 例:
"user","member","customer"
- Type:
設定例
const attributesConfig = {
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形式で返されます:
一般的なエラーコード
| Status | Error Message | 説明 |
|---|---|---|
| 400 | Validation Error | 無効なリクエストボディ形式または必須フィールドの欠落 |
| 400 | request body must have required property 'name' | リクエストボディにnameフィールドがない |
| 400 | request body must have required property 'items' | リクエストボディにitems配列がない |
| 400 | request body must NOT have fewer than 1 items | items配列が空(最小1項目が必要) |
| 400 | request body must NOT have additional properties | リクエストにサポートされていないフィールドが含まれている |
| 400 | Failed to create attribute group | データベース挿入操作が挿入されたIDを返さなかった |
| 400 | Failed to update attribute group | 更新操作がデータを変更しない(変更が検出されない) |
| 401 | Authentication failed | 認証トークンがないか無効 |
| 401 | token could not be verified | 認証トークンがないか無効 |
| 403 | User is not authorized to access this resource | ユーザーに必要な権限がない(管理者アクセス) |
| 404 | Attribute group not found | 要求された操作に対して属性グループが存在しない |
| 500 | Failed to create attribute | 作成中のデータベース接続の問題または予期しない障害 |
| 500 | Failed to get attribute group | 取得中のデータベース接続の問題または予期しない障害 |
| 500 | Failed to find attributes | リスト取得中のデータベース接続の問題、無効なフィルター構文、または予期しない障害 |
| 500 | Failed to update attribute | 更新中のデータベース接続の問題または予期しない障害 |
| 500 | Failed to delete attribute | 削除中のデータベース接続の問題または予期しない障害 |
エラーレスポンス形式
{
"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 'items'",
"request body must NOT have fewer than 1 items"
]
}
}
🔗 関連ドキュメント
- Product Service - 製品管理操作
- User Service - ユーザー管理操作
- Organization Service - 組織管理操作
- Authentication Service - 認証と認可
- Error Handling - エラーパターンの理解
- Schema Component - データ検証の概念
- Custom Service Tutorial - 独自のサービスの構築