fastify / fastify/help

Update request body schema according to the provided route param in runtime

Open
#1,067 1 comment 0 reactions 0 assignees View on GitHub
help wanted question
Dominant language
No language data
Stars
68
Forks
8
Avg merge
11h 2m
Merged PRs (30d)
2

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:
```ts
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:
```ts
import { type ZodTypeProvider } from 'fastify-type-provider-zod';

fastify.withTypeProvider().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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.