🛒 Order Service
The Order Service provides a complete REST API for managing order entities with CRUD operations. It's built using the Nodeblocks functional composition approach and integrates seamlessly with MongoDB.
🚀 Quickstart
import express from 'express';
import { middlewares, services, drivers } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { orderService } = services;
const { getMongoClient } = drivers;
const client = getMongoClient('mongodb://localhost:27017', 'dev');
express()
.use(
orderService(
{
orders: client.collection('orders'),
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
Order Operations
Method | Path | Description | Auth Required |
---|---|---|---|
POST | /orders | Create a new order | ✅ Required |
GET | /orders/:orderId | Retrieve an order by ID | ✅ Required |
GET | /orders | List/filter orders | ✅ Required |
PATCH | /orders/:orderId | Update an order | ✅ Required |
DELETE | /orders/:orderId | Delete an order | ✅ Required |
🗄️ Entity Schema
The order entity combines base fields (auto-generated) with complex order-specific data including items array and pricing:
{
"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)"
}
Field Details
Field | Type | Auto-Generated | Required | Description |
---|---|---|---|---|
items | array | ❌ | ✅ | Array of order items with product details |
total | number | ❌ | ✅ | Total order amount (minimum 0) |
subtotal | number | ❌ | ❌ | Subtotal before tax (minimum 0) |
tax | number | ❌ | ❌ | Tax amount (minimum 0) |
currency | string | ❌ | ❌ | Currency code (e.g., "USD", "EUR") |
status | string | ❌ | ❌ | Order status (e.g., "pending", "completed") |
identityId | string (uuid) | ❌ | ✅ | Identity who placed the order |
organizationId | string (uuid) | ❌ | ❌ | Organization associated with the order |
createdAt | datetime | ✅ | ✅ | Creation timestamp |
id | string | ✅ | ✅ | Unique identifier (UUID) |
updatedAt | datetime | ✅ | ✅ | Last modification timestamp |
Items Array Schema
Each item in the items
array must contain:
Field | Type | Required | Validation | Description |
---|---|---|---|---|
productId | string (uuid) | ✅ | UUID format | Product identifier |
quantity | number | ✅ | Minimum 1 | Quantity ordered |
price | number | ✅ | Minimum 0 | Price per unit |
📝 Note: The schema enforces
additionalProperties: false
, meaning only defined fields are allowed. Auto-generated fields are set by the service and should not be included in create/update requests.
🔐 Authentication Headers
For all endpoints, include the following headers:
Authorization: Bearer <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 Order
Creates a new order with the provided information including items array and pricing details.
Request:
- Method:
POST
- Path:
/orders
- Headers:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Bearer token required
Request Body:
Field | Type | Required | Description |
---|---|---|---|
items | array | ✅ | Array of order items (see Items Schema) |
total | number | ✅ | Total order amount |
identityId | string (uuid) | ✅ | Identity who placed the order |
subtotal | number | ❌ | Subtotal before tax |
tax | number | ❌ | Tax amount |
currency | string | ❌ | Currency code |
status | string | ❌ | Order status |
organizationId | string (uuid) | ❌ | Organization associated with order |
Response Body:
Field | Type | Description |
---|---|---|
items | array | Array of order items with product details |
items[].productId | string | Product identifier |
items[].quantity | number | Quantity ordered |
items[].price | number | Price per unit |
total | number | Total order amount |
subtotal | number | Subtotal before tax |
tax | number | Tax amount |
currency | string | Currency code |
status | string | Order status |
identityId | string | Identity who placed the order |
organizationId | string | Organization associated with order |
createdAt | string | Creation timestamp |
id | string | Unique order identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (items, total, identityId required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role or self (order owner)
Authorization Note:
When creating an order, the identityId
field in the request body must match the identityId
associated with your access token. If you attempt to create an order for a different identity, you will receive a 403 Forbidden error.
Admin users cannot create orders for other users unless the backend validator logic is changed to allow this.
Example Request:
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"
}'
Success Response:
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": "pending",
"createdAt": "2025-07-04T01:59:20.084Z",
"id": "10283907-d41a-4647-a235-18ec63f3369a",
"updatedAt": "2025-07-04T01:59:20.084Z"
}
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 'identityId'",
"request body must have required property 'items'"
]
}
}
When authentication fails:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"message": "token could not be verified"
}
}
When authorization fails:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"error": {
"message": "User is not authorized to access this order"
}
}
2. Get Order by ID
Retrieves a specific order by its unique ID.
Request:
- Method:
GET
- Path:
/orders/:orderId
- Headers:
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Bearer token required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
orderId | string | ✅ | Unique order identifier |
Response Body:
Field | Type | Description |
---|---|---|
items | array | Array of order items with product details |
items[].productId | string | Product identifier |
items[].quantity | number | Quantity ordered |
items[].price | number | Price per unit |
total | number | Total order amount |
subtotal | number | Subtotal before tax |
tax | number | Tax amount |
currency | string | Currency code |
status | string | Order status |
identityId | string | Identity who placed the order |
organizationId | string | Organization associated with order |
createdAt | string | Creation timestamp |
id | string | Unique order identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: None (GET request)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role or order ownership
Example Request:
curl http://localhost:8089/orders/10283907-d41a-4647-a235-18ec63f3369a \
-H "Authorization: Bearer <access_token>"
Success Response:
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"
}
Error Responses:
When no order exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Order not found"
}
}
3. List Orders
Retrieves a list of orders with optional filtering and pagination.
Request:
- Method:
GET
- Path:
/orders
- Headers:
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Bearer token required
Query Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
currency | string | ❌ | Filter by currency |
organizationId | string | ❌ | Filter by organization |
status | string | ❌ | Filter by status |
subtotal | number | ❌ | Filter by subtotal amount |
tax | number | ❌ | Filter by tax amount |
total | number | ❌ | Filter by total amount |
identityId | string | ❌ | Filter by identityId |
page | number | ❌ | Page number for pagination |
limit | number | ❌ | Number of items per page |
Response Body:
Field | Type | Description |
---|---|---|
items | array | Array of order items with product details |
items[].productId | string | Product identifier |
items[].quantity | number | Quantity ordered |
items[].price | number | Price per unit |
total | number | Total order amount |
subtotal | number | Subtotal before tax |
tax | number | Tax amount |
currency | string | Currency code |
status | string | Order status |
identityId | string | Identity who placed the order |
organizationId | string | Organization associated with order |
createdAt | string | Creation timestamp |
id | string | Unique order identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: None (GET request)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role or self
Example Requests:
List all orders:
curl http://localhost:8089/orders \
-H "Authorization: Bearer <access_token>"
Filter by status:
curl "http://localhost:8089/orders?status=completed" \
-H "Authorization: Bearer <access_token>"
Filter by currency:
curl "http://localhost:8089/orders?currency=USD" \
-H "Authorization: Bearer <access_token>"
Success Response:
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"
}
]
4. Update Order
Updates an existing order with partial data.
Request:
- Method:
PATCH
- Path:
/orders/:orderId
- Headers:
Content-Type: application/json
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Bearer token required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
orderId | string | ✅ | Unique order identifier |
Request Body (all fields optional):
Field | Type | Required | Description |
---|---|---|---|
items | array | ❌ | Array of order items |
total | number | ❌ | Total order amount |
subtotal | number | ❌ | Subtotal before tax |
tax | number | ❌ | Tax amount |
currency | string | ❌ | Currency code |
status | string | ❌ | Order status |
identityId | string (uuid) | ❌ | Identity who placed the order |
organizationId | string (uuid) | ❌ | Organization associated with order |
Response Body:
Field | Type | Description |
---|---|---|
items | array | Array of order items with product details |
items[].productId | string | Product identifier |
items[].quantity | number | Quantity ordered |
items[].price | number | Price per unit |
total | number | Updated total order amount |
subtotal | number | Updated subtotal before tax |
tax | number | Updated tax amount |
currency | string | Updated currency code |
status | string | Updated order status |
identityId | string | Identity who placed the order |
organizationId | string | Updated organization associated with order |
createdAt | string | Creation timestamp |
id | string | Unique order identifier |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (partial updates, all fields optional)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role or order ownership
Example Request:
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"}'
Success Response:
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"
}
Error Responses:
When no order exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Order not found"
}
}
5. Delete Order
Permanently deletes an order from the system.
Request:
- Method:
DELETE
- Path:
/orders/:orderId
- Headers:
Authorization: Bearer <token>
x-nb-fingerprint: <device-fingerprint>
- Authorization: Bearer token required
URL Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
orderId | string | ✅ | Unique order identifier |
Response Body:
Field | Type | Description |
---|---|---|
No response body | - | Delete endpoint returns no response body on success |
Validation:
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role or order ownership
Example Request:
curl -X DELETE http://localhost:8089/orders/10283907-d41a-4647-a235-18ec63f3369a \
-H "Authorization: Bearer <access_token>"
Success Response:
HTTP/1.1 204 No Content
Error Responses:
When no order exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Order not found"
}
}
⚙️ Configuration Options
Service Configuration
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
};
};
}
Configuration Details
The order 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:
user
: 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 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'
}
}
};
🚨 Error Handling
All order 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 'identityId' | Missing identityId field in request body |
400 | request body must have required property 'items' | Missing items array in request body |
400 | request body must have required property 'total' | Missing total field in request body |
400 | request body must NOT have additional properties | Request contains unsupported fields |
400 | Failed to create order | Database insert operation failed to return an inserted ID |
400 | Failed to update order | Update operation doesn't modify any data (no changes detected) |
400 | Failed to delete order | Database deletion operation failed |
401 | token could not be verified | Missing or invalid authorization token |
401 | Authentication failed | Missing or invalid authentication token |
401 | Token fails security check | Token security validation failed |
403 | User is not authorized to access this order | User lacks required permissions (admin/owner access) |
403 | User is not authorized to access this resource | User lacks required permissions (admin access) |
404 | Order not found | Order doesn't exist for the requested operation |
500 | Failed to create order | Database connection issues or unexpected failures during creation |
500 | Failed to get order | Database connection issues or unexpected failures during retrieval |
500 | Failed to find orders | Database connection issues, invalid filter syntax, or unexpected failures during listing |
500 | Failed to update order | Database connection issues or unexpected failures during update |
500 | Failed to delete order | 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 'items'",
"request body must have required property 'total'"
]
}
}
🔗 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