Skip to main content
Version: 0.9.0 (Latest)

๐Ÿชช Validator

Validators are functions that perform additional validation beyond schema validation. They run before your route handlers and can check business logic, resource existence, authentication, and more.


๐Ÿ” What are Validators?โ€‹

Validators are predicate functions that run in the request pipeline before handlers. They can:

  • Validate business logic (e.g., "does this resource exist?")
  • Check authentication (e.g., "is the user authorized?")
  • Validate parameters (e.g., "is this a valid UUID?")
  • Enforce constraints (e.g., "does the user have permission?")
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Request โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Schema โ”‚ โ† JSON Schema validation
โ”‚ Validators โ”‚ โ† Custom business logic
โ”‚ Handler โ”‚ โ† Your route logic
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key characteristics:

  • Async functions - Can perform database queries
  • Throw on failure - Use NodeblocksError for consistent error responses
  • Composable - Chain multiple validators together
  • Context-aware - Access database, request params, and context

๐Ÿ“‹ Available Validatorsโ€‹

Validators are organized by domain in the Backend Blocks documentation. Each block provides domain-specific validators for its operations.

Validator Categoriesโ€‹

CategoryValidatorsDocumentation
AuthenticationisAuthenticated, verifyAuthenticationAuthentication Validators ยป
Commonsome, checkIdentityType, validateResourceAccess, requireParam, isUUID, isNumber, ownsResourceCommon Validators ยป
IdentityisSelfIdentity Validators ยป
UserownsProfile, validateUserProfileAccessUser Validators ยป
ChathasSubscription, ownsSubscription, ownsChannel, ownsMessage, validateChannelAccess, validateMessageAccess, hasOrganizationAccessToMessageTemplate, channelExistsChat Validators ยป
OrderownsOrder, validateOrderAccessOrder Validators ยป
OrganizationhasOrgRole, validateOrganizationAccessOrganization Validators ยป
CategorydoesCategoryExistCategory Validators ยป

โ„น๏ธ Note: For detailed documentation on each validator, including parameters, behavior, and usage examples, see the specific block documentation linked above.


๐Ÿ› ๏ธ Creating Custom Validatorsโ€‹

Validator Function Signatureโ€‹

type Validator = (payload: primitives.RouteHandlerPayload) => Promise<void>;

Basic Validator Exampleโ€‹

import { primitives } from '@nodeblocks/backend-sdk';

const validateUserExists = async (payload: primitives.RouteHandlerPayload) => {
const { context, params } = payload;
const userId = params.requestParams?.userId;

const user = await context.db.users.findOne({ id: userId });
if (!user) {
throw new primitives.NodeblocksError(404, 'User not found', 'USER_NOT_FOUND');
}
};

Advanced Validator Exampleโ€‹

import { primitives } from '@nodeblocks/backend-sdk';

const validateUserPermission = async (payload: primitives.RouteHandlerPayload) => {
const { context, params } = payload;
const { userId, organizationId } = params.requestParams;

// Check if user exists
const user = await context.db.users.findOne({ id: userId });
if (!user) {
throw new primitives.NodeblocksError(404, 'User not found', 'USER_NOT_FOUND');
}

// Check if user belongs to organization
const membership = await context.db.memberships.findOne({
userId,
organizationId,
status: 'active'
});

if (!membership) {
throw new primitives.NodeblocksError(403, 'Access denied', 'ACCESS_DENIED');
}
};

Factory Function Patternโ€‹

Create reusable validator factories:

const requireResourceExists = (collectionName: string, paramName: string) => {
return async (payload: primitives.RouteHandlerPayload) => {
const { context, params } = payload;
const resourceId = params.requestParams?.[paramName];

const resource = await context.db[collectionName].findOne({ id: resourceId });
if (!resource) {
throw new primitives.NodeblocksError(
404,
`${collectionName} not found`,
'RESOURCE_NOT_FOUND'
);
}
};
};

// Usage
const validateProductExists = requireResourceExists('products', 'productId');
const validateOrderExists = requireResourceExists('orders', 'orderId');

๐Ÿ”— Using Validators in Routesโ€‹

Single Validatorโ€‹

export const getCategoryRoute = withRoute({
method: 'GET',
path: '/categories/:categoryId',
validators: [doesCategoryExist],
handler: getCategoryHandler,
});

Multiple Validatorsโ€‹

export const protectedUserRoute = withRoute({
method: 'PATCH',
path: '/users/:userId',
validators: [
isAuthenticated(),
validateResourceAccess(['admin'])
],
handler: updateUserHandler,
});

Conditional Validatorsโ€‹

const validators = [
// Only check authentication for non-public routes
...(isPublicRoute ? [] : [isAuthenticated()])
];

export const getUserRoute = withRoute({
method: 'GET',
path: '/users/:userId',
validators,
handler: getUserHandler,
});

Alternative Validation Pathsโ€‹

export const flexibleUserRoute = withRoute({
method: 'GET',
path: '/users/:identifier',
validators: [
// Use standard validators here. Legacy parameter validators like
// requireParam/isUUID/isNumber cannot be used directly with `some()`.
some(validateHasUserId, validateHasEmail),
validateUserExists
],
handler: getUserHandler,
});

๐Ÿšจ Error Handlingโ€‹

Using NodeblocksErrorโ€‹

Always use NodeblocksError for consistent error responses:

import { primitives } from '@nodeblocks/backend-sdk';

const validateResource = async (payload: primitives.RouteHandlerPayload) => {
// Your validation logic
if (!isValid) {
throw new primitives.NodeblocksError(
400, // HTTP status code
'Validation failed', // Human-readable message
'VALIDATION_ERROR' // Error code for client handling
);
}
};

Error Response Formatโ€‹

When validators throw errors, clients receive:

{
"error": {
"message": "Category does not exist"
}
}

๐Ÿ“‹ Validator Referenceโ€‹

For detailed documentation on each validator, see the Backend Blocks documentation:


๐Ÿ“ Best Practicesโ€‹

1. Fail Fastโ€‹

  • Validators run before handlers, so fail early for invalid requests
  • Don't perform expensive operations in validators unless necessary

2. Reusable Patternsโ€‹

  • Create factory functions for common validation patterns
  • Use domain-specific validators for business logic

3. Clear Error Messagesโ€‹

  • Provide descriptive error messages
  • Use consistent error codes for client-side handling

4. Database Efficiencyโ€‹

  • Use database indexes for validator queries
  • Consider caching for frequently accessed data

5. Compositionโ€‹

  • Chain validators logically (required โ†’ format โ†’ business logic)
  • Keep validators focused on single responsibilities

6. Access Controlโ€‹

  • Use appropriate access control validators for protected resources
  • Combine authentication and authorization validators
  • Consider using some() for flexible validation scenarios

โžก๏ธ Nextโ€‹