Skip to main content

AdditionalRequest

controller.ts / hooks.ts
export type AdditionalRequest = Pick<FastifyRequest, 'cookies'> & {
setCookie: (...args: Parameters<FastifyReply['setCookie']>) => void;
token: string;
};

Using AdditionalRequest, you can extend the FastifyRequest or Request types. This allows you to keep information between multiple Hooks and from Hooks to the Handler.

Frourio automatically extend the arguments of the Handler and Hooks with AdditionalRequest defined in controller.ts or hooks.ts.

  • Controller-level: Affects only the current endpoint. Defined in controller.ts.
  • Directory-level: Affects the current endpoint and the endpoints under it. Defined in hooks.ts.
info

The examples on this page are written with Fastify, but the same features are valid with Express.

Pull requests to add examples with Express are welcome!

Bridging Hooks and the Handler

To share values between hooks and controllers, extend and set them with AdditinalRequest.

Example

controller.ts
import { defineController, defineHooks } from './$relay';

export type AdditionalRequest = {
foo: string;
};

export const hooks = defineHooks(() => ({
preHandler: (req, reply, done) => {
req.foo = 'Stored in hooks!';
done();
},
}));

export default defineController(() => ({
get: (req) => {
return { status: 200, body: req.foo };
},
}));

Relaying type extended by plugins

The first argument of the Handler method does not reflect extensions by plugins such as @fastify/cookie because it is not a FastifyRequest but created by Frourio.

If you want to access extended content, you must extend it with AdditinalRequest and set the value with Hooks.

Example

controller.ts
import { defineController, defineHooks } from './$relay';
import { FastifyReply, FastifyRequest } from 'fastify';

export type AdditionalRequest = Pick<FastifyRequest, 'cookies'> & {
setCookie: (...args: Parameters<FastifyReply['setCookie']>) => void;
};

export const hooks = defineHooks(() => ({
preHandler: (req, reply, done) => {
Object.assign(req, {
setCookie: (...args: Parameters<FastifyReply['setCookie']>) => void reply.setCookie(...args),
});
done();
},
}));

export default defineController(() => ({
post: async ({ body: { token }, setCookie }) => {
const expiresIn = 60 * 60 * 24 * 5 * 1000;
const cookie = await getCookie(token, { expiresIn }); // some function that returns a cookie
setCookie('session', cookie, {
maxAge: expiresIn,
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
path: '/',
});
return { status: 200 };
},
delete: async ({ setCookie, cookies }) => {
const sessionId = cookies.session ?? '';
if (sessionId) await revokeSession(sessionId); // some function that revokes a session
setCookie('session', '', { maxAge: 0, path: '/' });
return { status: 200 };
},
}));