fastify-type-provider-zod
fastify-type-provider-zod copied to clipboard
Schemas and hooks
I have custom JwtAuth hook and I use it on specific routes.
export const jwtAuth: preValidationHookHandler = (request, res, next) => {
if (request.headers.cookie) {
try {
const token = request.headers.cookie.replace("token=", "");
if (token && typeof token === "string") {
const user = request.server.jwt.verify(token);
request.user = user;
next();
}
} catch (err) {
res.status(401).send({ error: err });
}
}
if (!request.headers.cookie)
res.status(401).send({ message: "Unauthorized" });
};
Before I started to use ZodTypeProvider the type infered from fastify/jwt module where it has been manually set. So, I used it the following way and it obviosly worked.
fastify.get<{ Params: ProfileParams }>(
"/profile/:id",
{ preValidation: jwtAuth },
async (req, res) => {
const { id } = req.params;
const userId = id === "me" ? req.user.id : id;
...
}
);
But now when I switched to ".withTypeProvider<ZodTypeProvider>()" routes, the ones with preValidation hooks stopped to get the types so following is not working anymore, cuz for some reason ts recognizes now request as socket stream and params is unknown.
fastify.withTypeProvider<ZodTypeProvider>().get(
"/profile/:id",
{
preValidation: jwtAuth,
schema: {
params: ProfileSchema,
response: { 200: ProfileSuccess },
},
},
async (req, res) => {
const { id } = req.params; //params is unknown
const userId = id === "me" ? req.user.id : id; //Property 'user' does not exist on type 'SocketStream'.
...
}
);
If i comment out the hook in last code example the type of params gets infered correctly!
I've tried dozens of workarounds already but did not find the solution to make this work. May be someone knows what am I missing?
@sbeben try this
export type preHandlerAsyncHookZodHandler = preHandlerAsyncHookHandler<
RawServerDefault,
RawRequestDefaultExpression,
RawReplyDefaultExpression,
RouteGenericInterface,
unknown,
any,
ZodTypeProvider
>;
@sidwebworks I have the same problem. Could you tell me more about it?
I cannot explain why, but in my case
We loose schema types :
preHandler: validateRole,
Doesn't loose schema types :
preHandler: (request, reply) => validateRole(request, reply)
Doesn't loose schema types :
preHandler: [validateRole] as never,
@sbeben try this
export type preHandlerAsyncHookZodHandler = preHandlerAsyncHookHandler< RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, unknown, any, ZodTypeProvider >;
@sbeben can you explain how to use it please.
i'm having same problem
const isAdmin = function prehandler(req: any, reply: any, done: any): asserts req is FastifyRequest & {user: IAdmin} {
if (!req.user?.sub) throw new UnauthorizedError()
if (req.user.role !== 'admin') throw new ForbiddenError()
done()
}
but still in handler it see user?: JWT
I solved it by creating custom types passing "ZodTypeProvider" as generic for the original fastify types.
fastify-zod-provider.d.ts
import { ZodTypeProvider } from "fastify-type-provider-zod";
export type FastifyZodInstance = FastifyInstance<
RawServer,
RawRequest,
RawReply,
Logger,
ZodTypeProvider
>;
export type FastifyZodRequest = FastifyRequest<
RouteGeneric,
RawServer,
RawRequest,
SchemaCompiler,
ZodTypeProvider
>;
export type FastifyZodReply = FastifyReply<
RawServer,
RawRequest,
RawReply,
RouteGeneric,
ContextConfig,
SchemaCompiler,
ZodTypeProvider
>;
my-fastify-hook.ts
export async function myFastifyHook(req: FastifyZodRequest, res: FastifyZodReply) {
// your hook handler
}
my-fastify-route.ts
app.withTypeProvider<ZodTypeProvider>().route({
preHandler: myFastifyHook,
// another route settings
});