Skip to main content

AdditionalRequest

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!


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

Frourio extends FastifyRequest or Request type with the AdditionalRequest type exported from controller.ts and hooks.ts.

If defined in controller.ts, it will be reflected in the current endpoints.
If defined in hooks.ts, it will be reflected in the current and subordinate endpoints.

Bridging Hooks and Controllers

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 Controller 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 };
},
}));