daisy-client / src /utils /validations.ts
Jessedbrown's picture
feat/init-daisy-client
6d643ca
Raw History Blame Contribute Delete
2.56 kB
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;
};