🏷️ 属性サービス
属性サービスは、キーと値のペアからなる属性グループを管理するための完全な REST API を提供します。Nodeblocks の関数型合成アプローチと MongoDB 連携により、製品の属性、カテゴリのプロパティ、その他の構造化メタデータを扱えるよう設計されています。
🚀 クイックスタート
import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { attributesService } = services;
const { getMongoClient } = drivers;
const client = getMongoClient('mongodb://localhost:27017', 'dev');
express()
.use(
attributesService(
{
attributes: client.collection('attributes'),
identities: client.collection('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'));
📋 エンドポイント概要
属性グループ操作
メソッド | パス | 説明 | 認証 |
---|---|---|---|
POST | /attributes | 属性グループを新規作成 | ✅ 管理者 |
GET | /attributes/:attributeId | ID で属性グループを取得 | ❌ なし |
GET | /attributes | 属性グループを一覧/フィルタ取得 | ❌ なし |
PATCH | /attributes/:attributeId | 属性グループを更新 | ✅ 管理者 |
DELETE | /attributes/:attributeId | 属性グループを削除 | ✅ 管理者 |
🗄️ エンティティスキーマ
属性グループエンティティは、ベースフィールド(自動生成)と属性固有データで構成されます:
{
"name": "string",
"items": [
{
"key": "string",
"value": "string"
}
],
"createdAt": "string (datetime)",
"id": "string",
"updatedAt": "string (datetime)"
}
フィールド詳細
フィールド | 型 | 自動生成 | 必須 | 説明 |
---|---|---|---|---|
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 Endpoints
1. 属性グループの作成
指定された名前とキー・値ペアで新しい属性グループを作成します。
リクエスト:
- Method:
POST
- Path:
/attributes
- ヘッダー:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- 認可: 管理者ロール必須
リクエストボディ:
フィールド | 型 | 必須 | 説明 |
---|---|---|---|
name | string | ✅ | 属性グループ名 |
items | array | ✅ | キー・値ペアの配列(最低1件) |
items[].key | string | ✅ | 属性キー/名称 |
items[].value | string | ✅ | 属性値 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
name | string | 属性グループ名 |
items | array | キー・値ペアの配列 |
items[].key | string | 属性キー/名称 |
items[].value | string | 属性値 |
createdAt | string | 作成日時 |
id | string | 属性グループの一意ID |
updatedAt | string | 最終更新日時 |
バリデーション:
-
スキーマ検証: 自動適用(name と items が必須、追加プロパティ不可)
-
ルートバリデーション:
- 認証済みリクエスト(ベアラートークン)必須
- 管理者ロール必須
-
Items 検証: 最低1件の要素が必要で、各要素は key と value が必須
リクエスト例:
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
- ヘッダー: なし
- 認可: 不要
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
attributeId | string | ✅ | 属性グループの一意ID |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
name | string | 属性グループ名 |
items | array | キー・値ペアの配列 |
items[].key | string | 属性キー/名称 |
items[].value | string | 属性値 |
createdAt | string | 作成日時 |
id | string | 属性グループの一意ID |
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
- ヘッダー: なし
- 認可: 不要
クエリパラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
name | string | ❌ | 属性グループ名でフィルタ |
page | number | ❌ | ページ番号 |
limit | number | ❌ | 1ページあたりの件数 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
name | string | 属性グループ名 |
items | array | キー・値ペアの配列 |
items[].key | string | 属性キー/名称 |
items[].value | string | 属性値 |
createdAt | string | 作成日時 |
id | string | 属性グループの一意ID |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: name とページング(page, limit)のクエリ検証
- ルートバリデーション: なし
リクエスト例:
すべての属性グループを一覧:
curl {{host}}/attributes
name でフィルタ:
curl "{{host}}/attributes?name=Product"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"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"
}
]
4. 属性グループの更新
既存の属性グループを更新します。注意: スキーマ上、更新できるのは name
フィールドのみです。items
配列はこの更新エンドポイントでは変更できません。
リクエスト:
- Method:
PATCH
- Path:
/attributes/:attributeId
- ヘッダー:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- 認可: 管理者ロール必須
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
attributeId | string | ✅ | 属性グループの一意ID |
リクエストボディ:
フィールド | 型 | 必須 | 説明 |
---|---|---|---|
name | string | ❌ | 新しい属性グループ名 |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
name | string | 更新後の属性グループ名 |
items | array | キー・値ペアの配列(変更なし) |
items[].key | string | 属性キー/名称 |
items[].value | string | 属性値 |
createdAt | string | 作成日時 |
id | string | 属性グループの一意ID |
updatedAt | string | 最終更新日時 |
バリデーション:
- スキーマ検証: 自動適用(更新可能なのは name フィールドのみ、追加プロパティ不可)
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロール必須
⚠️ 重要: 更新スキーマで更新できるのは
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
- ヘッダー:
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- 認可: 管理者ロール必須
URL パラメータ:
パラメータ | 型 | 必須 | 説明 |
---|---|---|---|
attributeId | string | ✅ | 属性グループの一意ID |
レスポンスボディ:
フィールド | 型 | 説明 |
---|---|---|
ボディなし | - | 成功時はレスポンスボディなし |
バリデーション:
- スキーマ検証: attributeId のパスパラメータ検証
- ルートバリデーション:
- 認証済みリクエスト(ベアラー)必須
- 管理者ロール必須
リクエスト例:
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 token security secrets
- Type:
{ authEncSecret: string; authSignSecret: string }
- Description: Secret keys for JWT encryption and signing (used for token validation)
- Required: Yes (for production)
- Child Properties:
authEncSecret
: Secret key for JWT payload encryptionauthSignSecret
: Secret key for JWT signature verification
👥 ユーザー種別設定
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 attributesConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
user: {
typeIds: {
admin: 'administrator',
guest: 'visitor',
user: 'member'
}
}
};
🚨 エラーハンドリング
属性サービスのエラーは、適切なHTTPステータスコードとJSON形式で返されます:
代表的なエラーコード
ステータス | エラーメッセージ | 説明 |
---|---|---|
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 | 追加IDが返らず作成に失敗 |
400 | Failed to update attribute | 更新対象の変更が検出されず失敗 |
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 | 作成中のDB接続問題/予期せぬ失敗 |
500 | Failed to get attribute | 取得中のDB接続問題/予期せぬ失敗 |
500 | Failed to find attributes | 一覧取得中のDB接続問題/フィルタ不正/予期せぬ失敗 |
500 | Failed to update attribute | 更新中のDB接続問題/予期せぬ失敗 |
500 | Failed to delete attribute | 削除中のDB接続問題/予期せぬ失敗 |
エラーレスポンス形式
{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}
Validation Errors には追加情報が含まれます:
{
"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"
]
}
}
🔗 関連ドキュメント
- プロダクトサービス - プロダクト管理
- ユーザーサービス - ユーザー管理
- 組織サービス - 組織管理
- 認証サービス - 認証と認可
- エラーハンドリング - エラーパターンの理解
- スキーマコンポーネント - データ検証の概念
- カスタムサービスチュートリアル - 独自サービスの構築