Description
💬 Question here
Is it possible to update a route's request body schema (request.routeOptions.schema.body
) according to the provided route param in runtime, using the preValidation
hook? It's possible to achieve this using the preHandler
hook but that's past the builtin validation stage of the request, and requires manually validating the request body.
This is my schema:
import { type RouteShorthandOptions } from 'fastify';
import { z } from 'zod';
const userInteractionKindSchema = z.enum(['bookmark', 'reaction', 'feedback']);
const bookmarkPayloadSchema = z.object({
bookmark: z.boolean(),
});
const reactionPayloadSchema = z.object({
reaction: z.enum(['like', 'dislike']).nullable(),
});
const feedbackPayloadSchema = z.object({
feedback: z.string(),
});
const userInteractionPayloadSchemaByKind = {
[userInteractionKindSchema.enum.bookmark]: bookmarkPayloadSchema,
[userInteractionKindSchema.enum.reaction]: reactionPayloadSchema,
[userInteractionKindSchema.enum.feedback]: feedbackPayloadSchema,
};
const updateUserInteractionRouteSchema = {
params: z.object({
interactionKind: userInteractionKindSchema,
}),
body: z.union([
bookmarkPayloadSchema,
reactionPayloadSchema,
feedbackPayloadSchema,
]),
} satisfies RouteShorthandOptions['schema'];
And this is my route:
import { type ZodTypeProvider } from 'fastify-type-provider-zod';
fastify.withTypeProvider<ZodTypeProvider>().put(
'/userInteractions/:interactionKind',
{
schema: updateUserInteractionRouteSchema,
// doesn't work
preValidation: async request => {
const interactionKindPayloadSchema = userInteractionPayloadSchemaByKind[
request.params.interactionKind
];
request.routeOptions.schema.body = interactionKindPayloadSchema /* requires `as any` to work */;
},
// works, but requires manual validation
preHandler: async request => {
const interactionKindPayloadSchema =
userInteractionPayloadSchemaByKind[request.params.interactionKind];
try {
interactionKindPayloadSchema.parse(request.body);
} catch (error) {
throw new Error(
'Invalid request body for the provided interaction kind',
{ cause: error },
);
}
},
},
(request, reply) => { ... },
);
Updating request.routeOptions.schema.body
in the preValidation
hook doesn't seem to work - when getting a request for the "bookmark"
interaction kind with { "reaction": "like" }
as the body, which matches another interaction kind's schema, the handler is reached even though it should fail. My current workaround is to manually validate the request body in the preHandler
hook.
Your Environment
- node version: 20.10.0
- fastify version: 4.24.3
- os: Mac