Skip to main content
Version: 0.13.0 (Previous)

👤 Profile Service

Testing Status

The Profile Service provides a complete REST API for managing profile 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 {profileService} = services;
const {withMongo} = drivers;

const connectToDatabase = withMongo('mongodb://localhost:27017/?authSource=admin', 'dev', 'user', 'password');

express()
.use(
profileService(
{
...(await connectToDatabase('profiles')),
...(await connectToDatabase('identities')),
...(await connectToDatabase('organizations')),
...(await connectToDatabase('products')),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
authMode: 'bearer', // or 'cookie'
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
},
// Optional third argument: { fileStorageDriver } — required for avatar upload URLs / avatar URL normalization
),
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('Server running'));

📋 Endpoint Summary

MethodPathDescriptionAuthorization
POST/profilesCreate a new profileBearer token required
GET/profiles/:profileIdRetrieve a profile by IDBearer token required (admin or profile owner)
GET/profilesList/filter profilesBearer token required (admin only)
GET/profiles/identities/:identityIdRetrieve profiles by identity IDBearer token required (self-access only)
PATCH/profiles/:profileIdUpdate a profileBearer token required (admin or profile owner)
DELETE/profiles/:profileIdDelete a profileBearer token required (admin or profile owner)

File Upload Operations

MethodPathDescriptionAuthorization
GET/profiles/:profileId/avatar-upload-urlGet signed URL to upload profile avatarBearer token required (admin or profile owner)

Profile Follow Operations

MethodPathDescriptionAuthorization
PUT/profiles/:profileId/profile-follows/:followProfileIdCreate a profile follow relationshipBearer token required (admin or profile owner)
DELETE/profiles/:profileId/profile-follows/:followProfileIdDelete a profile follow relationshipBearer token required (admin or profile owner)
GET/profiles/:profileId/followersGet profile followers with paginationBearer token required (admin or profile owner)

Organization Follow Operations

MethodPathDescriptionAuthorization
PUT/profiles/:profileId/organization-follows/:followOrganizationIdCreate an organization follow relationshipBearer token required (admin or profile owner)
DELETE/profiles/:profileId/organization-follows/:followOrganizationIdDelete an organization follow relationshipBearer token required (admin or profile owner)

Product Like Operations

MethodPathDescriptionAuthorization
PUT/profiles/:profileId/product-likes/:likeProductIdCreate a product like relationshipBearer token required (admin or profile owner)
DELETE/profiles/:profileId/product-likes/:likeProductIdDelete a product like relationshipBearer token required (admin or profile owner)

🗄️ Entity Schema

The profile entity combines base fields (auto-generated) with profile-specific data:

{
"id": "string",
"createdAt": "string (datetime)",
"updatedAt": "string (datetime)",
"identityId": "string",
"name": "string",
"avatar": {
"url": "string",
"type": "string"
} | null,
"profileFollows": [
{
"followProfileId": "string"
}
],
"organizationFollows": [
{
"followOrganizationId": "string"
}
],
"productLikes": [
{
"likeProductId": "string"
}
]
}

Field Details

FieldTypeAuto-GeneratedRequiredDescription
idstringUnique identifier (UUID)
createdAtdatetimeCreation timestamp
updatedAtdatetimeLast modification timestamp
identityIdstringLinked identity identifier
namestringProfile's display name
avatarobject or nullProfile avatar metadata or null
profileFollowsarrayArray of profile follow relationships (initialized as empty array)
organizationFollowsarrayArray of organization follow relationships (initialized as empty array)
productLikesarrayArray of product like relationships (initialized as empty array)

📝 Note: Auto-generated fields are set by the service and should not be included in create/update requests.

🖼️ Avatar: The avatar field can be null or an object with storage metadata.


🔐 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.

🍪 Cookie auth: When authMode: 'cookie', protected routes read the access token from cookies instead of the Bearer header. Host apps must register cookie-parser.


🔧 API Endpoints

1. Create Profile

Creates a new profile with the provided information.

Request:

  • Method: POST
  • Path: /profiles
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearer token required

Request Body:

FieldTypeRequiredDescription
identityIdstringLinked identity identifier
namestringProfile's display name
avatarobject or nullOptional avatar metadata ({ objectId, type })

Response Body:

FieldTypeDescription
idstringUnique profile identifier
identityIdstringLinked identity identifier
namestringProfile's display name
avatarobject or nullProfile avatar metadata or null
profileFollowsarrayArray of profile follow relationships
organizationFollowsarrayArray of organization follow relationships
productLikesarrayArray of product like relationships
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Enforced automatically (identityId and name required; optional avatar; no additional properties)
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or self for the target identity

Example Request:

curl -X POST {{host}}/profiles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"name": "John Doe"
}'

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"name": "John Doe",
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"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 'identityId'",
"request body must have required property 'name'",
"request body must NOT have additional properties"
]
}
}

When no authorization token is provided:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": {
"message": "token could not be verified"
}
}

When database insert operation fails to return an inserted ID:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Failed to create profile"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to create profile"
}
}

2. Get Profile by ID

Retrieves a specific profile by their unique ID.

Request:

  • Method: GET
  • Path: /profiles/:profileId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearer token required (admin or profile owner)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringUnique user profile identifier

Response Body:

FieldTypeDescription
idstringUnique profile identifier
identityIdstringLinked identity identifier
namestringProfile's display name
avatarobject or nullProfile avatar metadata or null
profileFollowsarrayArray of profile follow relationships
organizationFollowsarrayArray of organization follow relationships
productLikesarrayArray of product like relationships
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Path parameter validation (profileId required)
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the target profile

Example Request:

curl {{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Authorization: Bearer your-access-token-here"

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"name": "John Doe Updated",
"avatar": null,
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
}

Error Responses:

When no authorization token is provided:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": {
"message": "token could not be verified"
}
}

When the user is not authorized to access this resource:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"message": "Identity is not authorized to access this resource"
}
}

When no user exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to get profile"
}
}

3. List Profiles

Retrieves a list of profiles with optional filtering and pagination.

Request:

  • Method: GET
  • Path: /profiles
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearer token required (admin only)

Query Parameters:

ParameterTypeRequiredDescription
identityIdstringFilter users by identity identifier
namestringFilter users by display name
pagenumberPage number (1-1000)
limitnumberItems per page (1-50)

Response Body:

FieldTypeDescription
dataarrayArray of user objects
metadataobjectResponse metadata
metadata.paginationobjectPagination information

Each user object in the data array contains:

FieldTypeDescription
idstringUnique profile identifier
identityIdstringLinked identity identifier
namestringProfile's display name
avatarobject or nullProfile avatar metadata or null
profileFollowsarrayArray of profile follow relationships
organizationFollowsarrayArray of organization follow relationships
productLikesarrayArray of product like relationships
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Query parameter validation for name (string), page and limit (integers with min/max constraints)
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role

Example Requests:

List all profiles:

curl {{host}}/profiles \
-H "Authorization: Bearer <access-token>"

Filter by identity ID:

curl "{{host}}/profiles?identityId=811ff0a3-a26f-447b-b68a-dd83ea4000b9" \
-H "Authorization: Bearer <access-token>"

Filter by name:

curl "{{host}}/profiles?name=John" \
-H "Authorization: Bearer <access-token>"

Combine filters:

curl "{{host}}/profiles?name=John&page=1&limit=20" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"data": [
{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"name": "John Doe",
"avatar": null,
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T09:41:22.552Z"
},
{
"id": "8fec096b-1bc7-5bfe-c827-3600e8fe2790",
"identityId": "922ff1b4-b37g-558c-c79b-ee94fb5001c0",
"name": "Jane Smith",
"avatar": {
"url": "https://storage.example.com/avatars/avatar123.png",
"type": "image/png"
},
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"createdAt": "2024-05-29T10:15:33.441Z",
"updatedAt": "2024-05-29T10:15:33.441Z"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 20,
"total": 2,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}

Error Responses:

When an unexpected error occurs (database connection issues, invalid filter syntax, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to find profiles"
}
}

4. Update Profile

Updates an existing user with partial data.

Request:

  • Method: PATCH
  • Path: /profiles/:profileId
  • Headers:
    • Content-Type: application/json
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearer token required (admin or profile owner)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringUnique user profile identifier

Request Body (required, all fields optional):

FieldTypeRequiredDescription
avatarobject or nullProfile avatar metadata or null
namestringProfile's display name

Note: While all fields in the request body are optional, the request body itself is required and cannot be empty. Sending an empty body will result in a 400 error.

Response Body:

FieldTypeDescription
idstringUnique profile identifier
identityIdstringLinked identity identifier
namestringUpdated user's display name
avatarobject or nullUpdated user avatar metadata or null
profileFollowsarrayArray of profile follow relationships
organizationFollowsarrayArray of organization follow relationships
productLikesarrayArray of product like relationships
createdAtstringCreation timestamp
updatedAtstringLast update timestamp

Validation:

  • Schema Validation: Enforced automatically (only name and avatar allowed; no additional properties)
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the target profile

Example Request:

curl -X PATCH {{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{"name": "John Doe Updated"}'

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"id": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"identityId": "811ff0a3-a26f-447b-b68a-dd83ea4000b9",
"name": "John Doe Updated",
"avatar": null,
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"createdAt": "2024-05-28T09:41:22.552Z",
"updatedAt": "2024-05-28T14:22:15.789Z"
}

Error Responses:

When request body is empty or missing:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Request body is required"
}
}

When no user exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}

When the update operation doesn't modify any data (no changes detected):

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"message": "Failed to update profile"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to update profile"
}
}

5. Delete Profile

Permanently deletes a user from the system.

Request:

  • Method: DELETE
  • Path: /profiles/:profileId
  • Headers:
    • Authorization: Bearer <token>
    • x-nb-fingerprint: <device-fingerprint>
  • Authorization: Bearer token required (admin or profile owner)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringUnique user profile identifier

Response Body:

FieldTypeDescription
No response body-Delete endpoint returns no response body on success

Validation:

  • Schema Validation: None (DELETE request)
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the target profile

Example Request:

curl -X DELETE {{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2 \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Error Responses:

When no user exists with the provided ID:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}

When an unexpected error occurs (database connection issues, etc.):

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Failed to delete profile"
}
}

6. Get Avatar Upload URL

Generates a pre-signed URL for securely uploading a user avatar image. Returns an object ID and a temporary signed URL.

Request:

  • Method: GET
  • Path: /profiles/:profileId/avatar-upload-url
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringTarget user profile ID

Query Parameters:

ParameterTypeRequiredDescription
contentTypestringImage MIME type (enum: image/jpeg, image/png, image/webp, image/gif, image/svg+xml, image/avif, image/bmp, image/x-icon, image/tiff, image/heif, image/heic)
contentLengthnumberFile size in bytes (max 10MB = 10,000,000)

Response Body:

FieldTypeDescription
objectIdstringGenerated storage object ID for the avatar
urlstringPre-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 or owner of the target profile

Example Request:

curl "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/avatar-upload-url?contentType=image/jpeg&contentLength=524288" \
-H "Authorization: Bearer <access-token>"

Success Response:

{
"objectId": "7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2",
"url": "https://storage.googleapis.com/bucket/avatars/...&X-Goog-Expires=900&X-Goog-Signature=..."
}

7. Find Profiles by Identity ID

Retrieves paginated user profiles associated with a specific identity ID, with automatic avatar URL normalization and self-access control.

Request:

  • Method: GET
  • Path: /profiles/identities/:identityId
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (self-access only - users can only view their own profiles)

URL Parameters:

ParameterTypeRequiredDescription
identityIdstringTarget identity ID to retrieve profiles for

Query Parameters:

ParameterTypeRequiredDefaultDescription
pagenumber1Page number for pagination (1-1000)
limitnumber10Number of profiles per page (1-50)

Response (200 - Success):

{
"data": [
{
"id": "profile-123",
"identityId": "identity-123",
"name": "John Doe",
"avatar": {
"url": "https://cdn.example.com/avatars/profile-123.jpg",
"type": "image/jpeg"
},
"profileFollows": [],
"organizationFollows": [],
"productLikes": [],
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"metadata": {
"pagination": {
"hasNext": false,
"hasPrev": false,
"limit": 10,
"page": 1,
"total": 1,
"totalPages": 1
}
}
}

Error Responses:

  • 401 Unauthorized: Invalid token
  • 403 Forbidden: Identity ID does not match
  • 500 Internal Server Error: Database or avatar processing errors

Use Cases:

  • Mobile apps retrieving user profiles for the authenticated identity
  • Web applications displaying user profile information
  • Profile management interfaces showing associated profiles

8. Create Profile Follow

Creates a social follow relationship between two user profiles, allowing users to follow each other for social networking features.

Request:

  • Method: PUT
  • Path: /profiles/:profileId/profile-follows/:followProfileId
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)
  • Body: Empty (no request body required)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringID of the profile performing the follow
followProfileIdstringID of the profile to be followed

Response Body: Empty (204 No Content)

Validation:

  • Schema Validation: Path parameter validation for profile IDs
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the source profile
    • Both profiles must exist in the database
  • Business Logic: Prevents duplicate follows of the same profile

Error Responses:

  • 400 Bad Request: Invalid profile IDs or malformed request
  • 401 Unauthorized: Missing or invalid authentication token
  • 403 Forbidden: User lacks permission (not admin or profile owner)
  • 404 Not Found: One or both profiles don't exist
  • 409 Conflict: Profile is already being followed
  • 500 Internal Server Error: Database operation failed

Example Request:

curl -X PUT "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/profile-follows/f8c9b2a1-3d4e-5f6g-7h8i-9j0k1l2m3n4o5p" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Duplicate Follow Response:

HTTP/1.1 409 Conflict
Content-Type: application/json

{
"error": {
"message": "Profile is already followed"
}
}

Use Cases:

  • Social networking features
  • Content personalization based on followed profiles
  • Building follower/following networks
  • Community engagement tracking

9. Delete Profile Follow

Deletes a social follow relationship between two user profiles (unfollowing), allowing users to remove connections to other profiles.

Request:

  • Method: DELETE
  • Path: /profiles/:profileId/profile-follows/:followProfileId
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)
  • Body: Empty (no request body required)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringID of the profile performing the unfollow
followProfileIdstringID of the profile to be unfollowed

Response Body: Empty (204 No Content)

Validation:

  • Schema Validation: Path parameter validation for profile IDs
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the source profile
    • Both profiles must exist in the database
    • Follow relationship must exist
  • Business Logic: Returns appropriate error if follow relationship doesn't exist

Error Responses:

  • 400 Bad Request: Invalid profile IDs or malformed request
  • 401 Unauthorized: Missing or invalid authentication token
  • 403 Forbidden: User lacks permission (not admin or profile owner)
  • 404 Not Found: Profile or follow relationship doesn't exist
  • 500 Internal Server Error: Database operation failed

Example Request:

curl -X DELETE "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/profile-follows/f8c9b2a1-3d4e-5f6g-7h8i-9j0k1l2m3n4o5p" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Follow Not Found Response:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile follow not found"
}
}

Use Cases:

  • Social networking features - unfollowing users
  • Relationship management - removing connections
  • Privacy control - managing social connections
  • Community engagement tracking

10. Get Profile Followers

Retrieves a paginated list of followers for a specific profile, with normalized avatar URLs.

Request:

  • Method: GET
  • Path: /profiles/:profileId/followers
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)
  • Body: Empty (no request body required)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringID of the profile to retrieve followers for

Query Parameters:

ParameterTypeRequiredDefaultDescription
pagenumber1Page number for pagination (1-1000)
limitnumber20Number of results per page (1-50)

Response Body: JSON with paginated follower list and metadata

Response Structure:

{
"data": [
{
"id": "string",
"name": "string",
"avatar": {
"url": "string",
"type": "string"
}
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number,
"hasNext": boolean,
"hasPrev": boolean
}
}
}

Validation:

  • Schema Validation: Path parameter validation for profile ID
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the profile
    • Profile must exist in the database
  • Business Logic: Returns paginated list with avatar URL normalization

Error Responses:

  • 400 Bad Request: Invalid profile ID or malformed request
  • 401 Unauthorized: Missing or invalid authentication token
  • 403 Forbidden: User lacks permission (not admin or profile owner)
  • 404 Not Found: Profile doesn't exist
  • 500 Internal Server Error: Database operation failed

Example Request:

curl -X GET "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/followers?page=1&limit=20" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"data": [
{
"id": "user-456",
"name": "John Doe",
"avatar": {
"url": "https://storage.example.com/avatars/avatar123.png",
"type": "image/png"
}
},
{
"id": "user-789",
"name": "Jane Smith",
"avatar": {
"url": "https://storage.example.com/avatars/avatar456.jpg",
"type": "image/jpeg"
}
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 20,
"total": 50,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}

Profile Not Found Response:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}

Use Cases:

  • Social networking features - displaying follower lists
  • Analytics - tracking follower counts and growth
  • Relationship management - viewing and managing social connections
  • Community engagement - follower-based content distribution

Key Features:

  • Pagination: Efficient handling of large follower lists
  • Avatar Normalization: Automatic conversion of storage references to accessible URLs
  • Flexible Query: Customizable page size and page number
  • Performance: Optimized MongoDB queries using $elemMatch operator

11. Create Organization Follow

Creates a social follow relationship between a user profile and an organization, allowing users to subscribe to organization updates.

Request:

  • Method: PUT
  • Path: /profiles/:profileId/organization-follows/:followOrganizationId
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)
  • Body: Empty (no request body required)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringID of the profile performing the follow
followOrganizationIdstringID of the organization to be followed

Response Body: Empty (204 No Content)

Validation:

  • Schema Validation: Path parameter validation for profile and organization IDs
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the source profile
    • Both profile and organization must exist in the database
    • Organization must not already be followed
  • Business Logic: Returns appropriate error if organization is already followed

Error Responses:

  • 400 Bad Request: Invalid profile/organization IDs or malformed request
  • 401 Unauthorized: Missing or invalid authentication token
  • 403 Forbidden: User lacks permission (not admin or profile owner)
  • 404 Not Found: Profile or organization doesn't exist
  • 409 Conflict: Organization is already followed
  • 500 Internal Server Error: Database operation failed

Example Request:

curl -X PUT "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/organization-follows/org-abc-123" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Organization Already Followed Response:

HTTP/1.1 409 Conflict
Content-Type: application/json

{
"error": {
"message": "Organization is already followed"
}
}

Profile/Organization Not Found Response:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}
HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Organization not found"
}
}

Use Cases:

  • Social networking features - following organizations
  • Relationship management - creating connections to organizations
  • Content subscription - allowing users to subscribe to organization updates
  • Community engagement - organization-based content distribution

Key Features:

  • Duplicate Prevention: Prevents a profile from following the same organization multiple times
  • Authorization: Ensures only authorized users can create follow relationships
  • Validation: Comprehensive checks for profile and organization existence
  • Performance: Efficient MongoDB operations for follow creation

12. Delete Organization Follow

Removes a social follow relationship between a user profile and an organization, allowing users to unsubscribe from organization updates.

Request:

  • Method: DELETE
  • Path: /profiles/:profileId/organization-follows/:followOrganizationId
  • Headers: Authorization: Bearer <token>
  • Authorization: Bearer token required (admin or profile owner)
  • Body: Empty (no request body required)

URL Parameters:

ParameterTypeRequiredDescription
profileIdstringID of the profile removing the follow
followOrganizationIdstringID of the organization to be unfollowed

Response Body: Empty (204 No Content)

Validation:

  • Schema Validation: Path parameter validation for profile and organization IDs
  • Route Validators:
    • Require authenticated request (bearer token)
    • Require admin role or owner of the source profile
    • Both profile and organization must exist in the database
    • Organization follow relationship must exist to be deleted
  • Business Logic: Returns 404 if follow relationship doesn't exist (not silent success)

Error Responses:

  • 400 Bad Request: Invalid profile/organization IDs or malformed request
  • 401 Unauthorized: Missing or invalid authentication token
  • 403 Forbidden: User lacks permission (not admin or profile owner)
  • 404 Not Found: Profile or follow relationship doesn't exist
  • 500 Internal Server Error: Missing organization currently bubbles up as an unmapped OrganizationNotFoundError
  • 500 Internal Server Error: Database operation failed

Example Request:

curl -X DELETE "{{host}}/profiles/7edfb95f-0ab6-4adc-a6e1-2a86a2f1e6d2/organization-follows/org-abc-123" \
-H "Authorization: Bearer <access-token>"

Success Response:

HTTP/1.1 204 No Content

Organization Follow Not Found Response:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Organization follow not found"
}
}

Profile Not Found Response:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
"error": {
"message": "Profile not found"
}
}

Organization Not Found Response:

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
"error": {
"message": "Organization not found"
}
}

Use Cases:

  • Social networking features - unfollowing organizations
  • Relationship management - removing connections to organizations
  • Content subscription management - unsubscribing from organization updates
  • Community engagement - dynamic organization relationship management

Key Features:

  • Existence Validation: Returns 404 if follow relationship doesn't exist (prevents silent failures)
  • Authorization: Ensures only authorized users can delete follow relationships
  • Validation: Comprehensive checks for profile, organization, and follow relationship existence
  • Performance: Efficient MongoDB $pull operation with existence check

13. Create Product Like

Creates a product like relationship for a user profile (favoriting a product).

Request:

  • Method: PUT
  • Path: /profiles/:profileId/product-likes/:likeProductId
  • Headers:
    • Authorization: Bearer <access_token>
    • x-nb-fingerprint: <device_fingerprint>
  • Path Parameters:
    • profileId (string, required): ID of the profile that will like the product
    • likeProductId (string, required): ID of the product to be liked
  • Body: Empty (no request body required)

Response:

Success (204 No Content):

(Empty body)

Error Responses:

{
"error": {
"message": "Validation Error",
"data": ["path parameter 'profileId' is required", "path parameter 'likeProductId' is required"]
}
}
{
"error": {
"message": "token could not be verified"
}
}
{
"error": {
"message": "Identity is not authorized to access this resource"
}
}
{
"error": {
"message": "Profile not found"
}
}
{
"error": {
"message": "Product not found"
}
}
{
"error": {
"message": "Product is already liked"
}
}
{
"error": {
"message": "Failed to create product like"
}
}

Use Cases:

  • Product engagement features - liking or favoriting products
  • Wish list management - adding products to favorites
  • Product recommendation - tracking user preferences
  • E-commerce features - product interaction tracking

Key Features:

  • Duplicate Prevention: Returns 409 if product is already liked (prevents duplicate entries)
  • Authorization: Ensures only authorized users can create product likes
  • Validation: Comprehensive checks for profile and product existence
  • Performance: Efficient MongoDB $push operation with duplicate check using $ne operator

14. Delete Product Like

Deletes a product like relationship from a user profile (unfavoriting a product).

Request:

  • Method: DELETE
  • Path: /profiles/:profileId/product-likes/:likeProductId
  • Headers:
    • Authorization: Bearer <access_token>
    • x-nb-fingerprint: <device_fingerprint>
  • Path Parameters:
    • profileId (string, required): ID of the profile that will unlike the product
    • likeProductId (string, required): ID of the product to be unliked
  • Body: Empty (no request body required)

Response:

Success (204 No Content):

(Empty body)

Error Responses:

{
"error": {
"message": "Validation Error",
"data": ["path parameter 'profileId' is required", "path parameter 'likeProductId' is required"]
}
}
{
"error": {
"message": "token could not be verified"
}
}
{
"error": {
"message": "Identity is not authorized to access this resource"
}
}
{
"error": {
"message": "Profile not found"
}
}
{
"error": {
"message": "Product not found"
}
}
{
"error": {
"message": "Product like not found"
}
}
{
"error": {
"message": "Failed to delete product like"
}
}

Use Cases:

  • Product engagement features - unliking or removing from favorites
  • Wish list management - removing products from favorites
  • Product recommendation - updating user preferences
  • E-commerce features - managing product interactions

Key Features:

  • Existence Validation: Returns 404 if like relationship doesn't exist (prevents silent failures)
  • Authorization: Ensures only authorized users can delete product likes
  • Validation: Comprehensive checks for profile, product, and like relationship existence
  • Performance: Efficient MongoDB $pull operation with existence check

🗄️ Datastore

CollectionRequiredDescription
profilesProfile documents and follow/like relationships
identitiesIdentity ownership and authorization checks
organizationsOrganization follow validation
productsProduct like validation

⚙️ Configuration Options

Service Configuration

interface ProfileServiceConfiguration {
authSecrets: {
authEncSecret: string; // JWT encryption secret
authSignSecret: string; // JWT signing secret
};
authMode?: 'bearer' | 'cookie'; // Default: bearer-style Authorization header
identity?: {
typeIds?: {
admin: string; // Admin identity type identifier
guest: string; // Guest identity type identifier
regular: string; // Regular identity type identifier
};
};
organization?: {
roles?: {
admin: string;
member: string;
owner: string;
};
};
}

🖼️ Avatar uploads: Pass an optional third argument { fileStorageDriver } when mounting the service to enable GET /profiles/:profileId/avatar-upload-url.

🍪 Cookie auth: When authMode: 'cookie', protected routes read the access token from cookies. Host apps must register cookie-parser middleware.

Configuration Details

The profile service configuration is organized into logical groups for security, identity types, and organization roles.

🔐 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 encryption
    • authSignSecret: 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"
    • 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"
    • regular: Regular user type identifier
      • Type: string
      • Description: Custom identifier for regular users
      • Use Case: Standard user access permissions
      • Example: "user", "member", "customer"

🏢 Organization Role Settings

organization.roles - Organization role identifier configuration

  • Type: { admin?: string; member?: string; owner?: string }
  • Description: Custom role identifiers used for organization-related authorization checks
  • Default: undefined

🔑 Auth Mode

authMode - Authentication transport

  • Type: 'bearer' | 'cookie'
  • Default: bearer behavior when unset
  • Description: When 'cookie', protected routes use cookie-based access tokens (requires cookie-parser on the host app)

Example Configuration

const profileConfig = {
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET || 'your-enc-secret',
authSignSecret: process.env.AUTH_SIGN_SECRET || 'your-sign-secret',
},
authMode: 'bearer', // or 'cookie'
identity: {
typeIds: {
admin: '100',
guest: '000',
regular: '001',
},
},
organization: {
roles: {
admin: 'admin',
member: 'member',
owner: 'owner',
},
},
};

🚨 Error Handling

All profile service errors return JSON format with appropriate HTTP status codes:

Common Error Codes

StatusError MessageDescription
400Validation ErrorInvalid request body format or missing required fields
400Failed to create profileDatabase insert operation failed to return an inserted ID
400Failed to update profileUpdate operation doesn't modify any data (no changes detected)
401token could not be verifiedMissing or invalid authorization token
403Identity is not authorized to access this resourceInsufficient permissions
403Identity is not the owner of the resourceUser is not the owner of the target profile/resource
404Profile not foundUser doesn't exist for GET/PATCH operations
404Profile not foundUser doesn't exist for DELETE operations
409Profile already followed / Organization already followed / Product already likedConflict on follow or like when the relationship already exists
500Failed to create profileDatabase connection issues or unexpected failures during creation
500Failed to get profileDatabase connection issues or unexpected failures during retrieval
500Failed to find profilesDatabase connection issues, invalid filter syntax, or unexpected failures during listing
500Failed to update profileDatabase connection issues or unexpected failures during update
500Failed to delete profileDatabase 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 'identityId'", "request body must have required property 'name'"]
}
}