🏷️ Attribute Service
The Attribute Service provides a complete REST API for managing attribute groups with key-value pairs. It's designed to handle product attributes, category properties, and other structured metadata using the Nodeblocks functional composition approach and MongoDB integration.
🚀 Quickstart
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'));
📋 Endpoint Summary
Attribute Group Operations
Method | Path | Description | Auth Required |
---|---|---|---|
POST | /attributes | Create a new attribute group | ✅ Admin |
GET | /attributes/:attributeId | Retrieve an attribute group by ID | ❌ None |
GET | /attributes | List/filter attribute groups | ❌ None |
PATCH | /attributes/:attributeId | Update an attribute group | ✅ Admin |
DELETE | /attributes/:attributeId | Delete an attribute group | ✅ Admin |
🗄️ Entity Schema
The attribute group entity combines base fields (auto-generated) with attribute-specific data:
{
"name": "string",
"items": [
{
"key": "string",
"value": "string"
}
],
"createdAt": "string (datetime)",
"id": "string",
"updatedAt": "string (datetime)"
}
Field Details
Field | Type | Auto-Generated | Required | Description |
---|---|---|---|---|
name | string | ❌ | ✅ | Attribute group name |
items | array | ❌ | ✅ | Array of key-value pairs (min 1 item) |
items[].key | string | ❌ | ✅ | Attribute key/name |
items[].value | string | ❌ | ✅ | Attribute value |
createdAt | datetime | ✅ | ✅ | Creation timestamp |
id | string | ✅ | ✅ | Unique identifier (UUID) |
updatedAt | datetime | ✅ | ✅ | Last modification timestamp |
📝 Note: Auto-generated fields are set by the service and should not be included in create/update requests. The
items
array must contain at least one key-value pair.
🔐 Authentication Headers
For protected endpoints, include the following headers:
Authorization: Bearer <admin_access_token>
x-nb-fingerprint: <device_fingerprint>
⚠️ Important: The
x-nb-fingerprint
header is required for all authenticated requests if fingerprint was specified during authorization. Without it, requests will return 401 Unauthorized.
🔧 API Endpoints
1. Create Attribute Group
Creates a new attribute group with the provided name and key-value pairs.
Request:
- Method:
POST
- Path:
/attributes
- Headers:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Admin role required
Request Body:
Field | Type | Required | Description |
---|---|---|---|
name | string | ✅ | Attribute group name |
items | array | ✅ | Array of key-value pairs (min 1 item) |
items[].key | string | ✅ | Attribute key/name |
items[].value | string | ✅ | Attribute value |
Response Body:
Field | Type | Description |
---|---|---|
name | string | Attribute group name |
items | array | Array of key-value pairs |
items[].key | string | Attribute key/name |
items[].value | string | Attribute value |
createdAt | string | Creation timestamp |
id | string | Unique attribute group identifier |
updatedAt | string | Last update timestamp |
Validation:
-
Schema Validation: Enforced automatically (name, items required, no additional properties)
-
Route Validators:
- Require authenticated request (bearer token)
- Require admin role
-
Items Validation: Must contain at least 1 item, each with required key and value
Example Request:
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"
}
]
}'
Success Response:
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"
}
Error Responses:
When request body is missing required fields:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'items'"
]
}
}
When items array is empty:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Validation Error",
"data": [
"request body must NOT have fewer than 1 items"
]
}
}
When authentication fails:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
2. Get Attribute Group by ID
Retrieves a specific attribute group by its unique ID.
Request:
- Method:
GET
- Path:
/attributes/:attributeId
- Headers: None
- Authorization: None required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
attributeId | string | ✅ | Unique attribute group identifier |
Response Body:
Field | Type | Description |
---|---|---|
name | string | Attribute group name |
items | array | Array of key-value pairs |
items[].key | string | Attribute key/name |
items[].value | string | Attribute value |
createdAt | string | Creation timestamp |
id | string | Unique attribute group identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Path parameter validation for attributeId
- Route Validators: None
Example Request:
curl {{host}}/attributes/69b013c9-cb20-4a7e-9c1f-59a55db1d949
Success Response:
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"
}
Error Responses:
When no attribute group exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
3. List Attribute Groups
Retrieves a list of attribute groups with optional filtering and pagination.
Request:
- Method:
GET
- Path:
/attributes
- Headers: None
- Authorization: None required
Query Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
name | string | ❌ | Filter by attribute group name |
page | number | ❌ | Page number for pagination |
limit | number | ❌ | Number of items per page |
Response Body:
Field | Type | Description |
---|---|---|
name | string | Attribute group name |
items | array | Array of key-value pairs |
items[].key | string | Attribute key/name |
items[].value | string | Attribute value |
createdAt | string | Creation timestamp |
id | string | Unique attribute group identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Query parameter validation for name and pagination (page, limit)
- Route Validators: None
Example Requests:
List all attribute groups:
curl {{host}}/attributes
Filter by 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. Update Attribute Group
Updates an existing attribute group. Note: Only the name
field can be updated according to the schema - the items
array cannot be modified through the update endpoint.
Request:
- Method:
PATCH
- Path:
/attributes/:attributeId
- Headers:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Admin role required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
attributeId | string | ✅ | Unique attribute group identifier |
Request Body:
Field | Type | Required | Description |
---|---|---|---|
name | string | ❌ | New attribute group name |
Response Body:
Field | Type | Description |
---|---|---|
name | string | Updated attribute group name |
items | array | Array of key-value pairs (unchanged) |
items[].key | string | Attribute key/name |
items[].value | string | Attribute value |
createdAt | string | Creation timestamp |
id | string | Unique attribute group identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (only name field allowed, no additional properties)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
⚠️ Important: The update schema only allows updating the
name
field. To modify theitems
array, you would need to delete and recreate the attribute group.
Example Request:
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"}'
Success Response:
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"
}
Error Responses:
When no attribute group exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
When authentication fails:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
5. Delete Attribute Group
Permanently deletes an attribute group from the system.
Request:
- Method:
DELETE
- Path:
/attributes/:attributeId
- Headers:
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Admin role required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
attributeId | string | ✅ | Unique attribute group identifier |
Response Body:
Field | Type | Description |
---|---|---|
No response body | - | Delete endpoint returns no response body on success |
Validation:
- Schema Validation: Path parameter validation for attributeId
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X DELETE {{host}}/attributes/69b013c9-cb20-4a7e-9c1f-59a55db1d949 \
-H "Authorization: Bearer <admin_token>" \
-H "x-nb-fingerprint: test-device-fingerprint"
Success Response:
HTTP/1.1 204 No Content
Error Responses:
When no attribute group exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Attribute group not found"
}
}
When authentication fails:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "Authentication failed"
}
}
⚙️ Configuration Options
Service Configuration
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
};
};
}
Configuration Details
The attributes service configuration is organized into logical groups for security and user type management.
🔐 Security Settings
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 Type Settings
identity.typeIds
- User type identifier configuration
- Type:
{ admin?: string; guest?: string; regular?: string }
- Description: Custom user type identifiers for role-based access control
- Default:
undefined
(uses default type validation) - Child Properties:
admin
: Admin user type identifier- Type:
string
- Description: Custom identifier for admin users
- Use Case: Role-based access control for administrative operations
- Example:
"admin"
,"administrator"
,"superuser"
- Type:
guest
: Guest user type identifier- Type:
string
- Description: Custom identifier for guest users
- Use Case: Limited access for unauthenticated or temporary users
- Example:
"guest"
,"visitor"
,"anonymous"
- Type:
regular
: Regular user type identifier- Type:
string
- Description: Custom identifier for regular users
- Use Case: Standard user access permissions
- Example:
"user"
,"member"
,"customer"
- Type:
Example Configuration
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'
}
}
};
🚨 Error Handling
All attribute service errors return JSON format with appropriate HTTP status codes:
Common Error Codes
Status | Error Message | Description |
---|---|---|
400 | Validation Error | Invalid request body format or missing required fields |
400 | request body must have required property 'name' | Missing name field in request body |
400 | request body must have required property 'items' | Missing items array in request body |
400 | request body must NOT have fewer than 1 items | Items array is empty (minimum 1 item required) |
400 | request body must NOT have additional properties | Request contains unsupported fields |
400 | Failed to create attribute | Database insert operation failed to return an inserted ID |
400 | Failed to update attribute | Update operation doesn't modify any data (no changes detected) |
401 | Authentication failed | Missing or invalid authentication token |
401 | token could not be verified | Missing or invalid authorization token |
403 | User is not authorized to access this resource | User lacks required permissions (admin access) |
404 | Attribute group not found | Attribute group doesn't exist for the requested operation |
500 | Failed to create attribute | Database connection issues or unexpected failures during creation |
500 | Failed to get attribute | Database connection issues or unexpected failures during retrieval |
500 | Failed to find attributes | Database connection issues, invalid filter syntax, or unexpected failures during listing |
500 | Failed to update attribute | Database connection issues or unexpected failures during update |
500 | Failed to delete attribute | Database connection issues or unexpected failures during deletion |
Error Response Format
{
"error": {
"message": "Error message description",
"data": ["Additional error details"]
}
}
Validation Errors include additional 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"
]
}
}
🔗 Related Documentation
- Product Service - Product management operations
- User Service - User management operations
- Organization Service - Organization management operations
- Authentication Service - Authentication and authorization
- Error Handling - Understanding error patterns
- Schema Component - Data validation concepts
- Custom Service Tutorial - Build your own services