Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
•
Windows Tipps & SecurityLogitech bringt Headset für Arbeit und Freizeit: das Zone Vibe Pro(01.10.2026 um 09:14 Uhr)
•
Sicherheitslücken (CVE)USN-8855-1: GStreamer Bad Plugins vulnerability(30.09.2026 um 18:05 Uhr)
•••••••••
Windows Tipps & SecurityLogitech bringt Headset für Arbeit und Freizeit: das Zone Vibe Pro(01.10.2026 um 09:14 Uhr)
•
Sicherheitslücken (CVE)USN-8855-1: GStreamer Bad Plugins vulnerability(30.09.2026 um 18:05 Uhr)
••••••••
Intelligence View
⚡ tsecurity.de Intelligence

How to Validate API Requests with Zod in Node.js (2026 Guide)

Every API you build has one thing in common: it accepts input from the outside world. And the outside world cannot be trusted. Whether it's a malformed JSON…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!

Every API you build has one thing in common: it accepts input from the outside world. And the outside world cannot be trusted.



Whether it's a malformed JSON body, a missing required field, or an age field set to "banana", bad input is the #1 source of bugs, crashes, and security vulnerabilities in backend applications.



In this guide, you'll learn how to use Zod — the TypeScript-first schema validation library — to validate every API request before it reaches your business logic. As of February 2026, Zod v3.24 remains the most popular runtime validation library in the Node.js ecosystem, with over 40 million weekly npm downloads.






Why Zod for API Validation?



You might be thinking: "I already use TypeScript. Isn't that enough?"



No. TypeScript types are erased at runtime. When a POST request hits your Express server, TypeScript has zero idea what's inside req.body. It could be anything.



Zod solves this by giving you:





  • Runtime validation — actually checks the data at runtime


  • Type inference — automatically generates TypeScript types from schemas


  • Detailed error messages — tells users exactly what's wrong


  • Zero dependencies — lightweight and fast






Setup



Let's start a new project. We'll use Node.js 22 LTS with Express 5:




mkdir zod-api-demo && cd zod-api-demo
npm init -y
npm install express zod
npm install -D typescript @types/express @types/node tsx
npx tsc --init









Step 1: Define Your Schemas



Create a schemas.ts file:




import { z } from 'zod';

export const createUserSchema = z.object({
body: z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
age: z.number().int().min(13, 'Must be at least 13 years old').optional(),
role: z.enum(['user', 'admin', 'moderator']).default('user'),
}),
});

export const updateUserSchema = z.object({
params: z.object({
id: z.string().uuid('Invalid user ID format'),
}),
body: z.object({
name: z.string().min(2).optional(),
email: z.string().email().optional(),
age: z.number().int().min(13).optional(),
role: z.enum(['user', 'admin', 'moderator']).optional(),
}),
});

export const listUsersSchema = z.object({
query: z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
role: z.enum(['user', 'admin', 'moderator']).optional(),
search: z.string().max(100).optional(),
}),
});

export type CreateUserInput = z.infer<typeof createUserSchema>;
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
export type ListUsersInput = z.infer<typeof listUsersSchema>;









Step 2: Build the Validation Middleware



A reusable middleware that validates any request against a Zod schema:




import { Request, Response, NextFunction } from 'express';
import { AnyZodObject, ZodError } from 'zod';

export const validate =
(schema: AnyZodObject) =>
(req: Request, res: Response, next: NextFunction) => {
try {
schema.parse({
body: req.body,
query: req.query,
params: req.params,
});
next();
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map((err) => ({
field: err.path.join('.'),
message: err.message,
}));

return res.status(400).json({
status: 'error',
message: 'Validation failed',
errors: formattedErrors,
});
}
next(error);
}
};









Step 3: Wire It Into Your Routes






import express from 'express';
import { validate } from './middleware/validate';
import { createUserSchema, updateUserSchema, listUsersSchema } from './schemas';

const app = express();
app.use(express.json());

app.post('/api/users', validate(createUserSchema), (req, res) => {
const { name, email, age, role } = req.body;
res.status(201).json({
status: 'success',
data: { id: crypto.randomUUID(), name, email, age, role },
});
});

app.get('/api/users', validate(listUsersSchema), (req, res) => {
const { page, limit, role, search } = req.query as any;
const offset = (page - 1) * limit;
res.json({
status: 'success',
data: [],
pagination: { page, limit, offset },
});
});

app.patch('/api/users/:id', validate(updateUserSchema), (req, res) => {
const { id } = req.params;
const updates = req.body;
res.json({ status: 'success', data: { id, ...updates } });
});

app.listen(3000, () => console.log('API running on http://localhost:3000'));









Step 4: Test the Validation






# Missing required fields
curl -X POST http://localhost:3000/api/users \
-H 'Content-Type: application/json' \
-d '{}'






Response:




{
"status": "error",
"message": "Validation failed",
"errors": [
{ "field": "body.name", "message": "Required" },
{ "field": "body.email", "message": "Required" }
]
}









Advanced: Reusable Schema Patterns



As your API grows, extract repeating patterns:




import { z } from 'zod';

export const paginationQuery = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
sortBy: z.string().optional(),
order: z.enum(['asc', 'desc']).default('desc'),
});

export const idParam = z.object({
id: z.string().uuid('Invalid ID format'),
});

export const listPostsSchema = z.object({
query: paginationQuery.extend({
status: z.enum(['draft', 'published', 'archived']).optional(),
authorId: z.string().uuid().optional(),
}),
});









Performance Tips





  1. Create schemas once, reuse everywhere — don't define schemas inside handlers


  2. Use .passthrough() sparingly — strict schemas are faster


  3. Prefer z.coerce for query params — Express delivers everything as strings



Zod's overhead is typically under 0.1ms per validation — negligible compared to database queries.






Wrapping Up



You've built schema definitions that serve as both validation rules and TypeScript types, a reusable middleware, structured error responses, and composable patterns that scale.



The best part? Your route handlers never worry about bad data again. If the code runs, the input is valid.



Start validating. Your future self will thank you.






Building APIs? 1xAPI offers ready-to-use API services so you can focus on your product instead of infrastructure.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How to Validate API Requests with Zod in Node.js (2026 Guide)

Thematisch verwandte Begriffe: Validate, Requests, with, Nodejs · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag