Skip to main content
Version: 0.14.0 (Previous)

📋 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 errors
  • coerceTypes: true — coerce query/body types
  • useDefaults: true — apply schema defaults
  • ajv-formats — format validation (email, date-time, etc.)
  • addMongoFilterKeyword — registers the queryFilter custom 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:

LayerProtection
Type safetyThe custom keyword runs for object schemas; non-object values are accepted by its underlying safety check
Prototype pollutionRejects enumerable __proto__, constructor, and prototype keys while recursively traversing the filter
Operator whitelistAllows 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 validationNested 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: JSONSchema7 to enhance
  • defaults: Map of property names to default values
  • condition: Optional predicate — default applies when type === 'object', type includes 'object', or the schema has properties / patternProperties

Defaults are applied recursively to properties, allOf, oneOf, anyOf, and items when type === 'array'. The helper does not traverse patternProperties, definitions, or schema-valued additionalProperties. 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 to object schemas, object unions, and type-less schemas with properties / patternProperties (within the traversal above):

  • additionalProperties: false — block undefined fields
  • queryFilter: 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​