📋 Schema Utilities
The Nodeblocks SDK provides AJV schema helpers with security enhancements for request validation. These utilities protect against unexpected fields and NoSQL injection in query filters.
🎯 Overview
import { utils } from '@nodeblocks/backend-sdk';
const {
createAjvInstance,
addMongoFilterKeyword,
applySchemaDefaults,
applyDefaultSchemaEnhancements,
} = utils;
The module exports four functions. Route-level business-logic validators (distinct from AJV schema validation) are documented in Validator.
The withSchema composer in primitives uses these helpers internally — see Route Component.
🏭 AJV Instance
createAjvInstance
Creates a pre-configured AJV instance:
import { utils } from '@nodeblocks/backend-sdk';
const { createAjvInstance } = utils;
const ajv = createAjvInstance();
const validate = ajv.compile(schema);
Configuration applied:
allErrors: true— collect all validation errorscoerceTypes: true— coerce query/body typesuseDefaults: true— apply schema defaultsajv-formats— format validation (email, date-time, etc.)addMongoFilterKeyword— registers thequeryFiltercustom keyword
🛡️ NoSQL Injection Protection
addMongoFilterKeyword
Registers the queryFilter custom AJV keyword on an existing AJV instance. When queryFilter: true is set on an object schema, validated data is checked against MongoDB query-filter safety rules.
import Ajv from 'ajv';
import { utils } from '@nodeblocks/backend-sdk';
const { addMongoFilterKeyword } = utils;
const ajv = new Ajv();
addMongoFilterKeyword(ajv);
createAjvInstance() calls this automatically.
Validation layers:
| Layer | Protection |
|---|---|
| Type safety | The custom keyword runs for object schemas; non-object values are accepted by its underlying safety check |
| Prototype pollution | Rejects enumerable __proto__, constructor, and prototype keys while recursively traversing the filter |
| Operator whitelist | Allows only $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $regex, $options, $and, $or |
| Regex safety | $regex must be a string ≤ 100 chars and pass safe-regex (ReDoS protection) |
| Recursive validation | Nested objects and arrays are validated at all depths |
Blocked operators include dangerous ones such as $where, $expr, and $function.
Error messages are intentionally generic ("Invalid query filter format") to avoid leaking database details.
Example schema:
const schema = {
type: 'object',
queryFilter: true,
properties: {
email: { type: ['string', 'object'] },
age: { type: ['number', 'object'] },
},
};
const validate = createAjvInstance().compile(schema);
validate({ email: { $in: ['user@example.com'] } }); // valid
validate({ email: 'user@example.com', $where: 'sleep(10000)' }); // invalid
🔧 Schema Enhancement
applySchemaDefaults
Recursively applies default property values to a JSON Schema.
import { utils } from '@nodeblocks/backend-sdk';
const { applySchemaDefaults } = utils;
const enhanced = applySchemaDefaults(
mySchema,
{ additionalProperties: false },
(schema) => schema.type === 'object'
);
Parameters:
schema:JSONSchema7to enhancedefaults: Map of property names to default valuescondition: Optional predicate — default applies whentype === 'object',typeincludes'object', or the schema hasproperties/patternProperties
Defaults are applied recursively to properties, allOf, oneOf, anyOf, and array items. Existing values on the schema are not overwritten.
applyDefaultSchemaEnhancements
Applies SDK security defaults recursively to object schemas:
import { utils } from '@nodeblocks/backend-sdk';
const { applyDefaultSchemaEnhancements } = utils;
const secureSchema = applyDefaultSchemaEnhancements(routeSchema);
Defaults applied (object types only, recursively):
additionalProperties: false— block undefined fieldsqueryFilter: true— enable MongoDB query-filter validation
Simple property types (string, number, etc.) are not modified.
📐 Best Practices
1. Use applyDefaultSchemaEnhancements for route schemas
// ✅ Good: security defaults on all object schemas
const schema = applyDefaultSchemaEnhancements(myRouteSchema);
2. Distinguish schema validation from business validators
AJV schema utilities validate structure and safety. Business rules (ownership, roles, uniqueness) belong in Validator functions.
3. Keep queryFilter enabled for filter objects
Do not disable queryFilter on user-controlled query objects unless you have an alternative injection defense.
🔗 See Also
- Validator — route-level business-logic validators
- Route Component —
withSchemacomposer integration - Authentication Utilities — token and request security (separate from schema validation)