On this Page
On this Guide
- Lesson 13: Validating a User Registration Form
- Lesson 14: Validating API Query Parameters
- Lesson 15: Validating Environment Variables
- Lesson 16: Handling Nested Errors and Formatted Output
- Lesson 17: Reusable Zod Error Parser for Forms
- Lesson 18: Blog Post Editor β Real-World Case Study
- Lesson 19: Zod + React Hook Form Integration
- Lesson 21: Validating Express Requests with Zod
- Lesson 22: Custom Zod Error Formatter for Express APIs
- Lesson 20: Final Thoughts, Best Practices, and Resources
Why Format Zod Errors?
By default, Zod gives you a rich error object. But clients often expect:
- A clean structure
- Flat key-value errors
- Easy-to-display messages in forms or frontend UIs
Instead of returning raw .issues, letβs format errors into something like:
{
"errors": {
"email": "Invalid email",
"password": "Too short"
}
}
What a Good API Error Response Looks Like
Hereβs a simple, predictable structure:
{
"status": "error",
"message": "Validation failed",
"errors": {
"field": "Error message"
}
}
Letβs build a utility to do that.
Creating a Zod Error Formatter
import { ZodError } from "zod";
export function formatZodError(error: ZodError) {
const formatted: Record<string string> = {};
for (const issue of error.issues) {
const path = issue.path.join(".");
if (!formatted[path]) {
formatted[path] = issue.message;
}
}
return {
status: "error",
message: "Validation failed",
errors: formatted,
};
}
This gives you a clean, flat object ready to send to any client.
Using It in Middleware
Update your validation middleware to use it:
import { formatZodError } from "@/utils/formatZodError";
export const validate =
<t>(schema: ZodSchema<t>) =>
(req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json(formatZodError(result.error));
}
req.body = result.data;
next();
};
Optional: Global Express Error Handler
For apps with multiple validation points or thrown errors:
app.use((err, req, res, next) => {
if (err instanceof ZodError) {
return res.status(400).json(formatZodError(err));
}
console.error(err);
res.status(500).json({ status: "error", message: "Internal Server Error" });
});
Summary
- Use a consistent structure for API validation errors
- Build a reusable
formatZodError()utility - Integrate it into middleware or global error handlers
- Clients love predictable error formats β your future self will too
Master the Code, Be the Guru!