Table of contents
Hey there, TypeScript enthusiasts! 👋 Today, we're diving deep into the world of input validation with Zod, a game-changing library that's about to revolutionize your Node.js development experience. Buckle up for a journey into type-safe paradise!
What's Zod ?
Zod is a TypeScript-first schema validation library that's taking the Node.js world by storm. It uses static type inference to automatically generate validators from your TypeScript types. Say goodbye to manually writing validation rules and hello to type-safe bliss!
Getting Started with Zod
First things first, let's get Zod installed in your project. It's as easy as running:
npm install zod
Zod in Action: From Basic to Advanced
Basic User Validation Example
Let's start with a simple user object validation :
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
age: z.number().min(18, "Must be at least 18 years old"),
email: z.string().email("Invalid email address"),
website: z.string().url().optional(),
});
type User = z.infer<typeof userSchema>; // Infer the TypeScript type from the schema
// Validate a user
const validUser = { name: "Alice", age: 30, email: "alice@example.com" };
console.log(userSchema.parse(validUser)); // Passes validation
const invalidUser = { name: "B", age: 17, email: "not-an-email" };
try {
userSchema.parse(invalidUser);
} catch (error) {
console.log(error.errors);
// [
// { path: ['name'], message: 'Name must be at least 2 characters' },
// { path: ['age'], message: 'Must be at least 18 years old' },
// { path: ['email'], message: 'Invalid email address' }
// ]
}
Advanced Validation: Nested Objects and Arrays
Zod shines when dealing with complex data structures :
const addressSchema = z.object({
street: z.string(),
city: z.string(),
zipCode: z.string().regex(/^\d{5}$/, "Invalid ZIP code"),
});
const advancedUserSchema = userSchema.extend({
addresses: z.array(addressSchema).min(1, "At least one address is required"),
tags: z.array(z.string()).optional(),
});
type AdvancedUser = z.infer<typeof advancedUserSchema>;
const validAdvancedUser: AdvancedUser = {
name: "Charlie",
age: 25,
email: "charlie@example.com",
addresses: [
{ street: "123 Main St", city: "Anytown", zipCode: "12345" }
],
tags: ["developer", "TypeScript"]
};
console.log(advancedUserSchema.parse(validAdvancedUser)); // Passes validation
Integrating Zod with Express
Now, let's see how Zod can make your Express APIs bulletproof:
import express from 'express';
import { z } from 'zod';
const app = express();
app.use(express.json());
const userSchema = z.object({
name: z.string().min(2),
age: z.number().min(18),
email: z.string().email()
});
app.post('/users', (req, res) => {
try {
const validatedUser = userSchema.parse(req.body);
// Input is valid, proceed with user creation
res.status(201).json(validatedUser);
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({ errors: error.errors });
} else {
res.status(500).json({ error: "Internal server error" });
}
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
Advanced Zod Techniques
Custom Validations
Extend Zod's built-in validations with your own custom logic:
const passwordSchema = z.string()
.min(8, "Password must be at least 8 characters")
.refine(
(password) => /[A-Z]/.test(password) && /[a-z]/.test(password) && /[0-9]/.test(password),
"Password must contain uppercase, lowercase, and numeric characters"
);
const userWithPasswordSchema = userSchema.extend({
password: passwordSchema
});
Zod Transforms
Use Zod to not just validate, but also transform your data:
const dateSchema = z.string().transform((str) => new Date(str));
const eventSchema = z.object({
name: z.string(),
date: dateSchema
});
console.log(eventSchema.parse({ name: "Conference", date: "2023-12-25" }));
// Outputs: { name: "Conference", date: Date object }
Why Zod is a Game-Changer
- Type Safety: Zod leverages TypeScript's type system, ensuring your runtime checks match your static types.
- Auto-completion: Your IDE will suggest valid schema properties as you type. No more guessing!
- Performance: Zod is blazingly fast, perfect for high-traffic APIs.
- Flexibility: From simple string validations to complex object shapes, Zod has got you covered.
- Inference: Use
z.infer<typeof schema>
to generate TypeScript types from your schemas.
Best Practices with Zod
- Define Schemas Once: Create reusable schemas for common data structures.
- Combine with TypeScript: Use
z.infer
to keep your types and validations in sync. - Error Handling: Always wrap Zod validations in try-catch blocks for proper error handling.
- Custom Error Messages: Provide clear, user-friendly error messages in your schemas.
- Performance Optimization: For high-traffic APIs, consider caching parsed results.
Wrapping Up
Zod is more than just a validation library; it's a TypeScript developer's best friend. By seamlessly integrating with your existing TypeScript types, it ensures that your data validation is always in sync with your type definitions.
So, are you ready to say goodbye to runtime type errors and hello to bulletproof APIs? Give Zod a try in your next project, and experience the joy of truly type-safe development!
Remember, in the world of web development, validation is not just a best practice—it's a superpower. And with Zod, you're practically wearing a cape! 🦸♂️
Happy coding, and may your types always be valid! 🎉
If you found this tutorial helpful, consider buying the author a coffee: Buy Me A Coffee
For more in-depth information, check out the official Zod documentation.