Skip to main content
Version: 0.13.0 (Previous)

๐Ÿ” 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)
  1. Define โ€” export withSchema(...) from src/schemas/<domain>.ts
  2. Pair with route โ€” compose(schema, route) in src/features/<domain>.ts (schema must come first)
  3. Bundle โ€” combine features in a service factory
  4. 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:

LayerPurposeDefined via
SchemaValidates request shape (path, query, body fields)withSchema in features
ValidatorsBusiness-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.


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โ€‹

BehaviorDetail
Supported locationspath and query only โ€” read from params.requestParams / params.requestQuery
Header/cookie paramsThe OpenAPIParameter type includes header and cookie, but the validator does not read headers or cookies. Do not rely on header validation via withSchema
Path paramsAlways treated as required
Query strictnessUndefined query keys are rejected (query parameter 'X' is not allowed)
Request bodyValidated only for POST, PUT, PATCH, DELETE โ€” not GET
Content typeDefaults to application/json; falls back to the first content entry
WebSocket routesUse 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 override
  • queryFilter: 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:

ModuleDescriptionReference
AddressAddress lookup schemasSDK only โ€” docs pending
AttributesAttribute management schemasAttribute Schemas ยป
AuthenticationAuth and token schemasAuthentication Schemas ยป
AvatarAvatar structure schemasAvatar Schemas ยป
CategoryCategory CRUD schemasCategory Schemas ยป
ChatChat channel and message schemasChat Schemas ยป
CommonShared schemas (pagination, etc.)Used across domains
File StorageFile upload schemasFile Storage Schemas ยป
IdentityIdentity lifecycle schemasIdentity Schemas ยป
InvitationInvitation schemasInvitation Schemas ยป
LocationLocation management schemasLocation Schemas ยป
NotificationNotification schemasSDK only โ€” docs pending
OAuthOAuth flow schemasOAuth Schemas ยป
OrderOrder management schemasOrder Schemas ยป
OrganizationOrganization schemasOrganization Schemas ยป
ProductProduct management schemasProduct Schemas ยป
ProfileProfile schemasProfile Schemas ยป

โžก๏ธ Nextโ€‹

Learn about Validator ยป for business-logic checks, Feature ยป for pairing schemas with routes, or Route ยป for handler chains.