๐ Schema
A schema defines and validates the shape of incoming request data. Nodeblocks relies on JSON Schema Draft-07 and validates at runtime via AJV. Schemas are defined with the withSchema primitive.
There is no schema registration API โ withSchema returns a SchemaComposer that transforms a ServiceDefinition. Schemas are exported from src/schemas/ and paired with routes in features via compose(schema, route).
Import schemas via the single namespace export:
import { schemas } from '@nodeblocks/backend-sdk';
๐ What is a Schema?โ
withSchema returns a SchemaComposerWithSchema โ a function (service: ServiceDefinition) => ServiceDefinition. It sets service.withNextRoute, a hook that wraps the next route's handler with validation when withRoute registers that route.
Schema lifecycleโ
schemas/*.ts โ features/*.ts โ services/*.ts โ defService()
(withSchema) (compose schema + route) (serve)
- Define โ export
withSchema(...)fromsrc/schemas/<domain>.ts - Pair with route โ
compose(schema, route)insrc/features/<domain>.ts(schema must come first) - Bundle โ combine features in a service factory
- Serve โ mount with
defService
See Feature ยป and Route ยป for how schemas attach to routes.
For HTTP routes, schema validation runs inside the wrapped handler before business logic. Invalid HTTP requests throw NodeblocksError with status 400. Legacy JSON Schema composers also support WebSocket message validation, but OpenAPI composers are intended for HTTP routes.
๐ Schema vs Validatorsโ
Two layers run before handler logic:
| Layer | Purpose | Defined via |
|---|---|---|
| Schema | Validates request shape (path, query, body fields) | withSchema in features |
| Validators | Business-logic checks (auth, existence, permissions) | validators on withRoute |
Schema validation is injected via withNextRoute when the route is registered. Route validators run separately in defService before the handler chain. See Validator ยป for business-logic checks beyond schema validation.
๐ OpenAPI Mode (recommended)โ
Pass an OpenAPI operation object with parameters and/or requestBody. This is the primary pattern in SDK schemas:
import { primitives } from '@nodeblocks/backend-sdk';
const { withSchema } = primitives;
export const identityIdPathParameter: primitives.OpenAPIParameter = {
in: 'path',
name: 'identityId',
required: true,
schema: { type: 'string' },
};
export const getIdentitySchema = withSchema({
parameters: [{ ...identityIdPathParameter }],
});
export const updateIdentitySchema = withSchema({
parameters: [{ ...identityIdPathParameter }],
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
additionalProperties: false,
properties: {
email: { type: 'string' },
emailVerified: { type: 'boolean' },
typeId: { type: 'string' },
},
},
},
},
required: true,
},
});
Reusable parameter constants (like identityIdPathParameter) are shared across schemas within a domain module.
OpenAPI validation scopeโ
| Behavior | Detail |
|---|---|
| Supported locations | path and query only โ read from params.requestParams / params.requestQuery |
| Header/cookie params | The OpenAPIParameter type includes header and cookie, but the validator does not read headers or cookies. Do not rely on header validation via withSchema |
| Path params | Always treated as required |
| Query strictness | Undefined query keys are rejected (query parameter 'X' is not allowed) |
| Request body | Validated only for POST, PUT, PATCH, DELETE โ not GET |
| Content type | Defaults to application/json; falls back to the first content entry |
| WebSocket routes | Use legacy JSON Schema mode for WebSocket message validation; OpenAPI mode is for HTTP routes |
๐ Legacy JSON Schema Modeโ
Pass a JSON Schema object (or multiple schemas to merge) to validate request body only:
export const createItemSchema = withSchema({
type: 'object',
additionalProperties: false,
properties: {
name: { type: 'string' },
status: { type: 'string' },
},
required: ['name', 'status'],
});
Pass multiple JSON Schema arguments to deep-merge them:
withSchema(baseSchema, extensionSchema);
Legacy WebSocket supportโ
Legacy composers validate inbound WebSocket messages for protocol: 'ws' routes. The validator strips emitterId (added by defService) before checking the message against the schema. OpenAPI mode does not support WebSocket validation.
๐ Field Requirementsโ
The required array determines which properties must be present:
withSchema({
type: 'object',
properties: {
productId: { type: 'string' },
rating: { type: 'number', minimum: 1, maximum: 5 },
},
required: ['productId', 'rating'],
});
For OpenAPI request bodies, set required: true on the requestBody object when the body itself is mandatory.
๐ Default Schema Enhancementsโ
The SDK applies applyDefaultSchemaEnhancements recursively to object schemas:
additionalProperties: falseโ blocks undefined fields unless you overridequeryFilter: trueโ protects against MongoDB injection in nested object schemas
withSchema({
type: 'object',
additionalProperties: true, // explicitly allow extra fields
properties: {
name: { type: 'string' },
},
});
โ ๏ธ Validation Errorsโ
When validation fails, withSchema throws NodeblocksError(400, 'Validation Error', 'withSchema', errors) before the handler runs.
OpenAPI mode โ messages prefixed by location:
{
"error": {
"message": "Validation Error",
"data": [
"request body must have required property 'email'",
"path parameter 'identityId' is required",
"query parameter 'page' is not allowed"
]
}
}
Legacy mode โ validates request body only. Error messages use raw AJV output without the request body prefix (e.g. "must have required property 'name'").
๐ง Reading Schema Definitionsโ
getSchemaDefinition (legacy only)โ
import { primitives } from '@nodeblocks/backend-sdk';
const { getSchemaDefinition } = primitives;
const merged = getSchemaDefinition(legacySchemaComposer);
Works only on legacy JSON Schema composers that expose a .schema property. Calling it on an OpenAPI composer throws โ read schemaComposer.openapi instead.
๐ฆ SDK Schema Modulesโ
Schemas are organized by domain in the SDK schemas namespace, matching src/schemas/index.ts:
| Module | Description | Reference |
|---|---|---|
| Address | Address lookup schemas | SDK only โ docs pending |
| Attributes | Attribute management schemas | Attribute Schemas ยป |
| Authentication | Auth and token schemas | Authentication Schemas ยป |
| Avatar | Avatar structure schemas | Avatar Schemas ยป |
| Category | Category CRUD schemas | Category Schemas ยป |
| Chat | Chat channel and message schemas | Chat Schemas ยป |
| Common | Shared schemas (pagination, etc.) | Used across domains |
| File Storage | File upload schemas | File Storage Schemas ยป |
| Identity | Identity lifecycle schemas | Identity Schemas ยป |
| Invitation | Invitation schemas | Invitation Schemas ยป |
| Location | Location management schemas | Location Schemas ยป |
| Notification | Notification schemas | SDK only โ docs pending |
| OAuth | OAuth flow schemas | OAuth Schemas ยป |
| Order | Order management schemas | Order Schemas ยป |
| Organization | Organization schemas | Organization Schemas ยป |
| Product | Product management schemas | Product Schemas ยป |
| Profile | Profile schemas | Profile Schemas ยป |
โก๏ธ Nextโ
Learn about Validator ยป for business-logic checks, Feature ยป for pairing schemas with routes, or Route ยป for handler chains.