JSON Schema Validation in Node.js with Ajv — Full Working Example
Manually checking every field of an incoming request body with a chain of if-statements does not scale, and it is easy to miss edge cases. JSON Schema plus Ajv solves this by letting you describe the shape your data must have and validating against it in a single call. This tutorial walks through a complete, working setup.
Installing Ajv
npm install ajv ajv-formats
ajv-formats adds support for common string formats like email, date-time, and uri, which the core Ajv package does not include by default.
Defining a JSON Schema
Here is a schema for validating a user signup request:
const userSchema = {
type: "object",
properties: {
name: { type: "string", minLength: 2, maxLength: 80 },
email: { type: "string", format: "email" },
age: { type: "integer", minimum: 18, maximum: 120 },
role: { type: "string", enum: ["admin", "editor", "viewer"] },
phone: { type: "string", pattern: "^[6-9][0-9]{9}$" }
},
required: ["name", "email", "role"],
additionalProperties: false
};Compiling and Running the Validator
const Ajv = require("ajv");
const addFormats = require("ajv-formats");
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const validate = ajv.compile(userSchema);
const requestBody = {
name: "Priya Sharma",
email: "priya@example.com",
age: 29,
role: "editor",
phone: "9876543210"
};
const valid = validate(requestBody);
if (!valid) {
console.log(validate.errors);
} else {
console.log("Valid payload — proceed");
}ajv.compile() turns the schema into a fast, reusable validation function. Compile it once outside your request handler and reuse it on every request — never recompile per request, as compilation has real overhead.
Reading Validation Errors
When validation fails, validate.errors gives you a structured array describing exactly what went wrong:
const badBody = { name: "P", email: "not-an-email", role: "superadmin" };
validate(badBody);
console.log(validate.errors);
/* [
{ instancePath: '/name', message: 'must NOT have fewer than 2 characters' },
{ instancePath: '/email', message: 'must match format "email"' },
{ instancePath: '/role', message: 'must be equal to one of the allowed values' }
] */
// Turn errors into a friendly API response
function formatErrors(errors) {
return errors.map(e => `${e.instancePath || 'body'} ${e.message}`);
}Using Ajv as Express Middleware
function validateBody(schema) {
const validate = ajv.compile(schema);
return (req, res, next) => {
const valid = validate(req.body);
if (!valid) {
return res.status(400).json({
error: "Validation failed",
details: formatErrors(validate.errors)
});
}
next();
};
}
app.post("/signup", validateBody(userSchema), (req, res) => {
// req.body is guaranteed to match userSchema here
res.json({ status: "created" });
});Common Schema Keywords You Will Use Often
- type — restricts a value to string, number, integer, boolean, object, array, or null
- required — array of property names that must be present
- additionalProperties: false — rejects any field not explicitly defined in the schema
- enum — restricts a value to a fixed set of allowed options
- pattern — validates a string against a regular expression, useful for phone numbers or codes
- minimum / maximum — numeric range constraints
- format — built-in formats like email, date-time, and uri via ajv-formats
Frequently Asked Questions
Ajv (Another JSON Schema Validator) is the most widely used JavaScript library for validating JSON data against a JSON Schema. It is used to validate API request bodies, configuration files, and any structured JSON data at runtime.
Yes. Ajv compiles a JSON Schema into an optimized JavaScript validation function ahead of time, making it significantly faster than hand-written if-checks for anything beyond a few fields, while also being far less error-prone.
Yes. Dev Brains AI JSON Schema Generator creates a valid JSON Schema from a sample JSON object, ready to plug directly into ajv.