Validate POST/PUT/PATCH Bodies
Body Schemas
schema.body validates the request JSON body — required fields, types, formats, and nested shapes — before your handler runs.
What you'll learn
- Declare body as a JSON Schema object
- Mark required fields
- Use formats like email, uri, and uuid
schema.body is the most-used schema slot. Fastify hands the raw JSON body to Ajv, validates it
against your schema, and rejects bad requests with 400.
A Realistic Signup Body
app.post('/signup', {
schema: {
body: {
type: 'object',
required: ['email', 'password'],
additionalProperties: false,
properties: {
email: { type: 'string', format: 'email' },
password: { type: 'string', minLength: 8, maxLength: 128 },
name: { type: 'string', minLength: 1, maxLength: 80 },
marketingOptIn: { type: 'boolean', default: false },
},
},
},
handler: async (req) => createUser(req.body),
}); additionalProperties: false rejects requests that include unknown fields — useful for catching
typos and stopping mass-assignment bugs.
Nested Objects and Arrays
const body = {
type: 'object',
required: ['address'],
properties: {
address: {
type: 'object',
required: ['street', 'city'],
properties: {
street: { type: 'string' },
city: { type: 'string' },
country: { type: 'string', enum: ['US', 'IN', 'DE'] },
},
},
tags: {
type: 'array',
items: { type: 'string' },
maxItems: 10,
uniqueItems: true,
},
},
} as const; Formats
Out of the box Ajv supports a few formats. Register ajv-formats to get email, uri, uuid,
date-time, and more — covered in the Tuning Ajv lesson.
If validation fails, the response body looks like
{ "statusCode": 400, "error": "Bad Request", "message": "body must have required property 'email'" }.