🛣️ Organization Routes
Organization routes provide pre-configured HTTP endpoints for organization management operations in NodeBlocks applications. These routes combine blocks, terminators, and validators to create complete API endpoints with proper authentication, authorization, and error handling.
🎯 Overview
Organization routes are designed to:
- Provide complete API endpoints for organization management operations
- Combine blocks with terminators for secure operations
- Include authentication and authorization checks
- Support functional composition patterns
- Handle logging and error management automatically
📋 Route Structure
Each organization route follows a consistent pattern:
- HTTP Method: Defines the operation type (GET, POST, PATCH, DELETE)
- Path: Specifies the endpoint URL with parameters
- Handler: Composed function chain using blocks and terminators
- Validators: Authentication and authorization checks
🔧 Available Organization Routes
createOrganizationRoute
Creates a new organization and returns the created resource.
Purpose: Handles organization creation with full resource retrieval
Route Details:
- Method:
POST - Path:
/organizations - Authentication: Required (Bearer token)
Blocks: createOrganization, getOrganizationById, calculateChildAncestors, normalizeLogoOfOwner
Terminators: normalizeOrganizationTerminator
Validators: isAuthenticated, checkIdentityType(['admin'])
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createOrganizationRoute);
getOrganizationRoute
Retrieves a specific organization by ID.
Purpose: Fetches organization data with access control
Route Details:
- Method:
GET - Path:
/organizations/:organizationId - Authentication: Required (Bearer token)
Blocks: getOrganizationById, normalizeLogoOfOwner
Terminators: normalizeOrganizationTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin', 'member'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getOrganizationRoute);
findOrganizationsRoute
Retrieves all organizations with normalized list format.
Purpose: Lists organizations with pagination and access control
Route Details:
- Method:
GET - Path:
/organizations - Authentication: Required (Bearer token)
Blocks: findOrganizations, normalizeLogosOfOwners
Terminators: normalizeOrganizationsListTerminator
Validators: isAuthenticated, checkIdentityType(['admin'])
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationsRoute);
updateOrganizationRoute
Updates an existing organization and returns the updated resource.
Purpose: Modifies organization data with access control
Route Details:
- Method:
PATCH - Path:
/organizations/:organizationId - Authentication: Required (Bearer token)
Blocks: updateOrganization, getOrganizationById, normalizeLogoOfOwner
Terminators: normalizeOrganizationTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateOrganizationRoute);
deleteOrganizationRoute
Deletes an organization by ID.
Purpose: Removes organization with access control
Route Details:
- Method:
DELETE - Path:
/organizations/:organizationId - Authentication: Required (Bearer token)
Blocks: getOrganizationById, deleteLogoOfOwner, deleteOrganization
Terminators: deleteOrganizationTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteOrganizationRoute);
getOrganizationMemberRoleRoute
Retrieves the role of a specific member within an organization.
Purpose: Fetches member role within organization
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/members/:identityId/role - Authentication: Required (Bearer token)
Blocks: getOrganizationById, buildOrganizationsForMemberByIdsQuery, findOrganizations, calculateMemberRole
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getOrganizationMemberRoleRoute);
checkOrganizationMemberExistenceRoute
Checks if a member exists within an organization.
Purpose: Verifies member membership in organization
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/members/check-existence - Authentication: Required (Bearer token)
Blocks: getOrganizationById, checkOrganizationMemberExistence
Terminators: normalizeOrganizationMemberExistenceTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.checkOrganizationMemberExistenceRoute);
findOrganizationMembersRoute
Retrieves all members within an organization.
Purpose: Lists organization members
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/members - Authentication: Required (Bearer token)
Blocks: findOrganizationMembers
Terminators: normalizeOrganizationMembersListTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationMembersRoute);
upsertOrganizationMembersRoute
Creates or updates members within an organization.
Purpose: Manages organization member memberships
Route Details:
- Method:
PATCH - Path:
/organizations/:organizationId/members - Authentication: Required (Bearer token)
Blocks: getOrganizationById, upsertOrganizationMembers
Terminators: upsertOrganizationMembersTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.upsertOrganizationMembersRoute);
deleteOrganizationMemberRoute
Removes a member from an organization.
Purpose: Removes member from organization membership
Route Details:
- Method:
DELETE - Path:
/organizations/:organizationId/members/:identityId - Authentication: Required (Bearer token)
Blocks: deleteOrganizationMember
Terminators: deleteOrganizationMemberTerminator
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.deleteOrganizationMemberRoute);
findOrganizationsForMemberRoute
Retrieves all organizations for a specific identity (member). Supports optional inclusion of inherited roles from descendant organizations via the includeInherited=true query parameter.
Purpose: Lists organizations where identity is a member, with optional inherited roles
Route Details:
- Method:
GET - Path:
/organizations/members/:identityId - Authentication: Required (Bearer token)
Blocks: buildOrganizationsForMemberByRoleQuery, findOrganizations, normalizeLogosOfOwners, buildOrganizationsWithDescendantsQuery, extractAncestors, buildOrganizationsForMemberByIdsQuery, calculateMemberRoleForOrganizations, normalizeOrganizationsForMember
Terminators: Formats organizations list with role information; success/error mapping via orThrow
Validators: isAuthenticated, some(checkIdentityType(['admin']), isSelf(['params', 'requestParams', 'identityId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationsForMemberRoute);
getLogoUploadUrlRoute
Generates signed upload URL for organization logo via GET /organizations/:organizationId/logo-upload-url.
Purpose: Issues a pre-signed URL to upload an organization logo securely.
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/logo-upload-url - Authentication: Required (Bearer token)
Blocks: generateSignedLogoUploadUrl
Terminators: Built-in success/error mapping via orThrow
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Use in feature composition:
export const logoUploadFeature = compose(getSignedImageUploadUrlSchema, getLogoUploadUrlRoute);
findOrganizationDescendantsRoute
Retrieves all descendant organizations for a given organization.
Purpose: Lists descendants in the organization tree; supports depth via ?depth=<n> query parameter
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/descendants - Authentication: Required (Bearer token)
Blocks: getOrganizationById, buildDescendantsQuery, findOrganizations, normalizeOrganizations
Terminators: Normalizes descendant organizations list with success/error mapping via orThrow
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner', 'admin'], ['params', 'requestParams', 'organizationId']))
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findOrganizationDescendantsRoute);
getCertificateUploadUrlRoute
Generates a signed upload URL for an organization certificate.
Purpose: Provides secure upload URLs for certificate files with automatic object ID generation
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/certificate-upload-url - Authentication: Required (Bearer token)
- Query Parameters:
contentType- Certificate MIME type (application/pdf,image/gif,image/jpeg,image/png)contentLength- File size in bytes (max 10MB)
Blocks: generateFileUploadUrl
Response: { objectId: string; url: string } - UUID and signed upload URL
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Handler Process:
- Validates authentication and authorization
- Generates UUID object ID
- Creates signed upload URL with file extension
- Returns object ID and URL for client upload
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.getCertificateUploadUrlRoute);
// Client usage:
const response = await fetch(
`/api/organizations/org-123/certificate-upload-url?contentType=application/pdf&contentLength=102400`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { objectId, url } = await response.json();
createChangeRequestRoute
Creates organization change request with automatic audit status update.
Purpose: Handles organization change requests with validation, certificate upload, and audit tracking
Route Details:
- Method:
POST - Path:
/organizations/:organizationId/change-requests - Authentication: Required (Bearer token)
- Request Body: At least 1 field required (name, address, certificate, qualifications, etc.)
- Response:
204 No Content- Empty response body on success
Blocks: getOrganizationById, validateOrganizationName, extractTokenFromAuthorizationHeader, checkToken, createChangeRequest, buildUpdateOrganizationAfterNewChangeRequestPayload, updateOrganization, normalizeEmptyBody
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Error Responses:
400 Bad Request- Invalid input, duplicate organization name, or invalid token401 Unauthorized- Authentication failed500 Internal Server Error- Database or file storage errors
Handler Process:
- Retrieves organization by ID
- Validates organization name uniqueness if provided
- Extracts and validates access token from Authorization header
- Creates change request with identityId from token
- Updates organization audit status to
waiting_for_review - Returns empty body with 204 status
Key Features:
- Automatic organization name uniqueness validation
- Token-based identity extraction for change request authorship
- Automatic audit status update to
waiting_for_review - Support for certificate images and certified qualifications
- Comprehensive error handling with specific error classes
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.createChangeRequestRoute);
// Client usage:
const response = await fetch(`/api/organizations/org-123/change-requests`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Updated Organization Name',
addressLine1: '123 Main Street',
certificateImage: {
objectId: cert-uuid',
type: 'application/pdf'
},
certifiedQualifications: [
{ name: 'ISO 9001', status: 'approved', value: '2024' }
]
})
});
// Returns 204 No Content on success
findChangeRequestsForOrganizationRoute
Retrieves change requests for a specific organization with pagination and file URL enrichment.
Purpose: Lists organization change requests with normalized data and signed download URLs for certificates
Route Details:
- Method:
GET - Path:
/organizations/:organizationId/change-requests - Authentication: Required (Bearer token)
Blocks: findChangeRequests, normalizeChangeRequests
Terminators: Response formatting with pagination metadata
Validators: isAuthenticated, some(checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Response Format:
{
"data": [
{
"id": "string",
"organizationId": "string",
"identityId": "string",
"name": "string",
"certificateImage": {
"objectId": "string",
"type": "string"
},
"certificateImageUrl": "string",
"createdAt": "string",
"updatedAt": "string"
}
],
"metadata": {
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"totalPages": 3,
"hasNext": true,
"hasPrev": false
}
}
}
Error Responses:
401 Unauthorized- Authentication failed403 Forbidden- User lacks admin privileges or organization ownership500 Internal Server Error- Database query failures or file URL generation errors
Handler Process:
- Authenticates user and validates organization access
- Retrieves change requests from database with pagination
- Normalizes each change request (removes
_id, generates certificate URLs) - Returns paginated response with normalized data
Key Features:
- Pagination support with configurable page size
- Automatic file URL generation for certificate images
- Graceful fallback when URL generation fails
- Access control for organization owners and admins
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.findChangeRequestsForOrganizationRoute);
// Client usage:
const response = await fetch(`/api/organizations/org-123/change-requests?page=1&limit=20`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const result = await response.json();
// Returns 200 OK with paginated change requests
updateOrganizationAsAdminRoute
Updates an organization as admin with extended field access and audit status validation.
Purpose: Provides admin-only organization updates including name changes, audit status, and certified fields
Route Details:
- Method:
PATCH - Path:
/admin/organizations/:organizationId/ - Authentication: Required (Bearer token)
- Authorization: Admin identity type only
- Request Body: At least 1 field (all fields optional)
- Response:
200 OK- Returns updated organization with normalized logo URL
Blocks: validateAuditStatus, updateOrganization, getOrganizationById, normalizeLogoOfOwner
Terminators: normalizeOrganizationTerminator
Validators: isAuthenticated, checkIdentityType(['admin'])
Error Responses:
400 Bad Request- Invalid audit status or validation failure401 Unauthorized- Authentication failed403 Forbidden- Non-admin user attempted admin update404 Not Found- Organization not found500 Internal Server Error- Database or processing errors
Handler Process:
- Validates audit status if provided (must be 'approved' or 'rejected')
- Updates organization with provided fields
- Retrieves updated organization from database
- Normalizes logo to include signed download URL
- Returns normalized organization data
Available Update Fields:
- Common Fields:
branchName,contact_email,contact_phone,description - Admin-Approved Fields:
name,address,certificateImage,certifiedQualifications,logo,typeId,auditStatus
Key Features:
- Admin-only access control
- Extended field access including name changes
- Audit status validation for change request workflow
- Support for certificate images and certified qualifications
- Automatic logo URL normalization in response
- Flexible partial updates (all fields optional)
Usage:
import { routes } from '@nodeblocks/backend-sdk';
// Register route with Express app
app.use('/api', routes.updateOrganizationAsAdminRoute);
// Client usage:
const response = await fetch(`/api/admin/organizations/org-123/`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${adminToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Updated Organization Name',
auditStatus: 'approved',
certificateImage: {
objectId: 'cert-uuid',
type: 'application/pdf'
},
certifiedQualifications: [
{ name: 'ISO 9001', status: 'approved', value: '2024' }
]
})
});
const updatedOrg = await response.json();
// Returns 200 OK with normalized organization including logo URL
Organization Followers Retrieval
getOrganizationFollowersRoute
Retrieves paginated list of followers for an organization via GET /organizations/:organizationId/followers.
Purpose: Provides an API endpoint for retrieving organization followers with pagination and avatar normalization.
Route Details:
- Method: GET
- Path:
/organizations/:organizationId/followers - Authentication: Required (Bearer token)
Blocks: getOrganizationById, buildOrganizationFollowersByFollowOrganizationIdQuery, buildWithoutMongoIdFindOptions, findProfiles, normalizeFollowers
Terminators: Built-in success/error mapping via orThrow with 200 status code
Validators:
isAuthenticatedsome(checkIdentityType(['admin']),hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']))
Request Body: None (empty body)
Response (200 OK): JSON with paginated follower list and metadata
Path Parameters:
organizationId: string- ID of the organization to retrieve followers for
Query Parameters:
page?: number- Page number for pagination (default: 1)limit?: number- Results per page (default: 20)
Response Structure:
{
"data": [
{
"id": "string",
"name": "string",
"avatar": {
"url": "string",
"type": "string"
}
}
],
"metadata": {
"pagination": {
"page": number,
"limit": number,
"total": number,
"totalPages": number
}
}
}
Error Responses:
400 Bad Request: Invalid request parameters or malformed path401 Unauthorized: Authentication failed403 Forbidden: User lacks admin privileges and doesn't own the organization404 Not Found: Organization doesn't exist500 Internal Server Error: Database or file storage operation failed
Handler Process:
- Authentication & Authorization: Validates user is authenticated and has permission (admin or organization owner)
- Organization Validation: Ensures the organization exists using getOrganizationById
- Query Building: Builds MongoDB filter for organization followers
- Find Options: Builds query options (excludes MongoDB _id)
- Followers Retrieval: Finds profiles with pagination using findProfiles
- Avatar Normalization: Converts avatar objectIds to accessible URLs
- Response Formatting: Combines follower data with pagination metadata
- Error Mapping: Maps specific block errors to appropriate HTTP status codes
- Success Response: Returns 200 OK with paginated, normalized follower list
Key Features:
- Pagination Support: Efficient handling of large follower lists
- Avatar Normalization: Automatic conversion of storage references to accessible URLs
- Authorization Control: Restricts access to admins and organization owners
- Comprehensive Error Handling: Provides specific error responses for different failure scenarios
- Reuses Profile Blocks: Leverages existing findProfiles and normalizeFollowers functions
Authorization Notes:
- Requires authentication via Bearer token
- Accessible by administrators or organization owners
- Uses
somevalidator to allow either admin access or organization ownership
Usage:
import { routes } from '@nodeblocks/backend-sdk';
const { getOrganizationFollowersRoute } = routes;
// Register route with Express app
app.use('/api', getOrganizationFollowersRoute);
// Client usage - get organization followers
const response = await fetch('/api/organizations/org-123/followers?page=1&limit=20', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 200) {
const { data, metadata } = await response.json();
console.log('Followers:', data);
console.log('Pagination:', metadata.pagination);
} else if (response.status === 404) {
console.log('Organization not found');
} else {
console.error('Failed to retrieve followers:', response.status);
}
Route Composition: The route is composed using functional programming patterns:
const getOrganizationFollowersRoute = withRoute({
handler: compose(
// Validate organization exists
withLogging(
applyPayloadArgs(getOrganizationById, [
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId']
]),
'organization'
),
// Build query filter for followers
flatMapAsync(
withLogging(
applyPayloadArgs(buildOrganizationFollowersByFollowOrganizationIdQuery, [
['params', 'requestParams', 'organizationId']
]),
'filter'
)
),
// Build find options
flatMapAsync(
withLogging(
applyPayloadArgs(buildWithoutMongoIdFindOptions, []),
'options'
)
),
// Find profiles with pagination
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(findProfiles, [
['context', 'db', 'users'],
['context', 'data', 'filter'],
['context', 'data', 'options']
]),
'paginatedFollowers'
)
)
),
// Normalize follower avatars
flatMapAsync(
withLogging(
applyPayloadArgs(normalizeFollowers, [
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedFollowers', 'data']
]),
'normalizedFollowers'
)
),
// Format response with pagination metadata
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedFollowers'],
['context', 'data', 'paginatedFollowers', 'metadata']
],
'normalizedBody'
)
),
// Map errors to HTTP status codes
lift(
orThrow([
[OrganizationNotFoundError, 404],
[OrganizationDbError, 500],
[AvatarBlockError, 500],
[ProfileDbBlockError, 500],
], [['context', 'data', 'normalizedBody'], 200])
)
),
method: 'GET',
path: '/organizations/:organizationId/followers',
validators: [/* authentication and authorization validators */]
});
Performance Considerations:
- Pagination support to handle large follower lists
- Indexed organization lookups for fast validation
- Batch avatar URL normalization for multiple followers
- Minimal response payload with only essential follower data
- Efficient MongoDB $elemMatch query for array matching
Integration Patterns:
- Combines with organization service for complete organization management
- Integrates with file storage driver for avatar URL generation
- Works with pagination middleware for scalable follower lists
- Reuses profile blocks for consistency across profile and organization features
- Supports real-time follower count updates and notifications