Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Type Fastify Request and Reply payloads?

I'm just getting into Fastify with Typescript and really enjoying it.

However, I'm trying to figure out if I can type the response payload. I have the response schema for serialization working and that may be sufficient, but I have internally typed objects (such as IUser) that it would be nice to have Typescript check against.

The following works great, but I'd like to return an TUser for example and have typescript if I return something different. Using schema merely discludes fields.

interface IUser {
    firstname: string,
    lastname: string
} // Not in use in example

interface IUserRequest extends RequestGenericInterface {
  Params: { username: string };
}

const getUserHandler = async (
  req: FastifyRequest<IUserRequest, RawServerBase, IncomingMessage | Http2ServerRequest>
) => {
  const { username } = req.params;
  return { ... }; // Would like to return instance of IUser
};


app.get<IUserRequest>('/:username', { schema }, getUserHandler);

Is there an equivalent of RequestGenericInterface I can extend for the response?

Small Update: It seems that the reply.send() can be used to add the type, but it would be nice for self-documentation sake to provide T higher up.

like image 283
Blaine Garrett Avatar asked Mar 14 '26 00:03

Blaine Garrett


1 Answers

After looking at the type definitions, I found out that there is also an alternative way to only type-check the handler (like in Julien TASSIN's answer), like this:

import { FastifyReply, FastifyRequest, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
import { RouteGenericInterface } from "fastify/types/route";

interface IUser {
  firstname: string;
  lastname: string;
}

interface IUserRequest extends RouteGenericInterface {
  Params: { username: string };
  Reply: IUser; // put the response payload interface here
}

function getUserHandler(
  request: FastifyRequest<IUserRequest>,
  reply: FastifyReply<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    IUserRequest // put the request interface here
  >
) {
  const { username } = request.params;

  // do something

  // the send() parameter is now type-checked
  return reply.send({
    firstname: "James",
    lastname: "Bond",
  });
}

You can also create your own interface with generic to save writing repeating lines, like this:

import { FastifyReply, FastifyRequest, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
import { RouteGenericInterface } from "fastify/types/route";

export interface FastifyReplyWithPayload<Payload extends RouteGenericInterface>
  extends FastifyReply<
    RawServerDefault,
    RawRequestDefaultExpression,
    RawReplyDefaultExpression,
    Payload
  > {}

then use the interface like this:

function getUserHandler(
  request: FastifyRequest<IUserRequest>,
  reply: FastifyReplyWithPayload<IUserRequest>
) {
  const { username } = request.params;

  // do something

  // the send() parameter is also type-checked like above
  return reply.send({
    firstname: "James",
    lastname: "Bond",
  });
}
like image 56
Muhammad Rizqi Ardiansyah Avatar answered Mar 16 '26 14:03

Muhammad Rizqi Ardiansyah



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!