import { z } from 'zod'; // Zod schemas for API response structures export const errorDetailBodySchema = z.object({ message: z.string(), code: z.string().optional(), field: z.string().optional(), path: z.string().optional(), }); const errorBodySchema = z.object({ message: z.string(), code: z.string(), details: z.array(errorDetailBodySchema).optional(), }); export const apiErrorResponseBodyZodSchema = z.object({ meta: z.object({ status: z.number().min(400).max(599), }), errors: z.array(errorBodySchema), }); /** * Standard response schema * @description A standard response schema for all API responses * @example * { * "data": { ... }, * "meta": { ... } * } */ export const apiSuccessResponseBodyZodSchema = z.object({ data: z.unknown(), meta: z.object({ status: z.number().min(200).max(399), cache: z .object({ hit: z.boolean(), source: z.string().optional(), ttl: z.number().optional(), expireAt: z.number().optional(), }) .optional(), }), }); export type ErrorDetailBodyZodSchemaType = z.infer; export type ErrorBodyZodSchemaType = z.infer; export type ApiErrorResponseBodyZodSchemaType = z.infer; export type ApiSuccessResponseBodyZodSchemaType = Exclude< z.infer, 'data' > & { data: DataType; }; export const apiPaginationZodSchema = z.object({ items: z.array(z.unknown()), totalItems: z.number(), limit: z.number().int().positive(), page: z.number().int().positive(), totalPages: z.number().int().positive(), hasNextPage: z.boolean(), hasPrevPage: z.boolean(), pagingCounter: z.number().int().positive(), prevPage: z.number().int().positive(), nextPage: z.number().int().positive(), }); export type ApiPaginationZodSchemaType = Omit, 'items'> & { items: ItemsType[]; }; /** * Custom labels for the api paginated response body */ export const mongoosePaginateCustomLabels = { docs: 'items', totalDocs: 'totalItems', limit: 'limit', page: 'page', } as const; /** * The body of a paginated response from the api */ export type ApiPaginatedResponseBodyZodSchemaType = ApiSuccessResponseBodyZodSchemaType< ApiPaginationZodSchemaType >; /** * Method to create a success response body * @param meta * @param data * @returns */ export function createApiSuccessResponseBody(meta: ApiSuccessResponseBodyZodSchemaType['meta'], data: T) { return apiSuccessResponseBodyZodSchema.parse({ data, meta, }) as ApiSuccessResponseBodyZodSchemaType; } /** * Creates an error response with a single error */ export function createApiErrorResponseBody( meta: ApiErrorResponseBodyZodSchemaType['meta'], errors: ApiErrorResponseBodyZodSchemaType['errors'], ): ApiErrorResponseBodyZodSchemaType { const response: ApiErrorResponseBodyZodSchemaType = { meta, errors, }; return apiErrorResponseBodyZodSchema.parse(response); }