Skip to main content
Version: 0.14.0 (Latest)

📋 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 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 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