UNPKG

fastify-file-router

Version:

A fastify plugin that automatically registers routes from files in a directory.

136 lines 5.38 kB
import type { FastifyReply, FastifyRequest, FastifySchema } from 'fastify'; import type { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { z } from 'zod'; /** * Type helper to check if a value is a Zod schema * Exported for use in routeRegistration.ts */ export declare function isZodSchema(value: unknown): value is z.ZodTypeAny; /** * Schema definition that accepts both Zod schemas and JSON Schema * This allows mixing validation approaches within a single route definition. */ export interface ZodRouteSchema { params?: z.ZodTypeAny | JSONSchema; querystring?: z.ZodTypeAny | JSONSchema; body?: z.ZodTypeAny | JSONSchema; headers?: z.ZodTypeAny | JSONSchema; response?: Record<string | number, z.ZodTypeAny | JSONSchema>; [key: string]: unknown; } /** * Schema type indicators to track which fields use Zod vs JSON Schema */ export interface SchemaTypeIndicators { params?: 'zod' | 'json'; querystring?: 'zod' | 'json'; body?: 'zod' | 'json'; headers?: 'zod' | 'json'; response?: Record<string | number, 'zod' | 'json'>; } /** * Helper type to extract TypeScript types from mixed Zod and JSON Schema schemas * Returns unknown for properties that don't exist (matching Fastify's default behavior) */ type ExtractZodSchemaTypes<T extends ZodRouteSchema> = { Params: T['params'] extends z.ZodTypeAny ? z.infer<T['params']> : T['params'] extends JSONSchema ? FromSchema<T['params']> : unknown; Body: T['body'] extends z.ZodTypeAny ? z.infer<T['body']> : T['body'] extends JSONSchema ? FromSchema<T['body']> : unknown; Querystring: T['querystring'] extends z.ZodTypeAny ? z.infer<T['querystring']> : T['querystring'] extends JSONSchema ? FromSchema<T['querystring']> : unknown; Headers: T['headers'] extends z.ZodTypeAny ? z.infer<T['headers']> : T['headers'] extends JSONSchema ? FromSchema<T['headers']> : unknown; Response: T['response'] extends Record<string | number, z.ZodTypeAny | JSONSchema> ? { [K in keyof T['response']]: T['response'][K] extends z.ZodTypeAny ? z.infer<T['response'][K]> : T['response'][K] extends JSONSchema ? FromSchema<T['response'][K]> : never; } : unknown; }; /** * Route handler function type with inferred types from Zod schemas */ type TypedZodRouteHandler<T extends ZodRouteSchema> = (request: FastifyRequest<ExtractZodSchemaTypes<T>>, reply: FastifyReply) => Promise<unknown> | unknown; /** * Route module returned by defineRouteZod */ export interface DefinedZodRoute<T extends ZodRouteSchema> { schema: FastifySchema & { __zodSchemas?: Partial<{ params?: z.ZodTypeAny; querystring?: z.ZodTypeAny; body?: z.ZodTypeAny; headers?: z.ZodTypeAny; response?: Record<string | number, z.ZodTypeAny>; }>; __schemaTypes?: SchemaTypeIndicators; }; handler: TypedZodRouteHandler<T>; } /** * Formats Zod validation errors into a single error message string. * Format: "Bad Request: [component] - [comma-separated list of issues]" * This function is exported so it can be used in routeRegistration.ts */ export declare function formatZodError(error: z.ZodError, component: string): string; /** * Formats JSON Schema validation errors into a single error message string. * Format: "Bad Request: [component] - [comma-separated list of issues]" * This function is exported so it can be used in routeRegistration.ts */ export declare function formatJsonSchemaError(errors: Array<{ instancePath: string; message?: string; }>, component: string): string; /** * Helper to define a route using Zod schemas and/or JSON Schema. * This function extracts TypeScript types from Zod schemas using `z.infer` * and from JSON Schema using `FromSchema`, allowing you to mix validation approaches. * * @example * ```typescript * import { defineRouteZod } from 'fastify-file-router'; * import { z } from 'zod'; * * // Pure Zod example * export const route = defineRouteZod({ * schema: { * params: z.object({ * id: z.string().min(1) * }), * body: z.object({ * name: z.string().optional(), * email: z.email().optional() * }) * }, * handler: async (request, reply) => { * // request.params.id is correctly typed as string * // request.body.name and request.body.email are correctly typed * const { id } = request.params; * const { name, email } = request.body; * reply.status(200).send({ id, name, email }); * } * }); * ``` * * @example * ```typescript * // Mixed Zod and JSON Schema example * export const route = defineRouteZod({ * schema: { * params: z.object({ id: z.string() }), // Zod schema * body: { * type: 'object', * properties: { name: { type: 'string' } }, * required: ['name'] * } as const // JSON Schema * }, * handler: async (request, reply) => { * // Types are correctly inferred from both schema types * const { id } = request.params; // string (from Zod) * const { name } = request.body; // string (from JSON Schema) * reply.status(200).send({ id, name }); * } * }); * ``` */ export declare function defineRouteZod<T extends ZodRouteSchema>(route: { schema: T; handler: TypedZodRouteHandler<T>; }): DefinedZodRoute<T>; export {}; //# sourceMappingURL=defineRouteZod.d.ts.map