Validating Request Body
You can validate the body of a request by creating the schema for the body using the bodySchema function. It supports JSON, FormData (multipart/form-data and application/x-www-form-urlencoded), and plain text bodies. If the validation is successful, the returned validated request will have a bodyObject property that contains the validated body.
JSON Body
Validate JSON request body by providing a json schema:
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
// create the schema for the body
const body = bodySchema({
// create the schema for the JSON body
json: z.object({
name: z.string(),
age: z.number(),
}),
});
export async function POST(request: Request) {
// create the schema for the request
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
// bodyObject contains the validated body for direct property access
const bodyObject = validatedRequest.bodyObject; // { name: string, age: number }
const name = bodyObject.name; // string
const age = bodyObject.age; // number
}The function automatically detects application/json content type (including with charset, e.g., application/json; charset=utf-8).
FormData Body
Validate form data (both multipart/form-data and application/x-www-form-urlencoded) by providing a formData schema:
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
const body = bodySchema({
// create the schema for the FormData body
formData: z.object({
name: z.string(),
email: z.string().email(),
}),
});
export async function POST(request: Request) {
// create the schema for the request
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
// bodyObject contains the validated body for direct property access
const bodyObject = validatedRequest.bodyObject; // { name: string, email: string }
const name = bodyObject.name; // string
const email = bodyObject.email; // string
}Non-string form values (like File objects) are converted to undefined in the
parsed object.
If FormData has multiple values for the same key, the behavior is
non-deterministic. The implementation iterates through FormData.entries(),
and the last value encountered during iteration will be used. However, the
iteration order may vary by environment, so you should avoid relying on a
specific value when multiple values exist for the same key.
Text Body
Validate plain text bodies by providing a text schema:
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
// create the schema for the body
const body = bodySchema({
// create the schema for the text body
text: z.string().min(10),
});
export async function POST(request: Request) {
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
const { text } = validatedRequest.bodyObject; // string
}Multiple Body Types
You can provide multiple body schemas. The function will check them in order: JSON first, then FormData, then text:
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
const body = bodySchema({
json: z.object({ type: z.literal("json") }),
formData: z.object({ type: z.literal("form") }),
text: z.string(),
});
export async function POST(request: Request) {
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
const { type } = validatedRequest.bodyObject; // type depends on Content-Type
}Body Object
When body validation succeeds, the validated result includes both body (the original request body) and bodyObject (the validated body for direct property access):
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
const body = bodySchema({
json: z.object({ value: z.string() }),
});
export async function POST(request: Request) {
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
// body contains the original request body (ReadableStream | null)
// Note: The body stream may be consumed after validation
const originalBody = validatedRequest.body; // ReadableStream<Uint8Array> | null
// bodyObject contains the validated body for direct property access
// When validation succeeds, bodyObject is guaranteed to be defined
const bodyObject = validatedRequest.bodyObject; // { value: string }
const value = bodyObject.value; // string (no optional chaining needed)
}bodyObject is only defined when a body schema is provided to
requestSchema. It contains the unwrapped body value, allowing direct
property access without needing to access a nested body property.
Handling Missing Body
When a body schema is defined, validation will fail if:
- The request doesn't have a matching content type
- The request doesn't have a body
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
const body = bodySchema({
json: z.object({ value: z.string() }),
});
export async function POST(request: Request) {
try {
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
// bodyObject is guaranteed to be defined when validation succeeds
const value = validatedRequest.bodyObject.value;
} catch (error) {
// Validation will fail if:
// - Content-Type is not "application/json"
// - Request has no body
// Handle error appropriately
}
}If no body schemas are provided, bodyObject will be undefined:
import { requestSchema } from "@nicnocquee/zod-request";
export async function GET(request: Request) {
const validatedRequest = await requestSchema({}).parseAsync(request);
// No body schema provided, so bodyObject is undefined
if (validatedRequest.bodyObject) {
// This will never be true when no body schema is provided
}
}Error Handling
Invalid body data will throw a Zod validation error:
import { bodySchema, requestSchema } from "@nicnocquee/zod-request";
import { z } from "zod";
const body = bodySchema({
json: z.object({
age: z.number(),
}),
});
export async function POST(request: Request) {
try {
const validatedRequest = await requestSchema({
body,
}).parseAsync(request);
} catch (error) {
// Handle validation error
if (error instanceof z.ZodError) {
// Invalid body format
}
}
}