Skip to content

Commit fac1906

Browse files
thomheymannEommjsumners
authored
docs: Migration Guide v3 (fastify#2140)
Co-Authored-By: Manuel Spigolon <[email protected]> Co-Authored-By: James Sumners <[email protected]>
1 parent e0c1751 commit fac1906

File tree

5 files changed

+255
-41
lines changed

5 files changed

+255
-41
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ end_of_line = lf
55
insert_final_newline = true
66
indent_style = space
77
indent_size = 2
8+
quote_type = single
89

910
[*.md]
1011
trim_trailing_whitespace = false

docs/Migration-Guide-V3.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# V3 Migration Guide
2+
3+
This guide is aimed to help migration from Fastify v2 to v3.
4+
5+
Before beginning please ensure that any deprecation warnings from v2 are fixed as we have removed all deprecated features and they will no longer work after upgrading. ([#1750](https://github.com/fastify/fastify/pull/1750))
6+
7+
## Breaking changes
8+
9+
### Changed middleware support ([#2014](https://github.com/fastify/fastify/pull/2014))
10+
11+
From Fastify v3, middleware support does not come out of the box with the framework itself.
12+
13+
If you use Express middleware in your application, please install and register the [`fastify-express`](https://github.com/fastify/fastify-express) or [`middie`](https://github.com/fastify/middie) plugin before doing so.
14+
15+
**v2:**
16+
17+
```js
18+
fastify.use(require('cors')());
19+
```
20+
21+
**v3:**
22+
23+
```js
24+
await fastify.register(require('fastify-express'));
25+
fastify.use(require('cors')());
26+
```
27+
28+
### Changed logging serialization ([#2017](https://github.com/fastify/fastify/pull/2017))
29+
30+
We have updated our logging [Serializers](https://github.com/fastify/fastify/blob/master/docs/Logging.md) to now receive Fastify [`Request`](https://github.com/fastify/fastify/blob/master/docs/Request.md) and [`Reply`](https://github.com/fastify/fastify/blob/master/docs/Reply.md) objects instead of native ones.
31+
32+
If you have created custom serializers they will need updating if they expect properties that aren't exposed by the Fastify objects themselves.
33+
34+
**v2:**
35+
36+
```js
37+
const fastify = require('fastify')({
38+
logger: {
39+
serializers: {
40+
res(res) {
41+
return {
42+
statusCode: res.statusCode,
43+
customProp: res.customProp
44+
};
45+
}
46+
}
47+
}
48+
});
49+
```
50+
51+
**v3:**
52+
53+
```js
54+
const fastify = require('fastify')({
55+
logger: {
56+
serializers: {
57+
res(reply) {
58+
return {
59+
statusCode: reply.statusCode, // No change required
60+
customProp: reply.raw.customProp // Log custom property from res object
61+
};
62+
}
63+
}
64+
}
65+
});
66+
```
67+
68+
### Changed schema substitution ([#2023](https://github.com/fastify/fastify/pull/2023))
69+
70+
We have dropped support for non-standard `replace-way` shared schema substitution and replaced it with standard compliant JSON Schema `$ref` based substitution. To better understand this change read [Validation and Serialization in Fastify v3](https://dev.to/eomm/validation-and-serialization-in-fastify-v3-2e8l).
71+
72+
**v2:**
73+
74+
```js
75+
const schema = {
76+
body: 'schemaId#'
77+
};
78+
fastify.route({ method, url, schema, handler });
79+
```
80+
81+
**v3:**
82+
83+
```js
84+
const schema = {
85+
body: {
86+
$ref: 'schemaId#'
87+
}
88+
};
89+
fastify.route({ method, url, schema, handler });
90+
```
91+
92+
### Changed schema validation options ([#2023](https://github.com/fastify/fastify/pull/2023))
93+
94+
We have replaced `setSchemaCompiler` and `setSchemaResolver` options with `setValidatorCompiler` to enable future tooling improvements. To deepen this change [read the article](https://dev.to/eomm/validation-and-serialization-in-fastify-v3-2e8l).
95+
96+
**v2:**
97+
98+
```js
99+
const fastify = Fastify();
100+
const ajv = new AJV();
101+
ajv.addSchema(schemaA);
102+
ajv.addSchema(schemaB);
103+
104+
fastify.setSchemaCompiler(schema => ajv.compile(schema));
105+
fastify.setSchemaResolver(ref => ajv.getSchema(ref).schema);
106+
```
107+
108+
**v3:**
109+
110+
```js
111+
const fastify = Fastify();
112+
const ajv = new AJV();
113+
ajv.addSchema(schemaA);
114+
ajv.addSchema(schemaB);
115+
116+
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) =>
117+
ajv.compile(schema)
118+
);
119+
```
120+
121+
### Changed hooks behaviour ([#2004](https://github.com/fastify/fastify/pull/2004))
122+
123+
From Fastify v3, the behavior of `onRoute` and `onRegister` hooks will change slightly in order to support hook encapsulation.
124+
125+
- `onRoute` - The hook will be called asynchronously, in v1/v2 it's called as soon as a route is registered. This means that if you want to use it, you should register this hook as soon as possible in your code.
126+
- `onRegister` - Same as the onRoute hook, the only difference is that now the very first call will no longer be the framework itself, but the first registered plugin
127+
128+
### Changed TypeScript support
129+
130+
The type system was changed in Fastify version 3. The new type system introduces generic constraining and defaulting, plus a new way to define schema types such as a request body, querystring, and more!
131+
132+
**v2:**
133+
134+
```ts
135+
interface PingQuerystring {
136+
foo?: number;
137+
}
138+
139+
interface PingParams {
140+
bar?: string;
141+
}
142+
143+
interface PingHeaders {
144+
a?: string;
145+
}
146+
147+
interface PingBody {
148+
baz?: string;
149+
}
150+
151+
server.get<PingQuerystring, PingParams, PingHeaders, PingBody>(
152+
'/ping/:bar',
153+
opts,
154+
(request, reply) => {
155+
console.log(request.query); // This is of type `PingQuerystring`
156+
console.log(request.params); // This is of type `PingParams`
157+
console.log(request.headers); // This is of type `PingHeaders`
158+
console.log(request.body); // This is of type `PingBody`
159+
}
160+
);
161+
```
162+
163+
**v3:**
164+
165+
```ts
166+
server.get<{
167+
Querystring: PingQuerystring;
168+
Params: PingParams;
169+
Headers: PingHeaders;
170+
Body: PingBody;
171+
}>('/ping/:bar', opts, async (request, reply) => {
172+
console.log(request.query); // This is of type `PingQuerystring`
173+
console.log(request.params); // This is of type `PingParams`
174+
console.log(request.headers); // This is of type `PingHeaders`
175+
console.log(request.body); // This is of type `PingBody`
176+
});
177+
```
178+
179+
## Further additions and improvements
180+
181+
- Hooks now have consistent context irregardless of how they are registered ([#2005](https://github.com/fastify/fastify/pull/2005))
182+
- Deprecated `request.req` and `reply.res` for [`request.raw`](https://github.com/fastify/fastify/blob/master/docs/Request.md) and [`reply.raw`](https://github.com/fastify/fastify/blob/master/docs/Reply.md) ([#2008](https://github.com/fastify/fastify/pull/2008))
183+
- Removed `modifyCoreObjects` option ([#2015](https://github.com/fastify/fastify/pull/2015))
184+
- Added [`connectionTimeout`](https://github.com/fastify/fastify/blob/master/docs/Server.md#factory-connection-timeout) option ([#2086](https://github.com/fastify/fastify/pull/2086))
185+
- Added [`keepAliveTimeout`](https://github.com/fastify/fastify/blob/master/docs/Server.md#factory-keep-alive-timeout) option ([#2086](https://github.com/fastify/fastify/pull/2086))
186+
- Added async-await support for [plugins](https://github.com/fastify/fastify/blob/master/docs/Plugins.md#async-await) ([#2093](https://github.com/fastify/fastify/pull/2093))

docs/Validation-and-Serialization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ fastify.post('/the/url', {
313313
}).required()
314314
},
315315
validatorCompiler: ({ schema, method, url, httpPart }) => {
316-
return (data) => Joi.validate(data, schema)
316+
return data => schema.validate(data)
317317
}
318318
}, handler)
319319
```

examples/typescript-server.ts

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/**
32
* Most type annotations in this file are not strictly necessary but are
43
* included for this example.
@@ -11,42 +10,70 @@
1110
* node examples/typescript-server.js
1211
*/
1312

14-
import * as fastify from '../fastify'
15-
import { createReadStream } from 'fs'
16-
import * as http from 'http'
13+
import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify';
14+
import { Server, IncomingMessage, ServerResponse } from 'http';
1715

18-
const server = fastify()
16+
// Create an http server. We pass the relevant typings for our http version used.
17+
// By passing types we get correctly typed access to the underlying http objects in routes.
18+
// If using http2 we'd pass <http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse>
19+
const server: FastifyInstance<
20+
Server,
21+
IncomingMessage,
22+
ServerResponse
23+
> = fastify();
1924

20-
const opts = {
21-
schema: {
22-
response: {
23-
200: {
24-
type: 'object',
25-
properties: {
26-
hello: {
27-
type: 'string'
28-
}
29-
}
30-
}
31-
}
32-
}
25+
// Define interfaces for our request. We can create these automatically
26+
// off our JSON Schema files (See TypeScript.md) but for the purpose of this
27+
// example we manually define them.
28+
interface PingQuerystring {
29+
foo?: number;
3330
}
3431

35-
function getHelloHandler (req: fastify.FastifyRequest<http.IncomingMessage>,
36-
reply: fastify.FastifyReply<http.ServerResponse>) {
37-
reply.header('Content-Type', 'application/json').code(200)
38-
reply.send({ hello: 'world' })
32+
interface PingParams {
33+
bar?: string;
3934
}
4035

41-
function getStreamHandler (req, reply) {
42-
const stream = createReadStream(process.cwd() + '/examples/plugin.js', 'utf8')
43-
reply.code(200).send(stream)
36+
interface PingHeaders {
37+
a?: string;
4438
}
4539

46-
server.get('/', opts, getHelloHandler)
47-
server.get('/stream', getStreamHandler)
40+
interface PingBody {
41+
baz?: string;
42+
}
4843

49-
server.listen(3000, err => {
50-
if (err) throw err
51-
console.log(`server listening on ${server.server.address().port}`)
52-
})
44+
// Define our route options with schema validation
45+
const opts: RouteShorthandOptions = {
46+
schema: {
47+
body: {
48+
type: 'object',
49+
properties: {
50+
pong: {
51+
type: 'string'
52+
}
53+
}
54+
}
55+
}
56+
};
57+
58+
// Add our route handler with correct types
59+
server.get<{
60+
Querystring: PingQuerystring;
61+
Params: PingParams;
62+
Headers: PingHeaders;
63+
Body: PingBody;
64+
}>('/ping/:bar', opts, (request, reply) => {
65+
console.log(request.query); // this is of type `PingQuerystring`
66+
console.log(request.params); // this is of type `PingParams`
67+
console.log(request.headers); // this is of type `PingHeaders`
68+
console.log(request.body); // this is of type `PingBody`
69+
reply.code(200).send({ pong: 'it worked!' });
70+
});
71+
72+
// Start your server
73+
server.listen(8080, (err, address) => {
74+
if (err) {
75+
console.error(err);
76+
process.exit(0);
77+
}
78+
console.log(`Server listening at ${address}`);
79+
});

test/schema-examples.test.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test('Example - URI $id', t => {
1515
})
1616

1717
fastify.post('/', {
18-
handler () {},
18+
handler () { },
1919
schema: {
2020
body: {
2121
type: 'array',
@@ -39,7 +39,7 @@ test('Example - string $id', t => {
3939
})
4040

4141
fastify.post('/', {
42-
handler () {},
42+
handler () { },
4343
schema: {
4444
body: { $ref: 'commonSchema#' },
4545
headers: { $ref: 'commonSchema#' }
@@ -98,7 +98,7 @@ test('Example - get schema encapsulated', async t => {
9898
test('Example - validation', t => {
9999
t.plan(1)
100100
const fastify = Fastify()
101-
const handler = () => {}
101+
const handler = () => { }
102102

103103
const bodyJsonSchema = {
104104
type: 'object',
@@ -221,7 +221,7 @@ test('Example - ajv config', t => {
221221
test('Example Joi', t => {
222222
t.plan(1)
223223
const fastify = Fastify()
224-
const handler = () => {}
224+
const handler = () => { }
225225

226226
const Joi = require('@hapi/joi')
227227
fastify.post('/the/url', {
@@ -231,7 +231,7 @@ test('Example Joi', t => {
231231
}).required()
232232
},
233233
validatorCompiler: ({ schema, method, url, httpPart }) => {
234-
return (data) => Joi.validate(data, schema)
234+
return data => schema.validate(data)
235235
}
236236
}, handler)
237237

@@ -241,7 +241,7 @@ test('Example Joi', t => {
241241
test('Example yup', t => {
242242
t.plan(1)
243243
const fastify = Fastify()
244-
const handler = () => {}
244+
const handler = () => { }
245245

246246
const yup = require('yup')
247247
// Validation options to match ajv's baseline options used in Fastify
@@ -280,7 +280,7 @@ test('Example yup', t => {
280280
test('Example - serialization', t => {
281281
t.plan(1)
282282
const fastify = Fastify()
283-
const handler = () => {}
283+
const handler = () => { }
284284

285285
const schema = {
286286
response: {
@@ -301,7 +301,7 @@ test('Example - serialization', t => {
301301
test('Example - serialization 2', t => {
302302
t.plan(1)
303303
const fastify = Fastify()
304-
const handler = () => {}
304+
const handler = () => { }
305305

306306
const schema = {
307307
response: {
@@ -351,7 +351,7 @@ test('Example - serializator', t => {
351351
test('Example - schemas examples', t => {
352352
t.plan(1)
353353
const fastify = Fastify()
354-
const handler = () => {}
354+
const handler = () => { }
355355

356356
fastify.addSchema({
357357
$id: 'http://foo/common.json',

0 commit comments

Comments
 (0)