Zod schema for validating query string parameters
Express middleware function that validates query parameters
// Pagination and search parameters
const paginationSchema = z.object({
page: z.string().transform(val => parseInt(val, 10)).pipe(z.number().int().min(1)).optional().default('1'),
limit: z.string().transform(val => parseInt(val, 10)).pipe(z.number().int().min(1).max(100)).optional().default('20'),
search: z.string().min(1).max(100).optional(),
sortBy: z.enum(['name', 'createdAt', 'updatedAt']).optional().default('createdAt'),
sortOrder: z.enum(['asc', 'desc']).optional().default('desc')
});
router.get('/courses', validateQuery(paginationSchema), courseController.list);
// Boolean flags and filters
const filterSchema = z.object({
published: z.string().transform(val => val === 'true').pipe(z.boolean()).optional(),
difficulty: z.enum(['beginner', 'intermediate', 'advanced']).optional(),
hasVideo: z.string().transform(val => val === 'true').pipe(z.boolean()).optional(),
minRating: z.string().transform(val => parseFloat(val)).pipe(z.number().min(0).max(5)).optional()
});
router.get('/courses/search', validateQuery(filterSchema), courseController.search);
// Date range validation
const dateRangeSchema = z.object({
startDate: z.string().datetime('Invalid start date format').optional(),
endDate: z.string().datetime('Invalid end date format').optional(),
timezone: z.string().optional().default('UTC')
}).refine(data => {
if (data.startDate && data.endDate) {
return new Date(data.startDate) <= new Date(data.endDate);
}
return true;
}, 'Start date must be before end date');
router.get('/analytics/progress', validateQuery(dateRangeSchema), analyticsController.getProgress);
// Array parameters (comma-separated values)
const arrayQuerySchema = z.object({
tags: z.string().transform(val => val.split(',')).pipe(z.array(z.string().min(1))).optional(),
categories: z.string().transform(val => val.split(',')).pipe(z.array(z.enum(['language', 'culture', 'grammar']))).optional(),
exclude: z.string().transform(val => val.split(',')).pipe(z.array(z.string().uuid())).optional()
});
router.get('/content/filter', validateQuery(arrayQuerySchema), contentController.filter);
Convenience middleware factory for query parameter validation only
Creates Express middleware that validates only query string parameters against a Zod schema, ignoring request body and URL parameters. This function is crucial for validating optional parameters that modify endpoint behavior, such as pagination settings, search filters, sorting options, and feature flags passed through the URL query string.
Query parameters are typically used for optional functionality like filtering, sorting, pagination, and search. Since they come from user input in the URL, they must be validated to ensure they conform to expected formats and ranges. This validation prevents malformed queries from causing errors and helps maintain consistent API behavior.
The middleware supports automatic type coercion, which is particularly useful for query parameters since they are always received as strings but often need to be converted to numbers, booleans, or other types. Zod's transformation capabilities make this conversion safe and predictable.
This function is essential for implementing robust API endpoints that accept optional parameters while maintaining strict data validation and type safety throughout the application.