📦 Product Service
The Product Service provides a complete REST API for managing product entities with comprehensive CRUD operations and powerful batch processing capabilities. 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 { productService } = services;
const { withMongo, createFileStorageDriver } = drivers;
const connectToDatabase = withMongo('mongodb://localhost:27017', 'dev', 'user', 'password');
// Required for image upload URL endpoint:
// Ensure GOOGLE_APPLICATION_CREDENTIALS is set to your Google Cloud service account JSON.
const fileStorageDriver = createFileStorageDriver(
'your-gcp-project-id',
'your-bucket-name'
);
express()
.use(
productService(
{
...(await connectToDatabase('products')),
...(await connectToDatabase('identities')),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
},
{ fileStorageDriver }
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));
📋 Endpoint Summary
Individual Product Operations
| Method | Path | Description | Authorization |
|---|---|---|---|
POST | /products | Create a new product | Bearer token required (admin only) |
GET | /products/:productId | Retrieve a product by ID | None required |
GET | /products | List/filter products | None required |
GET | /products/organizations/:organizationId | List products by organization | Bearer token required (org member+) |
GET | /products/:productId/likers | List users who liked a product | Bearer token required (admin only) |
PATCH | /products/:productId | Update a product | Bearer token required (admin only) |
DELETE | /products/:productId | Delete a product | Bearer token required (admin only) |
POST | /products/:productId/copy | Copy an existing product | Bearer token required (admin only) |
File Upload Operations
| Method | Path | Description | Authorization |
|---|---|---|---|
GET | /products/:productId/image-upload-url | Get signed URL to upload a product image | Bearer token required (admin only) |
POST | /products/:productId/images | Create a product image entry | Bearer token required (admin only) |
DELETE | /products/:productId/images/:imageId | Delete a product image | Bearer token required (admin only) |
Batch Product Operations
| Method | Path | Description | Authorization |
|---|---|---|---|
POST | /products/batch | Create multiple products | Bearer token required (admin only) |
PATCH | /products/batch | Update multiple products | Bearer token required (admin only) |
DELETE | /products/batch | Delete multiple products | Bearer token required (admin only) |
POST | /products/batch/copy | Copy multiple products | Bearer token required (admin only) |
Product Variant Operations
| Method | Path | Description | Authorization |
|---|---|---|---|
POST | /products/:productId/variants | Create a product variant | Bearer token required (admin only) |
GET | /products/:productId/variants | List variants for a product | None required |
GET | /products/:productId/variants/:productVariantId | Get a specific variant | Bearer token required |
PATCH | /products/:productId/variants/:productVariantId | Update a product variant | Bearer token required (admin only) |
DELETE | /products/:productId/variants/:productVariantId | Delete a product variant | Bearer token required (admin only) |
POST | /product/:productId/variants/bulk | Create multiple variants | Bearer token required (admin only) |
PATCH | /product/:productId/variants/bulk | Update multiple variants | Bearer token required (admin only) |
POST | /product/:productId/variants/bulk-delete | Delete multiple variants | Bearer token required (admin only) |
🗄️ Entity Schema
The product entity combines base fields (auto-generated) with product-specific data including images:
{
"name": "string",
"description": "string",
"images": [
{
"objectId": "string (uuid)",
"type": "string",
"id": "string (uuid)",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)"
}
],
"createdAt": "string (datetime)",
"id": "string (uuid)",
"updatedAt": "string (datetime)"
}
Field Details
| Field | Type | Auto-Generated | Required | Description |
|---|---|---|---|---|
name | string | ❌ | ✅ | Product name |
description | string | ❌ | ✅ | Product description |
images | array | Partial | ✅ | Array of product images |
images[].objectId | string (uuid) | ❌ | ✅ | Object identifier for the image file |
images[].type | string | ❌ | ✅ | Image MIME type (e.g., 'image/png') |
images[].id | string (uuid) | ✅ | ✅ | Unique identifier for the image entity |
images[].createdAt | datetime | ✅ | ✅ | Image creation timestamp |
images[].updatedAt | datetime | ✅ | ✅ | Image last modification timestamp |
createdAt | datetime | ✅ | ✅ | Product creation timestamp |
id | string (uuid) | ✅ | ✅ | Unique product identifier (UUID) |
updatedAt | datetime | ✅ | ✅ | Product last modification timestamp |
📝 Note:
- Auto-generated fields are set by the service and should not be included in create/update requests
- Each image in the
imagesarray gets its own base entity fields (id, createdAt, updatedAt)- The
objectIdin each image references the actual image file in storage- Field order in responses matches the actual API output
🔐 Authentication Headers
For protected endpoints, include the following headers:
Authorization: Bearer <admin_access_token>
x-nb-fingerprint: <device_fingerprint>
⚠️ Important: The
x-nb-fingerprintheader is required for all authenticated requests if fingerprint was specified during authorization. Without it, requests will return 401 Unauthorized.
🔧 API Endpoints
1. Create Product
Creates a new product with the provided information.
Request:
- Method:
POST - Path:
/products - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Product name |
description | string | ✅ | Product description |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Product name |
description | string | Product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (name, description required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST {{host}}/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"name": "Premium Widget",
"description": "High-quality widget for enterprise use"
}'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}
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 'name'",
"request body must have required property 'description'"
]
}
}
When database insert operation fails:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"message": "Failed to create product"
}
}
2. Get Product by ID
Retrieves a specific product by their unique ID.
Request:
- Method:
GET - Path:
/products/:productId - Authorization: None required
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Unique product identifier |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Product name |
description | string | Product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Path parameter validation (productId required)
- Route Validators: None
Example Request:
curl {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}
Error Responses:
When no product exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Product not found"
}
}
3. List Products
Retrieves a list of products with optional filtering and pagination.
Request:
- Method:
GET - Path:
/products - Authorization: None required
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ❌ | Filter by product name |
description | string | ❌ | Filter by product description |
page | number | ❌ | Page number for pagination (1-1000) |
limit | number | ❌ | Number of items per page (1-50) |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Product name |
description | string | Product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Query parameter validation (optional name, description, page, limit)
- Route Validators: None
Example Requests:
List all products:
curl {{host}}/products
Filter by name:
curl "{{host}}/products?name=Premium%20Widget"
With pagination:
curl "{{host}}/products?page=1&limit=10"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"name": "Premium Widget",
"description": "Updated high-quality widget for enterprise use",
"createdAt": "2025-06-24T06:39:17.101Z",
"id": "3d0e4b74-398c-43e2-a7b4-c9a180477322",
"updatedAt": "2025-06-24T06:39:17.101Z"
},
{
"name": "Product A",
"description": "Updated batch description",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "0e0dd6c7-c3d5-49e5-a1d8-20daa34d380a",
"updatedAt": "2025-06-24T06:39:55.720Z"
},
{
"name": "Product B",
"description": "Updated batch description",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "d5a60fdf-2a22-4fcc-8e40-a68cb89cce72",
"updatedAt": "2025-06-24T06:39:55.720Z"
}
]
4. List Products by Organization ID
Retrieves a list of products scoped to a specific organization with pagination and image normalization.
Request:
- Method:
GET - Path:
/products/organizations/:organizationId - Authorization: Bearer token required (organization member, admin, or owner)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId | string | ✅ | Organization identifier to scope product retrieval |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | ❌ | Page number for pagination (1-1000) |
limit | number | ❌ | Number of items per page (1-50) |
Response Body:
| Field | Type | Description |
|---|---|---|
data | array | Array of product objects |
data[].id | string | Unique product identifier |
data[].organizationId | string | Organization identifier |
data[].name | string | Product name |
data[].description | string | Product description |
data[].images | array | Array of product images with URLs |
data[].createdAt | string | Creation timestamp |
data[].updatedAt | string | Last update timestamp |
metadata | object | Pagination metadata |
metadata.pagination | object | Pagination information |
metadata.pagination.page | number | Current page number |
metadata.pagination.limit | number | Items per page |
metadata.pagination.total | number | Total number of products |
metadata.pagination.totalPages | number | Total number of pages |
metadata.pagination.hasNext | boolean | Whether there are more pages |
metadata.pagination.hasPrev | boolean | Whether there are previous pages |
Validation:
- Schema Validation: Organization ID path parameter and pagination query parameters
- Route Validators: Authentication required, organization membership validation
- Authorization: User must be a member, admin, or owner of the organization
Example Requests:
List products for an organization:
curl -H "Authorization: Bearer eyJ..." "{{host}}/products/organizations/org-123"
With pagination:
curl -H "Authorization: Bearer eyJ..." "{{host}}/products/organizations/org-123?page=1&limit=5"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "prod-123",
"organizationId": "org-456",
"name": "Premium Widget",
"description": "High-quality widget for professionals",
"images": [
{
"id": "img-789",
"objectId": "abc123...",
"type": "image/jpeg",
"url": "https://storage.googleapis.com/bucket/abc123..."
}
],
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: User doesn't have access to the organization500 Internal Server Error: Database operation failed or file storage error
Use Cases:
- Organization-specific product catalogs in multi-tenant applications
- Admin dashboards for managing products within an organization
- API consumers retrieving products for a specific business entity
5. List Product Likers
Retrieves a list of users who have liked a specific product with pagination and avatar normalization.
Request:
- Method:
GET - Path:
/products/:productId/likers - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Product identifier to retrieve likers for |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | ❌ | Page number for pagination (1-1000) |
limit | number | ❌ | Number of items per page (1-50) |
Response Body:
| Field | Type | Description |
|---|---|---|
data | array | Array of user objects who liked the product |
data[].id | string | User identifier |
data[].name | string | User display name |
data[].avatar | object | User avatar with signed URL |
data[].avatar.id | string | Avatar file identifier |
data[].avatar.objectId | string | Cloud storage object identifier |
data[].avatar.type | string | MIME type of the avatar image |
data[].avatar.url | string | Signed URL for avatar access |
metadata | object | Pagination metadata |
metadata.pagination | object | Pagination information |
metadata.pagination.page | number | Current page number |
metadata.pagination.limit | number | Items per page |
metadata.pagination.total | number | Total number of likers |
metadata.pagination.totalPages | number | Total number of pages |
metadata.pagination.hasNext | boolean | Whether there are more pages |
metadata.pagination.hasPrev | boolean | Whether there are previous pages |
Validation:
- Schema Validation: Product ID path parameter and pagination query parameters
- Route Validators: Authentication required, admin-only authorization
- Authorization: User must have admin role
Example Requests:
List product likers:
curl -H "Authorization: Bearer eyJ..." "{{host}}/products/prod-123/likers"
With pagination:
curl -H "Authorization: Bearer eyJ..." "{{host}}/products/prod-123/likers?page=1&limit=5"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "user-123",
"name": "John Doe",
"avatar": {
"id": "avatar-456",
"objectId": "abc123...",
"type": "image/jpeg",
"url": "https://storage.googleapis.com/bucket/abc123..."
}
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: Non-admin user attempting to view likers404 Not Found: Product not found500 Internal Server Error: Database operation failed or file storage error
Use Cases:
- Admin dashboards showing product engagement metrics
- Social features displaying who liked products
- Analytics and reporting on product popularity
- User relationship analysis for recommendation systems
6. Update Product
Updates an existing product with partial data.
Request:
- Method:
PATCH - Path:
/products/:productId - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Unique product identifier |
Request Body (all fields optional):
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ❌ | Product name |
description | string | ❌ | Product description |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Updated product name |
description | string | Updated product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (partial updates, all fields optional, no additional properties allowed)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X PATCH {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{"description": "Updated high-quality widget for enterprise use"}'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Premium Widget",
"description": "Updated high-quality widget for enterprise use",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T14:22:15.789Z"
}
Error Responses:
When no product exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Product not found"
}
}
7. Delete Product
Permanently deletes a product from the system.
Request:
- Method:
DELETE - Path:
/products/:productId - Headers:
Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Unique product identifier |
Response Body:
| Field | Type | Description |
|---|---|---|
| No response body | - | Delete endpoint returns no response body on success |
Validation:
- Schema Validation: Path parameter validation (productId required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X DELETE {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Authorization: Bearer <access-token>"
Success Response:
HTTP/1.1 204 No Content
Error Responses:
When no product exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Product not found"
}
}
8. Copy Product
Creates a copy of an existing product with a new ID.
Request:
- Method:
POST - Path:
/products/:productId/copy - Headers:
Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | ID of product to copy |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the copied product |
name | string | Product name (copied from original) |
description | string | Product description (copied from original) |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Path parameter validation (productId required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST {{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/copy \
-H "Authorization: Bearer <access-token>"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "9abc123f-1cd8-4def-b123-456789abcdef",
"name": "Premium Widget",
"description": "High-quality widget for enterprise use",
"createdAt": "2024-05-28T15:30:45.123Z",
"updatedAt": "2024-05-28T15:30:45.123Z"
}
Error Responses:
When no product exists with the provided ID:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"message": "Product not found"
}
}
🔄 Batch Product Operations
The Product Service provides powerful batch operations for managing multiple products efficiently.
9. Create Multiple Products
Creates multiple products in a single request.
Request:
- Method:
POST - Path:
/products/batch - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
Request Body:
Array of product objects, each requiring name and description.
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Product name |
description | string | Product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (array of product objects with required name and description)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
{
"name": "Product A",
"description": "Description for Product A"
},
{
"name": "Product B",
"description": "Description for Product B"
}
]'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"name": "Product A",
"description": "Description for Product A",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "0e0dd6c7-c3d5-49e5-a1d8-20daa34d380a",
"updatedAt": "2025-06-24T06:39:45.378Z"
},
{
"name": "Product B",
"description": "Description for Product B",
"createdAt": "2025-06-24T06:39:45.378Z",
"id": "d5a60fdf-2a22-4fcc-8e40-a68cb89cce72",
"updatedAt": "2025-06-24T06:39:45.378Z"
}
]
10. Update Multiple Products
Updates multiple products with the same data in a single request.
Request:
- Method:
PATCH - Path:
/products/batch - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
ids | array of strings | ✅ | Array of product IDs to update |
data | object | ✅ | Update data to apply to all products |
data.name | string | ❌ | New product name |
data.description | string | ❌ | New product description |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique product identifier |
name | string | Updated product name |
description | string | Updated product description |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (ids array and data object required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X PATCH {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"ids": [
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
],
"data": {
"description": "Updated batch description"
}
}'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"name": "Product A",
"description": "Updated batch description",
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T15:45:12.789Z"
},
{
"id": "8fec096b-1bc7-5bfe-c827-3600e8fe2790",
"name": "Product B",
"description": "Updated batch description",
"createdAt": "2024-05-28T09:41:23.123Z",
"updatedAt": "2024-05-28T15:45:12.789Z"
}
]
11. Delete Multiple Products
Deletes multiple products in a single request.
Request:
- Method:
DELETE - Path:
/products/batch - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
Request Body: Array of product IDs to delete.
Response Body:
| Field | Type | Description |
|---|---|---|
| No response body | - | Delete endpoint returns no response body on success |
Validation:
- Schema Validation: Enforced automatically (array of strings)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X DELETE {{host}}/products/batch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
]'
Success Response:
HTTP/1.1 204 No Content
12. Copy Multiple Products
Creates copies of multiple products in a single request.
Request:
- Method:
POST - Path:
/products/batch/copy - Headers:
Content-Type: application/json,Authorization: Bearer <access-token> - Authorization: Bearer token required (admin only)
Request Body: Array of product IDs to copy.
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the copied product |
name | string | Product name (copied from original) |
description | string | Product description (copied from original) |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Enforced automatically (array of strings)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST {{host}}/products/batch/copy \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
"7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"8fec096b-1bc7-5bfe-c827-3600e8fe2790"
]'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "9abc123f-1cd8-4def-b123-456789abcdef",
"name": "Product A",
"description": "Description for Product A",
"createdAt": "2024-05-28T16:00:00.000Z",
"updatedAt": "2024-05-28T16:00:00.000Z"
},
{
"id": "def456a1-2e3f-4567-8901-23456789bcde",
"name": "Product B",
"description": "Description for Product B",
"createdAt": "2024-05-28T16:00:00.100Z",
"updatedAt": "2024-05-28T16:00:00.100Z"
}
]
13. Get Product Image Upload URL
Generates a pre-signed URL for securely uploading a product image. Returns an object ID and a temporary signed URL.
Request:
- Method:
GET - Path:
/products/:productId/image-upload-url - Headers:
Authorization: Bearer <token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Target product ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
contentType | string | ✅ | Image MIME type (e.g., image/png) |
contentLength | number | ✅ | File size in bytes (max 10MB) |
Response Body:
| Field | Type | Description |
|---|---|---|
objectId | string | Generated storage object ID for the product image |
url | string | Pre-signed URL for uploading the file |
Validation:
- Schema Validation: Uses image upload schema (content type and size constraints)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl "{{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/image-upload-url?contentType=image/webp&contentLength=2097152" \
-H "Authorization: Bearer <access-token>"
Success Response:
{
"objectId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"url": "https://storage.googleapis.com/bucket/products/...&X-Goog-Expires=900&X-Goog-Signature=..."
}
14. Create Product Image
Creates a product image entry after uploading the file to cloud storage.
Request:
- Method:
POST - Path:
/products/:productId/images - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Target product ID |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
objectId | string | ✅ | Storage object ID from upload URL |
type | string | ✅ | Image type/category |
Example Request:
curl -X POST "{{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/images" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"objectId": "image-uuid-123",
"type": "product-image"
}'
15. Delete Product Image
Removes a product image and deletes the file from cloud storage.
Request:
- Method:
DELETE - Path:
/products/:productId/images/:imageId - Headers:
Authorization: Bearer <token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Target product ID |
imageId | string | ✅ | Image ID to delete |
Example Request:
curl -X DELETE "{{host}}/products/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/images/image-uuid-123" \
-H "Authorization: Bearer <access-token>"
16. Create Product Variant
Creates a new variant for an existing product.
Request:
- Method:
POST - Path:
/products/:productId/variants - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✅ | Product variant title |
description | string | ❌ | Variant description |
sku | string | ❌ | Stock keeping unit identifier |
imageIds | array of strings | ❌ | Array of image identifiers associated with the variant |
price | object | ❌ | Pricing details (see below) |
Price Object:
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | ❌ | Price amount |
currency | string | ❌ | ISO currency code |
taxIncluded | boolean | ❌ | Whether tax is included in amount |
taxable | boolean | ❌ | Whether the variant is taxable |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique variant identifier |
productId | string | Parent product ID |
title | string | Variant title |
description | string | Variant description |
sku | string | Stock keeping unit |
imageIds | array | Array of image IDs |
price | object | Pricing information |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Request body requires
title; all other fields optional - Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST "{{host}}/products/product-123/variants" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"title": "Large Size",
"description": "Large variant of the product",
"sku": "PROD-LG-001",
"price": {
"amount": 29.99,
"currency": "USD",
"taxIncluded": false,
"taxable": true
}
}'
Success Response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "variant-456",
"productId": "product-123",
"title": "Large Size",
"description": "Large variant of the product",
"sku": "PROD-LG-001",
"price": {
"amount": 29.99,
"currency": "USD",
"taxIncluded": false,
"taxable": true
},
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
17. List Product Variants
Retrieves all variants for a specific product with pagination.
Request:
- Method:
GET - Path:
/products/:productId/variants - Authorization: None required
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | ❌ | Page number for pagination (1-1000) |
limit | number | ❌ | Number of results per page (1-50) |
Response Body: Paginated response with variants array and metadata.
Response Structure:
{
"data": [
{
"id": "string",
"productId": "string",
"title": "string",
"description": "string",
"sku": "string",
"imageIds": ["string"],
"price": {
"amount": number,
"currency": "string",
"taxIncluded": boolean,
"taxable": boolean
},
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}
Validation:
- Schema Validation: Path parameter validation and pagination query parameters
- Route Validators: None
Example Request:
curl "{{host}}/products/product-123/variants?page=1&limit=20"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "variant-456",
"productId": "product-123",
"title": "Large Size",
"description": "Large variant",
"sku": "PROD-LG-001",
"imageIds": [],
"price": {
"amount": 29.99,
"currency": "USD",
"taxIncluded": false,
"taxable": true
},
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 20,
"total": 5,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}
18. Get Product Variant
Retrieves a specific product variant by ID.
Request:
- Method:
GET - Path:
/products/:productId/variants/:productVariantId - Headers:
Authorization: Bearer <token> - Authorization: Bearer token required
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
productVariantId | string | ✅ | Variant ID |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique variant identifier |
productId | string | Parent product ID |
title | string | Variant title |
description | string | Variant description |
sku | string | Stock keeping unit |
imageIds | array | Array of image IDs |
price | object | Pricing information |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: Path parameter validation (productId and productVariantId required)
- Route Validators:
- Require authenticated request (bearer token)
Example Request:
curl "{{host}}/products/product-123/variants/variant-456" \
-H "Authorization: Bearer <access-token>"
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "variant-456",
"productId": "product-123",
"title": "Large Size",
"description": "Large variant of the product",
"sku": "PROD-LG-001",
"imageIds": [],
"price": {
"amount": 29.99,
"currency": "USD",
"taxIncluded": false,
"taxable": true
},
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
Error Responses:
401 Unauthorized: Authentication failed404 Not Found: Product variant not found500 Internal Server Error: Database operation failed
19. Update Product Variant
Updates an existing product variant with partial data.
Request:
- Method:
PATCH - Path:
/products/:productId/variants/:productVariantId - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
productVariantId | string | ✅ | Variant ID to update |
Request Body (all fields optional):
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ❌ | Product variant title |
description | string | ❌ | Variant description |
sku | string | ❌ | Stock keeping unit identifier |
imageIds | array of strings | ❌ | Array of image identifiers associated with the variant |
price | object | ❌ | Pricing details (see below) |
Price Object (all fields optional):
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | ❌ | Price amount |
currency | string | ❌ | ISO currency code |
taxIncluded | boolean | ❌ | Whether tax is included in amount |
taxable | boolean | ❌ | Whether the variant is taxable |
Response Body:
| Field | Type | Description |
|---|---|---|
id | string | Unique variant identifier |
productId | string | Parent product ID |
title | string | Updated variant title |
description | string | Updated variant description |
sku | string | Updated stock keeping unit |
imageIds | array | Updated array of image IDs |
price | object | Updated pricing information |
createdAt | string | Creation timestamp |
updatedAt | string | Last update timestamp |
Validation:
- Schema Validation: All fields optional; no additional properties allowed
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X PATCH "{{host}}/products/product-123/variants/variant-456" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"price": {
"amount": 34.99,
"currency": "USD"
}
}'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "variant-456",
"productId": "product-123",
"title": "Large Size",
"description": "Large variant of the product",
"sku": "PROD-LG-001",
"imageIds": [],
"price": {
"amount": 34.99,
"currency": "USD",
"taxIncluded": false,
"taxable": true
},
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T14:22:15.789Z"
}
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: Non-admin user attempting to update variant404 Not Found: Product variant not found500 Internal Server Error: Database operation failed
20. Delete Product Variant
Removes a product variant.
Request:
- Method:
DELETE - Path:
/products/:productId/variants/:productVariantId - Headers:
Authorization: Bearer <token> - Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
productVariantId | string | ✅ | Variant ID to delete |
Response Body: No response body (204 No Content)
Validation:
- Schema Validation: Path parameter validation (productId and productVariantId required)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X DELETE "{{host}}/products/product-123/variants/variant-456" \
-H "Authorization: Bearer <access-token>"
Success Response:
HTTP/1.1 204 No Content
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: Non-admin user attempting to delete variant500 Internal Server Error: Database operation failed
21. Create Product Variants in Bulk
Creates multiple product variants at once (1-100 variants per request).
Request:
- Method:
POST - Path:
/product/:productId/variants/bulk - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
Request Body:
Array of variant objects (1-100 items), each requiring title.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✅ | Product variant title |
description | string | ❌ | Variant description |
sku | string | ❌ | Stock keeping unit identifier |
imageIds | array of strings | ❌ | Array of image identifiers |
price | object | ❌ | Pricing details |
Response Body: Array of created variant objects.
Validation:
- Schema Validation: Array of variant objects (1-100 items), each requires
title - Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST "{{host}}/product/product-123/variants/bulk" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '[
{
"title": "Small Size",
"sku": "PROD-SM-001",
"price": {
"amount": 19.99,
"currency": "USD"
}
},
{
"title": "Medium Size",
"sku": "PROD-MD-001",
"price": {
"amount": 24.99,
"currency": "USD"
}
}
]'
Success Response:
HTTP/1.1 201 Created
Content-Type: application/json
[
{
"id": "variant-789",
"productId": "product-123",
"title": "Small Size",
"sku": "PROD-SM-001",
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
},
{
"id": "variant-790",
"productId": "product-123",
"title": "Medium Size",
"sku": "PROD-MD-001",
"createdAt": "2025-01-15T10:30:00.100Z",
"updatedAt": "2025-01-15T10:30:00.100Z"
}
]
22. Update Product Variants in Bulk
Updates multiple product variants at once with the same data (1-100 variants per request).
Request:
- Method:
PATCH - Path:
/product/:productId/variants/bulk - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
ids | array of strings | ✅ | Array of variant IDs to update (1-100 items) |
data | object | ✅ | Update data to apply to all variants (see below) |
Data Object (all fields optional):
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ❌ | Product variant title |
description | string | ❌ | Variant description |
sku | string | ❌ | Stock keeping unit identifier |
imageIds | array of strings | ❌ | Array of image identifiers |
price | object | ❌ | Pricing details |
Response Body: Array of updated variant objects.
Validation:
- Schema Validation:
idsarray (1-100 items) anddataobject required - Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X PATCH "{{host}}/product/product-123/variants/bulk" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"ids": ["variant-456", "variant-789"],
"data": {
"price": {
"amount": 29.99,
"currency": "USD"
}
}
}'
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"id": "variant-456",
"productId": "product-123",
"title": "Large Size",
"price": {
"amount": 29.99,
"currency": "USD"
},
"updatedAt": "2025-01-15T14:22:15.789Z"
},
{
"id": "variant-789",
"productId": "product-123",
"title": "Small Size",
"price": {
"amount": 29.99,
"currency": "USD"
},
"updatedAt": "2025-01-15T14:22:15.789Z"
}
]
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: Non-admin user attempting to update variants404 Not Found: One or more product variants not found500 Internal Server Error: Database operation failed
23. Delete Product Variants in Bulk
Deletes multiple product variants at once (1-100 variants per request).
Request:
- Method:
POST - Path:
/product/:productId/variants/bulk-delete - Headers:
Content-Type: application/jsonAuthorization: Bearer <token>
- Authorization: Bearer token required (admin only)
URL Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | ✅ | Parent product ID |
Request Body: Array of variant IDs to delete (1-100 items).
Response Body: No response body (204 No Content)
Validation:
- Schema Validation: Array of variant ID strings (1-100 items)
- Route Validators:
- Require authenticated request (bearer token)
- Require admin role
Example Request:
curl -X POST "{{host}}/product/product-123/variants/bulk-delete" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '["variant-456", "variant-789"]'
Success Response:
HTTP/1.1 204 No Content
Error Responses:
401 Unauthorized: Authentication failed403 Forbidden: Non-admin user attempting to delete variants500 Internal Server Error: Database operation failed
⚙️ Configuration Options
Service Configuration
interface ProductServiceConfiguration {
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 product 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 productConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret'
},
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001'
}
}
};
🚨 Error Handling
All product 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 | Failed to create product | Database insert operation failed to return an inserted ID |
| 400 | Failed to update product | Update operation doesn't modify any data (no changes detected) |
| 400 | Failed to create products | Batch creation operation failed |
| 400 | Failed to update products | Batch update operation failed |
| 400 | Failed to delete products | Batch deletion operation failed |
| 400 | Failed to copy product | Product copy operation failed |
| 400 | Failed to copy products | Batch copy operation failed |
| 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 | Product not found | Product doesn't exist for the requested operation |
| 500 | Failed to create product | Database connection issues or unexpected failures during creation |
| 500 | Failed to get product | Database connection issues or unexpected failures during retrieval |
| 500 | Failed to find products | Database connection issues, invalid filter syntax, or unexpected failures during listing |
| 500 | Failed to update product | Database connection issues or unexpected failures during update |
| 500 | Failed to delete product | Database connection issues or unexpected failures during deletion |
| 500 | Failed to copy product | Database connection issues or unexpected failures during copying |
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 'description'"
]
}
}
🔗 Related Documentation
- 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