UNPKG

9.61 kBMarkdownView Raw
1<h1 align="center">Fastify</h1>
2
3<a id="typescript"></a>
4## TypeScript
5Fastify is shipped with a typings file, but you may need to install `@types/node`, depending on the Node.js version you are using.
6
7## Types support
8We do care about the TypeScript community, and one of our core team members is currently reworking all types.
9We do our best to have the typings updated with the latest version of the API, but *it can happen* that the typings are not in sync.<br/>
10Luckily this is Open Source and you can contribute to fix them, we will be very happy to accept the fix and release it as soon as possible as a patch release. Checkout the [contributing](#contributing) rules!
11
12Plugins may or may not include typings. See [Plugin Types](#plugin-types) for more information.
13
14## Example
15This example TypeScript app closely aligns with the JavaScript examples:
16
17```ts
18import * as fastify from 'fastify'
19import { Server, IncomingMessage, ServerResponse } from 'http'
20
21// Create a http server. We pass the relevant typings for our http version used.
22// By passing types we get correctly typed access to the underlying http objects in routes.
23// If using http2 we'd pass <http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse>
24// For https pass http2.Http2SecureServer or http.SecureServer instead of Server.
25const server: fastify.FastifyInstance<Server, IncomingMessage, ServerResponse> = fastify({})
26
27const opts: fastify.RouteShorthandOptions = {
28 schema: {
29 response: {
30 200: {
31 type: 'object',
32 properties: {
33 pong: {
34 type: 'string'
35 }
36 }
37 }
38 }
39 }
40}
41
42server.get('/ping', opts, (request, reply) => {
43 console.log(reply.res) // this is the http.ServerResponse with correct typings!
44 reply.code(200).send({ pong: 'it worked!' })
45})
46```
47
48<a id="generic-parameters"></a>
49## Generic Parameters
50Since you can validate the querystring, params, body, and headers, you can also override the default types of those values on the request interface:
51
52```ts
53import * as fastify from 'fastify'
54
55const server = fastify({})
56
57interface Query {
58 foo?: number
59}
60
61interface Params {
62 bar?: string
63}
64
65interface Body {
66 baz?: string
67}
68
69interface Headers {
70 a?: string
71}
72
73const opts: fastify.RouteShorthandOptions = {
74 schema: {
75 querystring: {
76 type: 'object',
77 properties: {
78 foo: {
79 type: 'number'
80 }
81 }
82 },
83 params: {
84 type: 'object',
85 properties: {
86 bar: {
87 type: 'string'
88 }
89 }
90 },
91 body: {
92 type: 'object',
93 properties: {
94 baz: {
95 type: 'string'
96 }
97 }
98 },
99 headers: {
100 type: 'object',
101 properties: {
102 a: {
103 type: 'string'
104 }
105 }
106 }
107 }
108}
109
110server.get<Query, Params, Headers, Body>('/ping/:bar', opts, (request, reply) => {
111 console.log(request.query) // this is of type Query!
112 console.log(request.params) // this is of type Params!
113 console.log(request.headers) // this is of type Headers!
114 console.log(request.body) // this is of type Body!
115 reply.code(200).send({ pong: 'it worked!' })
116})
117```
118
119All generic types are optional, so you can also pass types for the parts you validate with schemas:
120
121```ts
122import * as fastify from 'fastify'
123
124const server = fastify({})
125
126interface Params {
127 bar?: string
128}
129
130const opts: fastify.RouteShorthandOptions = {
131 schema: {
132 params: {
133 type: 'object',
134 properties: {
135 bar: {
136 type: 'string'
137 }
138 }
139 },
140 }
141}
142
143server.get<fastify.DefaultQuery, Params, unknown>('/ping/:bar', opts, (request, reply) => {
144 console.log(request.query) // this is of type fastify.DefaultQuery!
145 console.log(request.params) // this is of type Params!
146 console.log(request.headers) // this is of type unknown!
147 console.log(request.body) // this is of type fastify.DefaultBody because typescript will use the default type value!
148 reply.code(200).send({ pong: 'it worked!' })
149})
150
151// Given that you haven't validated the querystring, body, or headers, it would be best
152// to type those params as 'unknown'. However, it's up to you. The example below is the
153// best way to prevent you from shooting yourself in the foot. In other words, don't
154// use values you haven't validated.
155server.get<unknown, Params, unknown, unknown>('/ping/:bar', opts, (request, reply) => {
156 console.log(request.query) // this is of type unknown!
157 console.log(request.params) // this is of type Params!
158 console.log(request.headers) // this is of type unknown!
159 console.log(request.body) // this is of type unknown!
160 reply.code(200).send({ pong: 'it worked!' })
161})
162```
163
164<a id="http-prototypes"></a>
165## HTTP Prototypes
166By default, fastify will determine which version of http is being used based on the options you pass to it. If for any
167reason you need to override this you can do so as shown below:
168
169```ts
170interface CustomIncomingMessage extends http.IncomingMessage {
171 getClientDeviceType: () => string
172}
173
174// Passing overrides for the http prototypes to fastify
175const server: fastify.FastifyInstance<http.Server, CustomIncomingMessage, http.ServerResponse> = fastify()
176
177server.get('/ping', (request, reply) => {
178 // Access our custom method on the http prototype
179 const clientDeviceType = request.raw.getClientDeviceType()
180
181 reply.send({ clientDeviceType: `you called this endpoint from a ${clientDeviceType}` })
182})
183```
184
185In this example we pass a modified `http.IncomingMessage` interface since it has been extended elsewhere in our
186application.
187
188
189<a id="contributing"></a>
190## Contributing
191TypeScript related changes can be considered to fall into one of two categories:
192
193* [`Core`](#core-types) - The typings bundled with fastify
194* [`Plugins`](#plugin-types) - Fastify ecosystem plugins
195
196Make sure to read our [`CONTRIBUTING.md`](https://github.com/fastify/fastify/blob/master/CONTRIBUTING.md) file before getting started to make sure things go smoothly!
197
198<a id="core-types"></a>
199### Core Types
200When updating core types you should make a PR to this repository. Ensure you:
201
2021. Update `examples/typescript-server.ts` to reflect the changes (if necessary)
2032. Update `test/types/index.ts` to validate changes work as expected
204
205<a id="plugin-types"></a>
206### Plugin Types
207
208Plugins maintained by and organized under the fastify organization on GitHub should ship with typings just like fastify itself does.
209Some plugins already include typings but many do not. We are happy to accept contributions to those plugins without any typings, see [fastify-cors](https://github.com/fastify/fastify-cors) for an example of a plugin that comes with it's own typings.
210
211Typings for third-party-plugins may either be included with the plugin or hosted on DefinitelyTyped. Remember, if you author a plugin to either include typings or publish them on DefinitelyTyped! Information of how to install typings from DefinitelyTyped can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped#npm).
212
213Some types might not be available yet, so don't be shy about contributing.
214
215<a id="authoring-plugin-types"></a>
216### Authoring Plugin Types
217Typings for many plugins that extend the `FastifyRequest`, `FastifyReply` or `FastifyInstance` objects can be achieved as shown below.
218
219This code shows the typings for the [`fastify-static`](https://github.com/fastify/fastify-static) plugin.
220
221```ts
222/// <reference types="node" />
223
224// require fastify typings
225import * as fastify from 'fastify';
226
227// require necessary http, http2, https typings
228import { Server, IncomingMessage, ServerResponse } from "http";
229import { Http2SecureServer, Http2Server, Http2ServerRequest, Http2ServerResponse } from "http2";
230import * as https from "https";
231
232type HttpServer = Server | Http2Server | Http2SecureServer | https.Server;
233type HttpRequest = IncomingMessage | Http2ServerRequest;
234type HttpResponse = ServerResponse | Http2ServerResponse;
235
236// extend fastify typings
237declare module "fastify" {
238 interface FastifyReply<HttpResponse> {
239 sendFile(filename: string): FastifyReply<HttpResponse>;
240 }
241}
242
243// declare plugin type using fastify.Plugin
244declare function fastifyStatic(): fastify.Plugin<
245 Server,
246 IncomingMessage,
247 ServerResponse,
248 {
249 root: string;
250 prefix?: string;
251 serve?: boolean;
252 decorateReply?: boolean;
253 schemaHide?: boolean;
254 setHeaders?: (...args: any[]) => void;
255 redirect?: boolean;
256 wildcard?: boolean | string;
257
258 // Passed on to `send`
259 acceptRanges?: boolean;
260 cacheControl?: boolean;
261 dotfiles?: boolean;
262 etag?: boolean;
263 extensions?: string[];
264 immutable?: boolean;
265 index?: string[];
266 lastModified?: boolean;
267 maxAge?: string | number;
268 }
269>;
270
271declare namespace fastifyStatic {
272 interface FastifyStaticOptions {}
273}
274
275// export plugin type
276export = fastifyStatic;
277```
278
279Now you are good to go and could use the plugin like so:
280
281```ts
282import * as Fastify from 'fastify'
283import * as fastifyStatic from 'fastify-static'
284
285const app = Fastify()
286
287// the options here are type-checked
288app.register(fastifyStatic, {
289 acceptRanges: true,
290 cacheControl: true,
291 decorateReply: true,
292 dotfiles: true,
293 etag: true,
294 extensions: ['.js'],
295 immutable: true,
296 index: ['1'],
297 lastModified: true,
298 maxAge: '',
299 prefix: '',
300 root: '',
301 schemaHide: true,
302 serve: true,
303 setHeaders: (res, pathName) => {
304 res.setHeader('some-header', pathName)
305 }
306})
307
308app.get('/file', (request, reply) => {
309 // using newly defined function on FastifyReply
310 reply.sendFile('some-file-name')
311})
312```
313
314Adding typings to all our plugins is a community effort so feel free to contribute!