zod-validation
Zod schema validation patterns. Use when validating API inputs and data.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Zod schema validation patterns. Use when validating API inputs and data.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Use when listing files, searching file contents, finding files by name, or viewing files in terminal. Replace slow standard tools (ls, grep, find, cat) with faster modern alternatives.
Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.
Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.
Set up and maintain a structured project memory system in docs/project_notes/ that tracks bugs with solutions, architectural decisions, key project facts, and work history. Use this skill when asked to "set up project memory", "track our decisions", "log a bug fix", "update project memory", or "initialize memory system". Configures both CLAUDE.md and AGENTS.md to maintain memory awareness across different AI coding tools.
Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.
Prepares production launches. Use when preparing to deploy to production. Use when you need a pre-launch checklist, when setting up monitoring, when planning a staged rollout, or when you need a rollback strategy.
| name | zod-validation |
| description | Zod schema validation patterns. Use when validating API inputs and data. |
This skill covers Zod schema validation for type-safe data validation.
Use this skill when:
VALIDATE AT BOUNDARIES - Validate all external input. Trust internal data. Use Zod for type inference.
npm install zod
import { z } from 'zod';
// Primitives
const stringSchema = z.string();
const numberSchema = z.number();
const booleanSchema = z.boolean();
const dateSchema = z.date();
// String validations
const emailSchema = z.string().email();
const urlSchema = z.string().url();
const uuidSchema = z.string().uuid();
const minLengthSchema = z.string().min(1).max(100);
const regexSchema = z.string().regex(/^[a-z]+$/);
// Number validations
const positiveSchema = z.number().positive();
const intSchema = z.number().int();
const rangeSchema = z.number().min(0).max(100);
// Optional and nullable
const optionalSchema = z.string().optional(); // string | undefined
const nullableSchema = z.string().nullable(); // string | null
const nullishSchema = z.string().nullish(); // string | null | undefined
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().positive().optional(),
role: z.enum(['USER', 'ADMIN', 'MODERATOR']),
createdAt: z.date(),
});
// Type inference
type User = z.infer<typeof UserSchema>;
// Partial (all fields optional)
const PartialUserSchema = UserSchema.partial();
// Pick specific fields
const UserEmailSchema = UserSchema.pick({ email: true, name: true });
// Omit fields
const UserWithoutIdSchema = UserSchema.omit({ id: true, createdAt: true });
// Extend schema
const UserWithProfileSchema = UserSchema.extend({
profile: z.object({
bio: z.string().optional(),
avatar: z.string().url().optional(),
}),
});
// Arrays
const StringArraySchema = z.array(z.string());
const NumberArraySchema = z.array(z.number()).min(1).max(10);
// Tuples
const CoordinatesSchema = z.tuple([z.number(), z.number()]);
// Unions
const StringOrNumberSchema = z.union([z.string(), z.number()]);
const ResultSchema = z.discriminatedUnion('status', [
z.object({ status: z.literal('success'), data: z.unknown() }),
z.object({ status: z.literal('error'), error: z.string() }),
]);
// Enums
const RoleSchema = z.enum(['USER', 'ADMIN', 'MODERATOR']);
type Role = z.infer<typeof RoleSchema>; // 'USER' | 'ADMIN' | 'MODERATOR'
// Create user request
const CreateUserSchema = z.object({
email: z.string().email('Invalid email address'),
password: z.string()
.min(8, 'Password must be at least 8 characters')
.regex(/[A-Z]/, 'Password must contain uppercase letter')
.regex(/[0-9]/, 'Password must contain number'),
name: z.string().min(1, 'Name is required').max(100),
});
// Update user request (all fields optional)
const UpdateUserSchema = CreateUserSchema.partial();
// Query parameters
const PaginationSchema = z.object({
page: z.coerce.number().int().positive().default(1),
perPage: z.coerce.number().int().min(1).max(100).default(20),
sort: z.enum(['asc', 'desc']).default('desc'),
});
// Path parameters
const IdParamSchema = z.object({
id: z.string().uuid('Invalid ID format'),
});
// Transform during parse
const TrimmedStringSchema = z.string().trim();
const LowercaseEmailSchema = z.string().email().toLowerCase();
// Transform to different type
const DateStringSchema = z.string().transform((str) => new Date(str));
// Coerce types
const CoercedNumberSchema = z.coerce.number(); // "42" -> 42
const CoercedDateSchema = z.coerce.date(); // "2024-01-01" -> Date
// Complex transformation
const UserInputSchema = z.object({
email: z.string().email().toLowerCase().trim(),
name: z.string().trim(),
tags: z.string().transform((str) => str.split(',').map((t) => t.trim())),
});
// Custom refinement
const PasswordSchema = z.string()
.min(8)
.refine(
(password) => /[A-Z]/.test(password),
{ message: 'Password must contain uppercase letter' }
)
.refine(
(password) => /[0-9]/.test(password),
{ message: 'Password must contain number' }
);
// Cross-field validation
const PasswordConfirmSchema = z.object({
password: z.string().min(8),
confirmPassword: z.string(),
}).refine(
(data) => data.password === data.confirmPassword,
{
message: 'Passwords do not match',
path: ['confirmPassword'],
}
);
// Async validation
const UniqueEmailSchema = z.string().email().refine(
async (email) => {
const exists = await checkEmailExists(email);
return !exists;
},
{ message: 'Email already registered' }
);
// src/routes/users.ts
import { FastifyPluginAsync } from 'fastify';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
password: z.string().min(8),
});
const UserResponseSchema = z.object({
id: z.string(),
email: z.string(),
name: z.string(),
createdAt: z.string(),
});
type CreateUserInput = z.infer<typeof CreateUserSchema>;
type UserResponse = z.infer<typeof UserResponseSchema>;
const usersRoutes: FastifyPluginAsync = async (fastify) => {
// Manual validation
fastify.post<{ Body: CreateUserInput }>('/', async (request, reply) => {
const result = CreateUserSchema.safeParse(request.body);
if (!result.success) {
return reply.status(400).send({
error: 'Validation failed',
details: result.error.flatten(),
});
}
const user = await createUser(result.data);
return reply.status(201).send(user);
});
// With JSON Schema (Fastify validates)
fastify.post<{ Body: CreateUserInput; Reply: UserResponse }>('/v2', {
schema: {
body: zodToJsonSchema(CreateUserSchema),
response: {
201: zodToJsonSchema(UserResponseSchema),
},
},
}, async (request, reply) => {
const user = await createUser(request.body);
return reply.status(201).send(user);
});
};
// src/config/env.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
CORS_ORIGIN: z.string().url().optional(),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
export type Env = z.infer<typeof EnvSchema>;
function validateEnv(): Env {
const result = EnvSchema.safeParse(process.env);
if (!result.success) {
console.error('Invalid environment variables:');
console.error(result.error.flatten().fieldErrors);
process.exit(1);
}
return result.data;
}
export const env = validateEnv();
import { z, ZodError } from 'zod';
function parseOrThrow<T>(schema: z.ZodSchema<T>, data: unknown): T {
return schema.parse(data);
}
function parseOrNull<T>(schema: z.ZodSchema<T>, data: unknown): T | null {
const result = schema.safeParse(data);
return result.success ? result.data : null;
}
// Flatten errors for API response
function formatZodError(error: ZodError): Record<string, string[]> {
return error.flatten().fieldErrors as Record<string, string[]>;
}
// Usage
try {
const user = parseOrThrow(UserSchema, requestBody);
} catch (error) {
if (error instanceof ZodError) {
return { errors: formatZodError(error) };
}
throw error;
}
// Base schemas
const AddressSchema = z.object({
street: z.string(),
city: z.string(),
country: z.string(),
postalCode: z.string(),
});
const ContactSchema = z.object({
email: z.string().email(),
phone: z.string().optional(),
});
// Composed schema
const CustomerSchema = z.object({
id: z.string().uuid(),
name: z.string(),
contact: ContactSchema,
billingAddress: AddressSchema,
shippingAddress: AddressSchema.optional(),
});
z.infer<typeof Schema>safeParse for graceful errorsrefine for async validationszodToJsonSchema for OpenAPI/Swagger