File size: 2,561 Bytes
6d643ca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | import { z } from 'zod';
import { VALIDATION_LIMITS } from './constants';
/**
* Validation schemas using Zod
*
* This module contains all validation schemas for forms and API inputs.
* Schemas provide both runtime validation and TypeScript type generation.
*/
// Common validation patterns
const requiredString = z.string().min(1, 'This field is required');
// Closet item validation
export const closetItemSchema = z.object({
name: requiredString.max(
VALIDATION_LIMITS.NAME_MAX_LENGTH,
`Name must be less than ${VALIDATION_LIMITS.NAME_MAX_LENGTH} characters`
),
brand: requiredString.max(
VALIDATION_LIMITS.BRAND_MAX_LENGTH,
`Brand must be less than ${VALIDATION_LIMITS.BRAND_MAX_LENGTH} characters`
),
category: requiredString,
imageFile: z.instanceof(File).optional(),
imageUrl: z.string().url().optional(),
});
export type ClosetItemInput = z.infer<typeof closetItemSchema>;
// Search filters validation (simplified to only search query, page, limit)
export const searchFiltersSchema = z.object({
query: z
.string()
.max(VALIDATION_LIMITS.SEARCH_QUERY_MAX_LENGTH, 'Search query too long')
.optional(),
page: z.number().min(1).optional(),
limit: z
.number()
.min(1)
.max(VALIDATION_LIMITS.MAX_PAGINATION_LIMIT)
.optional(),
});
export type SearchFiltersInput = z.infer<typeof searchFiltersSchema>;
// API error validation
export const apiErrorSchema = z.object({
message: z.string(),
code: z.string().optional(),
details: z.record(z.unknown()).optional(),
});
export type ApiError = z.infer<typeof apiErrorSchema>;
// Pagination validation
export const paginationSchema = z.object({
page: z.number().min(1),
limit: z.number().min(1).max(VALIDATION_LIMITS.MAX_PAGINATION_LIMIT),
total: z.number().min(0),
totalPages: z.number().min(0),
});
export type PaginationInfo = z.infer<typeof paginationSchema>;
// Generic list response validation
export const createListResponseSchema = <T extends z.ZodTypeAny>(
itemSchema: T
) =>
z.object({
data: z.array(itemSchema),
pagination: paginationSchema.optional(),
meta: z.record(z.unknown()).optional(),
});
// Validation helpers
export const validateInput = <T extends z.ZodTypeAny>(
schema: T,
data: unknown
): z.infer<T> => {
const result = schema.safeParse(data);
if (!result.success) {
throw new Error(
`Validation failed: ${result.error.issues.map((i) => i.message).join(', ')}`
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result.data;
};
|