Skip to content

Commit 871466c

Browse files
authored
feat: add fastify plugin implementation (#252)
1 parent bf21a75 commit 871466c

5 files changed

Lines changed: 71 additions & 5 deletions

File tree

.changeset/pink-dogs-kneel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@ts-rest/fastify': major
3+
---
4+
5+
Added support for registering ts-rest as a Fastify plugin

apps/docs/docs/fastify.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const router = s.router(contract, {
3737
},
3838
});
3939

40-
s.registerRouter(contract, router, app);
40+
app.register(s.plugin(router));
4141

4242
const start = async () => {
4343
try {

apps/docs/docs/quickstart.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ const router = s.router(contract, {
245245
},
246246
});
247247

248-
s.registerRouter(contract, router, app);
248+
app.register(s.plugin(router));
249249

250250
const start = async () => {
251251
try {

libs/ts-rest/fastify/src/lib/ts-rest-fastify.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,34 @@ describe('ts-rest-fastify', () => {
107107
expect(response.body).toEqual({ foo: 'bar' });
108108
});
109109

110+
it('should instantiate fastify routes using plugin instance', async () => {
111+
const app = fastify({ logger: false });
112+
113+
app.register(s.plugin(router));
114+
115+
await app.ready();
116+
117+
const response = await supertest(app.server).get('/test');
118+
119+
expect(response.statusCode).toEqual(200);
120+
expect(response.body).toEqual({ foo: 'bar' });
121+
});
122+
123+
it('should allow for options when using plugin instance', async () => {
124+
const app = fastify({ logger: false });
125+
126+
app.register(s.plugin(router), {
127+
responseValidation: true,
128+
});
129+
130+
await app.ready();
131+
132+
const response = await supertest(app.server).get('/wrong');
133+
134+
expect(response.statusCode).toEqual(200);
135+
expect(response.body).toEqual({ foo: 'bar' });
136+
});
137+
110138
it('should parse body correctly', async () => {
111139
const app = fastify({ logger: false });
112140

libs/ts-rest/fastify/src/lib/ts-rest-fastify.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ type RecursiveRouterObj<T extends AppRouter> = {
3838
: never;
3939
};
4040

41+
type InitialisedRouter<TContract extends AppRouter> = {
42+
contract: TContract;
43+
routes: RecursiveRouterObj<TContract>;
44+
};
45+
4146
type RegisterRouterOptions = {
4247
logInitialization?: boolean;
4348
jsonQuery?: boolean;
@@ -100,9 +105,15 @@ const validateRequest = (
100105
};
101106

102107
export const initServer = () => ({
103-
router: <T extends AppRouter>(router: T, args: RecursiveRouterObj<T>) => args,
108+
router: <TContract extends AppRouter>(
109+
contract: TContract,
110+
routes: RecursiveRouterObj<TContract>
111+
): InitialisedRouter<TContract> => ({
112+
contract,
113+
routes,
114+
}),
104115
registerRouter: <
105-
T extends RecursiveRouterObj<TContract>,
116+
T extends InitialisedRouter<TContract>,
106117
TContract extends AppRouter
107118
>(
108119
contract: TContract,
@@ -115,12 +126,34 @@ export const initServer = () => ({
115126
requestValidationErrorHandler: 'combined',
116127
}
117128
) => {
118-
recursivelyRegisterRouter(routerImpl, contract, [], app, options);
129+
recursivelyRegisterRouter(routerImpl.routes, contract, [], app, options);
119130

120131
app.setErrorHandler(
121132
requestValidationErrorHandler(options.requestValidationErrorHandler)
122133
);
123134
},
135+
plugin:
136+
<T extends AppRouter>(
137+
router: InitialisedRouter<T>
138+
): fastify.FastifyPluginCallback<RegisterRouterOptions> =>
139+
(
140+
app,
141+
opts = {
142+
logInitialization: true,
143+
jsonQuery: false,
144+
responseValidation: false,
145+
requestValidationErrorHandler: 'combined',
146+
},
147+
done
148+
) => {
149+
recursivelyRegisterRouter(router.routes, router.contract, [], app, opts);
150+
151+
app.setErrorHandler(
152+
requestValidationErrorHandler(opts.requestValidationErrorHandler)
153+
);
154+
155+
done();
156+
},
124157
});
125158

126159
const requestValidationErrorHandler = (

0 commit comments

Comments
 (0)