Skip to main content
Version: 🚧 Canary

🛣️ 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:

  1. Validates authentication and authorization
  2. Generates UUID object ID
  3. Creates signed upload URL with file extension
  4. 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 token
  • 401 Unauthorized - Authentication failed
  • 500 Internal Server Error - Database or file storage errors

Handler Process:

  1. Retrieves organization by ID
  2. Validates organization name uniqueness if provided
  3. Extracts and validates access token from Authorization header
  4. Creates change request with identityId from token
  5. Updates organization audit status to waiting_for_review
  6. 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 failed
  • 403 Forbidden - User lacks admin privileges or organization ownership
  • 500 Internal Server Error - Database query failures or file URL generation errors

Handler Process:

  1. Authenticates user and validates organization access
  2. Retrieves change requests from database with pagination
  3. Normalizes each change request (removes _id, generates certificate URLs)
  4. 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 failure
  • 401 Unauthorized - Authentication failed
  • 403 Forbidden - Non-admin user attempted admin update
  • 404 Not Found - Organization not found
  • 500 Internal Server Error - Database or processing errors

Handler Process:

  1. Validates audit status if provided (must be 'approved' or 'rejected')
  2. Updates organization with provided fields
  3. Retrieves updated organization from database
  4. Normalizes logo to include signed download URL
  5. 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:

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 path
  • 401 Unauthorized: Authentication failed
  • 403 Forbidden: User lacks admin privileges and doesn't own the organization
  • 404 Not Found: Organization doesn't exist
  • 500 Internal Server Error: Database or file storage operation failed

Handler Process:

  1. Authentication & Authorization: Validates user is authenticated and has permission (admin or organization owner)
  2. Organization Validation: Ensures the organization exists using getOrganizationById
  3. Query Building: Builds MongoDB filter for organization followers
  4. Find Options: Builds query options (excludes MongoDB _id)
  5. Followers Retrieval: Finds profiles with pagination using findProfiles
  6. Avatar Normalization: Converts avatar objectIds to accessible URLs
  7. Response Formatting: Combines follower data with pagination metadata
  8. Error Mapping: Maps specific block errors to appropriate HTTP status codes
  9. 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 some validator 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