fastify 3.27.2 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +47 -35
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +4 -0
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Reply.md +23 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +17 -10
- package/docs/Reference/Server.md +48 -63
- package/docs/Reference/TypeScript.md +11 -13
- package/docs/Reference/Validation-and-Serialization.md +28 -53
- package/docs/Type-Providers.md +257 -0
- package/examples/hooks.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/fastify.d.ts +34 -22
- package/fastify.js +37 -35
- package/lib/configValidator.js +902 -1023
- package/lib/contentTypeParser.js +6 -16
- package/lib/context.js +36 -10
- package/lib/decorate.js +3 -1
- package/lib/error-handler.js +158 -0
- package/lib/error-serializer.js +257 -0
- package/lib/errors.js +43 -9
- package/lib/fourOhFour.js +31 -20
- package/lib/handleRequest.js +10 -13
- package/lib/hooks.js +14 -9
- package/lib/pluginOverride.js +0 -3
- package/lib/pluginUtils.js +3 -2
- package/lib/reply.js +28 -157
- package/lib/request.js +13 -10
- package/lib/route.js +131 -138
- package/lib/schema-controller.js +2 -2
- package/lib/schemas.js +27 -1
- package/lib/server.js +219 -116
- package/lib/symbols.js +4 -3
- package/lib/validation.js +2 -1
- package/lib/warnings.js +2 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +31 -35
- package/test/404s.test.js +243 -110
- package/test/500s.test.js +2 -2
- package/test/async-await.test.js +13 -69
- package/test/content-parser.test.js +32 -0
- package/test/context-config.test.js +52 -0
- package/test/custom-http-server.test.js +14 -7
- package/test/custom-parser-async.test.js +0 -65
- package/test/custom-parser.test.js +54 -121
- package/test/decorator.test.js +1 -3
- package/test/delete.test.js +5 -5
- package/test/encapsulated-error-handler.test.js +50 -0
- package/test/esm/index.test.js +0 -14
- package/test/fastify-instance.test.js +4 -4
- package/test/fluent-schema.test.js +4 -4
- package/test/get.test.js +3 -3
- package/test/helper.js +18 -3
- package/test/hooks-async.test.js +14 -47
- package/test/hooks.on-ready.test.js +9 -4
- package/test/hooks.test.js +58 -99
- package/test/http2/closing.test.js +5 -11
- package/test/http2/unknown-http-method.test.js +3 -9
- package/test/https/custom-https-server.test.js +12 -6
- package/test/input-validation.js +2 -2
- package/test/internals/handleRequest.test.js +3 -40
- package/test/internals/initialConfig.test.js +33 -12
- package/test/internals/reply.test.js +245 -3
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.test.js +84 -1
- package/test/logger.test.js +80 -40
- package/test/maxRequestsPerSocket.test.js +6 -4
- package/test/middleware.test.js +2 -25
- package/test/nullable-validation.test.js +51 -14
- package/test/plugin.test.js +31 -5
- package/test/pretty-print.test.js +22 -10
- package/test/reply-error.test.js +123 -12
- package/test/request-error.test.js +2 -5
- package/test/route-hooks.test.js +17 -17
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +204 -20
- package/test/router-options.test.js +1 -1
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +24 -19
- package/test/schema-serialization.test.js +9 -9
- package/test/schema-special-usage.test.js +14 -81
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +1 -1
- package/test/stream.test.js +23 -12
- package/test/throw.test.js +8 -5
- package/test/type-provider.test.js +20 -0
- package/test/types/fastify.test-d.ts +10 -18
- package/test/types/import.js +2 -0
- package/test/types/import.ts +1 -0
- package/test/types/instance.test-d.ts +35 -14
- package/test/types/logger.test-d.ts +44 -15
- package/test/types/route.test-d.ts +8 -2
- package/test/types/schema.test-d.ts +2 -39
- package/test/types/type-provider.test-d.ts +417 -0
- package/test/validation-error-handling.test.js +8 -8
- package/test/versioned-routes.test.js +28 -16
- package/test/wrapThenable.test.js +7 -6
- package/types/content-type-parser.d.ts +17 -8
- package/types/hooks.d.ts +102 -59
- package/types/instance.d.ts +124 -104
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/reply.d.ts +16 -11
- package/types/request.d.ts +10 -5
- package/types/route.d.ts +42 -31
- package/types/schema.d.ts +1 -1
- package/types/type-provider.d.ts +99 -0
- package/types/utils.d.ts +1 -1
- package/lib/schema-compilers.js +0 -12
- package/test/emit-warning.test.js +0 -166
|
@@ -61,8 +61,8 @@ test('object or null body', t => {
|
|
|
61
61
|
method: 'POST',
|
|
62
62
|
url: '/',
|
|
63
63
|
handler: (req, reply) => {
|
|
64
|
-
t.equal(req.body,
|
|
65
|
-
reply.code(200).send({
|
|
64
|
+
t.equal(req.body, undefined)
|
|
65
|
+
reply.code(200).send({ isUndefinedBody: req.body === undefined })
|
|
66
66
|
},
|
|
67
67
|
schema: {
|
|
68
68
|
body: {
|
|
@@ -79,10 +79,8 @@ test('object or null body', t => {
|
|
|
79
79
|
type: 'object',
|
|
80
80
|
nullable: true,
|
|
81
81
|
properties: {
|
|
82
|
-
|
|
83
|
-
type: '
|
|
84
|
-
format: 'email',
|
|
85
|
-
nullable: true
|
|
82
|
+
isUndefinedBody: {
|
|
83
|
+
type: 'boolean'
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
}
|
|
@@ -100,7 +98,7 @@ test('object or null body', t => {
|
|
|
100
98
|
}, (err, response, body) => {
|
|
101
99
|
t.error(err)
|
|
102
100
|
t.equal(response.statusCode, 200)
|
|
103
|
-
t.same(JSON.parse(body), {
|
|
101
|
+
t.same(JSON.parse(body), { isUndefinedBody: true })
|
|
104
102
|
})
|
|
105
103
|
})
|
|
106
104
|
})
|
|
@@ -114,8 +112,8 @@ test('nullable body', t => {
|
|
|
114
112
|
method: 'POST',
|
|
115
113
|
url: '/',
|
|
116
114
|
handler: (req, reply) => {
|
|
117
|
-
t.equal(req.body,
|
|
118
|
-
reply.code(200).send({
|
|
115
|
+
t.equal(req.body, undefined)
|
|
116
|
+
reply.code(200).send({ isUndefinedBody: req.body === undefined })
|
|
119
117
|
},
|
|
120
118
|
schema: {
|
|
121
119
|
body: {
|
|
@@ -133,10 +131,8 @@ test('nullable body', t => {
|
|
|
133
131
|
type: 'object',
|
|
134
132
|
nullable: true,
|
|
135
133
|
properties: {
|
|
136
|
-
|
|
137
|
-
type: '
|
|
138
|
-
format: 'email',
|
|
139
|
-
nullable: true
|
|
134
|
+
isUndefinedBody: {
|
|
135
|
+
type: 'boolean'
|
|
140
136
|
}
|
|
141
137
|
}
|
|
142
138
|
}
|
|
@@ -154,7 +150,48 @@ test('nullable body', t => {
|
|
|
154
150
|
}, (err, response, body) => {
|
|
155
151
|
t.error(err)
|
|
156
152
|
t.equal(response.statusCode, 200)
|
|
157
|
-
t.same(JSON.parse(body), {
|
|
153
|
+
t.same(JSON.parse(body), { isUndefinedBody: true })
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('Nullable body with 204', t => {
|
|
159
|
+
t.plan(5)
|
|
160
|
+
|
|
161
|
+
const fastify = Fastify()
|
|
162
|
+
|
|
163
|
+
fastify.route({
|
|
164
|
+
method: 'POST',
|
|
165
|
+
url: '/',
|
|
166
|
+
handler: (req, reply) => {
|
|
167
|
+
t.equal(req.body, undefined)
|
|
168
|
+
reply.code(204).send()
|
|
169
|
+
},
|
|
170
|
+
schema: {
|
|
171
|
+
body: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
nullable: true,
|
|
174
|
+
properties: {
|
|
175
|
+
hello: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
format: 'email'
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
fastify.listen(0, (err) => {
|
|
185
|
+
fastify.server.unref()
|
|
186
|
+
t.error(err)
|
|
187
|
+
|
|
188
|
+
sget({
|
|
189
|
+
method: 'POST',
|
|
190
|
+
url: 'http://localhost:' + fastify.server.address().port
|
|
191
|
+
}, (err, response, body) => {
|
|
192
|
+
t.error(err)
|
|
193
|
+
t.equal(response.statusCode, 204)
|
|
194
|
+
t.equal(body.length, 0)
|
|
158
195
|
})
|
|
159
196
|
})
|
|
160
197
|
})
|
package/test/plugin.test.js
CHANGED
|
@@ -864,7 +864,7 @@ test('plugin metadata - dependencies (nested)', t => {
|
|
|
864
864
|
})
|
|
865
865
|
|
|
866
866
|
test('pluginTimeout', t => {
|
|
867
|
-
t.plan(
|
|
867
|
+
t.plan(5)
|
|
868
868
|
const fastify = Fastify({
|
|
869
869
|
pluginTimeout: 10
|
|
870
870
|
})
|
|
@@ -873,13 +873,35 @@ test('pluginTimeout', t => {
|
|
|
873
873
|
})
|
|
874
874
|
fastify.ready((err) => {
|
|
875
875
|
t.ok(err)
|
|
876
|
-
t.equal(err.
|
|
876
|
+
t.equal(err.message,
|
|
877
|
+
"fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // to no call done on purpose'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
878
|
+
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
879
|
+
t.ok(err.cause)
|
|
880
|
+
t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
|
|
881
|
+
})
|
|
882
|
+
})
|
|
883
|
+
|
|
884
|
+
test('pluginTimeout - named function', { only: true }, t => {
|
|
885
|
+
t.plan(5)
|
|
886
|
+
const fastify = Fastify({
|
|
887
|
+
pluginTimeout: 10
|
|
888
|
+
})
|
|
889
|
+
fastify.register(function nameFunction (app, opts, done) {
|
|
890
|
+
// to no call done on purpose
|
|
891
|
+
})
|
|
892
|
+
fastify.ready((err) => {
|
|
893
|
+
t.ok(err)
|
|
894
|
+
t.equal(err.message,
|
|
895
|
+
"fastify-plugin: Plugin did not start in time: 'nameFunction'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
896
|
+
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
897
|
+
t.ok(err.cause)
|
|
898
|
+
t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
|
|
877
899
|
})
|
|
878
900
|
})
|
|
879
901
|
|
|
880
902
|
test('pluginTimeout default', t => {
|
|
881
|
-
t.plan(
|
|
882
|
-
const clock = fakeTimer.install()
|
|
903
|
+
t.plan(5)
|
|
904
|
+
const clock = fakeTimer.install({ shouldClearNativeTimers: true })
|
|
883
905
|
|
|
884
906
|
const fastify = Fastify()
|
|
885
907
|
fastify.register(function (app, opts, done) {
|
|
@@ -889,7 +911,11 @@ test('pluginTimeout default', t => {
|
|
|
889
911
|
|
|
890
912
|
fastify.ready((err) => {
|
|
891
913
|
t.ok(err)
|
|
892
|
-
t.equal(err.
|
|
914
|
+
t.equal(err.message,
|
|
915
|
+
"fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // default time elapsed without calling done'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
916
|
+
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
917
|
+
t.ok(err.cause)
|
|
918
|
+
t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
|
|
893
919
|
})
|
|
894
920
|
|
|
895
921
|
t.teardown(clock.uninstall)
|
|
@@ -7,7 +7,7 @@ const Fastify = require('..')
|
|
|
7
7
|
test('pretty print - static routes', t => {
|
|
8
8
|
t.plan(2)
|
|
9
9
|
|
|
10
|
-
const fastify = Fastify()
|
|
10
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
11
11
|
fastify.get('/test', () => {})
|
|
12
12
|
fastify.get('/test/hello', () => {})
|
|
13
13
|
fastify.get('/hello/world', () => {})
|
|
@@ -29,7 +29,7 @@ test('pretty print - static routes', t => {
|
|
|
29
29
|
test('pretty print - parametric routes', t => {
|
|
30
30
|
t.plan(2)
|
|
31
31
|
|
|
32
|
-
const fastify = Fastify()
|
|
32
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
33
33
|
fastify.get('/test', () => {})
|
|
34
34
|
fastify.get('/test/:hello', () => {})
|
|
35
35
|
fastify.get('/hello/:world', () => {})
|
|
@@ -51,7 +51,7 @@ test('pretty print - parametric routes', t => {
|
|
|
51
51
|
test('pretty print - mixed parametric routes', t => {
|
|
52
52
|
t.plan(2)
|
|
53
53
|
|
|
54
|
-
const fastify = Fastify()
|
|
54
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
55
55
|
fastify.get('/test', () => {})
|
|
56
56
|
fastify.get('/test/:hello', () => {})
|
|
57
57
|
fastify.post('/test/:hello', () => {})
|
|
@@ -75,7 +75,7 @@ test('pretty print - mixed parametric routes', t => {
|
|
|
75
75
|
test('pretty print - wildcard routes', t => {
|
|
76
76
|
t.plan(2)
|
|
77
77
|
|
|
78
|
-
const fastify = Fastify()
|
|
78
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
79
79
|
fastify.get('/test', () => {})
|
|
80
80
|
fastify.get('/test/*', () => {})
|
|
81
81
|
fastify.get('/hello/*', () => {})
|
|
@@ -137,12 +137,14 @@ test('pretty print - commonPrefix', t => {
|
|
|
137
137
|
const radixExpected = `└── /
|
|
138
138
|
├── hel
|
|
139
139
|
│ ├── lo (GET)
|
|
140
|
+
│ │ lo (HEAD)
|
|
140
141
|
│ └── icopter (GET)
|
|
142
|
+
│ icopter (HEAD)
|
|
141
143
|
└── hello (PUT)
|
|
142
144
|
`
|
|
143
145
|
const flatExpected = `└── / (-)
|
|
144
|
-
├── helicopter (GET)
|
|
145
|
-
└── hello (GET, PUT)
|
|
146
|
+
├── helicopter (GET, HEAD)
|
|
147
|
+
└── hello (GET, PUT, HEAD)
|
|
146
148
|
`
|
|
147
149
|
t.equal(typeof radixTree, 'string')
|
|
148
150
|
t.equal(typeof flatTree, 'string')
|
|
@@ -174,31 +176,41 @@ test('pretty print - includeMeta, includeHooks', t => {
|
|
|
174
176
|
│ │ • (onTimeout) ["onTimeout()"]
|
|
175
177
|
│ │ • (onRequest) ["anonymous()"]
|
|
176
178
|
│ │ • (errorHandler) "defaultErrorHandler()"
|
|
179
|
+
│ │ lo (HEAD)
|
|
180
|
+
│ │ • (onTimeout) ["onTimeout()"]
|
|
181
|
+
│ │ • (onRequest) ["anonymous()"]
|
|
182
|
+
│ │ • (onSend) ["headRouteOnSendHandler()"]
|
|
183
|
+
│ │ • (errorHandler) "defaultErrorHandler()"
|
|
177
184
|
│ └── icopter (GET)
|
|
178
185
|
│ • (onTimeout) ["onTimeout()"]
|
|
179
186
|
│ • (onRequest) ["anonymous()"]
|
|
180
187
|
│ • (errorHandler) "defaultErrorHandler()"
|
|
188
|
+
│ icopter (HEAD)
|
|
189
|
+
│ • (onTimeout) ["onTimeout()"]
|
|
190
|
+
│ • (onRequest) ["anonymous()"]
|
|
191
|
+
│ • (onSend) ["headRouteOnSendHandler()"]
|
|
192
|
+
│ • (errorHandler) "defaultErrorHandler()"
|
|
181
193
|
└── hello (PUT)
|
|
182
194
|
• (onTimeout) ["onTimeout()"]
|
|
183
195
|
• (onRequest) ["anonymous()"]
|
|
184
196
|
• (errorHandler) "defaultErrorHandler()"
|
|
185
197
|
`
|
|
186
198
|
const flatExpected = `└── / (-)
|
|
187
|
-
├── helicopter (GET)
|
|
199
|
+
├── helicopter (GET, HEAD)
|
|
188
200
|
│ • (onTimeout) ["onTimeout()"]
|
|
189
201
|
│ • (onRequest) ["anonymous()"]
|
|
190
202
|
│ • (errorHandler) "defaultErrorHandler()"
|
|
191
|
-
└── hello (GET, PUT)
|
|
203
|
+
└── hello (GET, PUT, HEAD)
|
|
192
204
|
• (onTimeout) ["onTimeout()"]
|
|
193
205
|
• (onRequest) ["anonymous()"]
|
|
194
206
|
• (errorHandler) "defaultErrorHandler()"
|
|
195
207
|
`
|
|
196
208
|
|
|
197
209
|
const hooksOnlyExpected = `└── / (-)
|
|
198
|
-
├── helicopter (GET)
|
|
210
|
+
├── helicopter (GET, HEAD)
|
|
199
211
|
│ • (onTimeout) ["onTimeout()"]
|
|
200
212
|
│ • (onRequest) ["anonymous()"]
|
|
201
|
-
└── hello (GET, PUT)
|
|
213
|
+
└── hello (GET, PUT, HEAD)
|
|
202
214
|
• (onTimeout) ["onTimeout()"]
|
|
203
215
|
• (onRequest) ["anonymous()"]
|
|
204
216
|
`
|
package/test/reply-error.test.js
CHANGED
|
@@ -290,7 +290,7 @@ test('Support rejection with values that are not Error instances', t => {
|
|
|
290
290
|
} else {
|
|
291
291
|
t.equal(err, nonErr)
|
|
292
292
|
}
|
|
293
|
-
reply.send('error')
|
|
293
|
+
reply.code(500).send('error')
|
|
294
294
|
})
|
|
295
295
|
|
|
296
296
|
fastify.inject({
|
|
@@ -337,7 +337,7 @@ test('invalid schema - ajv', t => {
|
|
|
337
337
|
})
|
|
338
338
|
})
|
|
339
339
|
|
|
340
|
-
test('should set the status code and the headers from the error object (from route handler)', t => {
|
|
340
|
+
test('should set the status code and the headers from the error object (from route handler) (no custom error handler)', t => {
|
|
341
341
|
t.plan(4)
|
|
342
342
|
const fastify = Fastify()
|
|
343
343
|
|
|
@@ -375,7 +375,7 @@ test('should set the status code and the headers from the error object (from cus
|
|
|
375
375
|
|
|
376
376
|
fastify.setErrorHandler((err, request, reply) => {
|
|
377
377
|
t.equal(err.message, 'ouch')
|
|
378
|
-
t.equal(reply.raw.statusCode,
|
|
378
|
+
t.equal(reply.raw.statusCode, 200)
|
|
379
379
|
const error = new Error('kaboom')
|
|
380
380
|
error.headers = { hello: 'world' }
|
|
381
381
|
error.statusCode = 400
|
|
@@ -446,6 +446,74 @@ test('should throw an error if the custom serializer does not serialize the payl
|
|
|
446
446
|
})
|
|
447
447
|
})
|
|
448
448
|
|
|
449
|
+
test('should not set headers or status code for custom error handler', t => {
|
|
450
|
+
t.plan(7)
|
|
451
|
+
|
|
452
|
+
const fastify = Fastify()
|
|
453
|
+
fastify.get('/', function (req, reply) {
|
|
454
|
+
const err = new Error('kaboom')
|
|
455
|
+
err.headers = {
|
|
456
|
+
'fake-random-header': 'abc'
|
|
457
|
+
}
|
|
458
|
+
reply.send(err)
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
fastify.setErrorHandler(async (err, req, res) => {
|
|
462
|
+
t.equal(res.statusCode, 200)
|
|
463
|
+
t.equal('fake-random-header' in res.headers, false)
|
|
464
|
+
return res.code(500).send(err.message)
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
fastify.inject({
|
|
468
|
+
method: 'GET',
|
|
469
|
+
url: '/'
|
|
470
|
+
}, (err, res) => {
|
|
471
|
+
t.error(err)
|
|
472
|
+
t.equal(res.statusCode, 500)
|
|
473
|
+
t.equal('fake-random-header' in res.headers, false)
|
|
474
|
+
t.equal(res.headers['content-length'], ('kaboom'.length).toString())
|
|
475
|
+
t.same(res.payload, 'kaboom')
|
|
476
|
+
})
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
test('error thrown by custom error handler routes to default error handler', t => {
|
|
480
|
+
t.plan(6)
|
|
481
|
+
|
|
482
|
+
const fastify = Fastify()
|
|
483
|
+
|
|
484
|
+
const error = new Error('kaboom')
|
|
485
|
+
error.headers = {
|
|
486
|
+
'fake-random-header': 'abc'
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
fastify.get('/', function (req, reply) {
|
|
490
|
+
reply.send(error)
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
const newError = new Error('kabong')
|
|
494
|
+
|
|
495
|
+
fastify.setErrorHandler(async (err, req, res) => {
|
|
496
|
+
t.equal(res.statusCode, 200)
|
|
497
|
+
t.equal('fake-random-header' in res.headers, false)
|
|
498
|
+
t.same(err.headers, error.headers)
|
|
499
|
+
|
|
500
|
+
return res.send(newError)
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
fastify.inject({
|
|
504
|
+
method: 'GET',
|
|
505
|
+
url: '/'
|
|
506
|
+
}, (err, res) => {
|
|
507
|
+
t.error(err)
|
|
508
|
+
t.equal(res.statusCode, 500)
|
|
509
|
+
t.same(JSON.parse(res.payload), {
|
|
510
|
+
error: statusCodes['500'],
|
|
511
|
+
message: newError.message,
|
|
512
|
+
statusCode: 500
|
|
513
|
+
})
|
|
514
|
+
})
|
|
515
|
+
})
|
|
516
|
+
|
|
449
517
|
// Issue 2078 https://github.com/fastify/fastify/issues/2078
|
|
450
518
|
// Supported error code list: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
|
451
519
|
const invalidErrorCodes = [
|
|
@@ -475,6 +543,34 @@ invalidErrorCodes.forEach((invalidCode) => {
|
|
|
475
543
|
})
|
|
476
544
|
})
|
|
477
545
|
|
|
546
|
+
test('error handler is triggered when a string is thrown from sync handler', t => {
|
|
547
|
+
t.plan(3)
|
|
548
|
+
|
|
549
|
+
const fastify = Fastify()
|
|
550
|
+
|
|
551
|
+
const throwable = 'test'
|
|
552
|
+
const payload = 'error'
|
|
553
|
+
|
|
554
|
+
fastify.get('/', function (req, reply) {
|
|
555
|
+
// eslint-disable-next-line no-throw-literal
|
|
556
|
+
throw throwable
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
fastify.setErrorHandler((err, req, res) => {
|
|
560
|
+
t.equal(err, throwable)
|
|
561
|
+
|
|
562
|
+
res.send(payload)
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
fastify.inject({
|
|
566
|
+
method: 'GET',
|
|
567
|
+
url: '/'
|
|
568
|
+
}, (err, res) => {
|
|
569
|
+
t.error(err)
|
|
570
|
+
t.equal(res.payload, payload)
|
|
571
|
+
})
|
|
572
|
+
})
|
|
573
|
+
|
|
478
574
|
test('status code should be set to 500 and return an error json payload if route handler throws any non Error object expression', async t => {
|
|
479
575
|
t.plan(2)
|
|
480
576
|
const fastify = Fastify()
|
|
@@ -508,24 +604,39 @@ test('should preserve the status code set by the user if an expression is thrown
|
|
|
508
604
|
})
|
|
509
605
|
|
|
510
606
|
test('should trigger error handlers if a sync route throws any non-error object', async t => {
|
|
511
|
-
t.plan(
|
|
607
|
+
t.plan(2)
|
|
512
608
|
|
|
513
609
|
const fastify = Fastify()
|
|
514
610
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
611
|
+
const throwable = 'test'
|
|
612
|
+
const payload = 'error'
|
|
613
|
+
|
|
614
|
+
fastify.get('/', function async (req, reply) {
|
|
615
|
+
// eslint-disable-next-line no-throw-literal
|
|
616
|
+
throw throwable
|
|
518
617
|
})
|
|
519
618
|
|
|
520
|
-
fastify.setErrorHandler(
|
|
521
|
-
t.
|
|
522
|
-
|
|
619
|
+
fastify.setErrorHandler((err, req, res) => {
|
|
620
|
+
t.equal(err, throwable)
|
|
621
|
+
res.code(500).send(payload)
|
|
622
|
+
})
|
|
623
|
+
|
|
624
|
+
const reply = await fastify.inject({ method: 'GET', url: '/' })
|
|
625
|
+
t.equal(reply.statusCode, 500)
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
test('should trigger error handlers if a sync route throws undefined', async t => {
|
|
629
|
+
t.plan(1)
|
|
630
|
+
|
|
631
|
+
const fastify = Fastify()
|
|
632
|
+
|
|
633
|
+
fastify.get('/', function async (req, reply) {
|
|
634
|
+
// eslint-disable-next-line no-throw-literal
|
|
635
|
+
throw undefined
|
|
523
636
|
})
|
|
524
637
|
|
|
525
|
-
// ----
|
|
526
638
|
const reply = await fastify.inject({ method: 'GET', url: '/' })
|
|
527
639
|
t.equal(reply.statusCode, 500)
|
|
528
|
-
t.equal(JSON.parse(reply.body).foo, 'bar')
|
|
529
640
|
})
|
|
530
641
|
|
|
531
642
|
test('setting content-type on reply object should not hang the server case 1', t => {
|
|
@@ -43,7 +43,7 @@ test('default 400 on request error with custom error handler', t => {
|
|
|
43
43
|
|
|
44
44
|
fastify.setErrorHandler(function (err, request, reply) {
|
|
45
45
|
t.type(request, 'object')
|
|
46
|
-
t.type(request, fastify[kRequest])
|
|
46
|
+
t.type(request, fastify[kRequest].parent)
|
|
47
47
|
reply
|
|
48
48
|
.code(err.statusCode)
|
|
49
49
|
.type('application/json; charset=utf-8')
|
|
@@ -132,10 +132,7 @@ test('default clientError handler ignores sockets in destroyed state', t => {
|
|
|
132
132
|
|
|
133
133
|
const fastify = Fastify({
|
|
134
134
|
bodyLimit: 1,
|
|
135
|
-
keepAliveTimeout: 100
|
|
136
|
-
logger: {
|
|
137
|
-
level: 'trace'
|
|
138
|
-
}
|
|
135
|
+
keepAliveTimeout: 100
|
|
139
136
|
})
|
|
140
137
|
fastify.server.on('clientError', () => {
|
|
141
138
|
// this handler is called after default handler, so we can make sure end was not called
|
package/test/route-hooks.test.js
CHANGED
|
@@ -7,11 +7,11 @@ const Fastify = require('../')
|
|
|
7
7
|
|
|
8
8
|
process.removeAllListeners('warning')
|
|
9
9
|
|
|
10
|
-
function endRouteHook (doneOrPayload, done) {
|
|
10
|
+
function endRouteHook (doneOrPayload, done, doneValue) {
|
|
11
11
|
if (typeof doneOrPayload === 'function') {
|
|
12
|
-
doneOrPayload()
|
|
12
|
+
doneOrPayload(doneValue)
|
|
13
13
|
} else {
|
|
14
|
-
done()
|
|
14
|
+
done(doneValue)
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -152,9 +152,9 @@ function testBeforeHandlerHook (hook) {
|
|
|
152
152
|
const fastify = Fastify()
|
|
153
153
|
|
|
154
154
|
fastify.post('/', {
|
|
155
|
-
[hook]: (req, reply, done) => {
|
|
155
|
+
[hook]: (req, reply, doneOrPayload, done) => {
|
|
156
156
|
req.hello = 'earth'
|
|
157
|
-
done
|
|
157
|
+
endRouteHook(doneOrPayload, done)
|
|
158
158
|
}
|
|
159
159
|
}, (req, reply) => {
|
|
160
160
|
reply.send({ hello: req.hello })
|
|
@@ -190,8 +190,8 @@ function testBeforeHandlerHook (hook) {
|
|
|
190
190
|
const fastify = Fastify()
|
|
191
191
|
|
|
192
192
|
fastify.post('/', {
|
|
193
|
-
[hook]: (req, reply, done) => {
|
|
194
|
-
done
|
|
193
|
+
[hook]: (req, reply, doneOrPayload, done) => {
|
|
194
|
+
endRouteHook(doneOrPayload, done, new Error('kaboom'))
|
|
195
195
|
}
|
|
196
196
|
}, (req, reply) => {
|
|
197
197
|
reply.send(req.body)
|
|
@@ -221,7 +221,7 @@ function testBeforeHandlerHook (hook) {
|
|
|
221
221
|
|
|
222
222
|
fastify.setErrorHandler(async (error, request, reply) => {
|
|
223
223
|
t.same(error, myError, 'the error object throws by the user')
|
|
224
|
-
reply.send({ this: 'is', my: 'error' })
|
|
224
|
+
return reply.code(500).send({ this: 'is', my: 'error' })
|
|
225
225
|
})
|
|
226
226
|
|
|
227
227
|
fastify.get('/', {
|
|
@@ -271,9 +271,9 @@ function testBeforeHandlerHook (hook) {
|
|
|
271
271
|
const fastify = Fastify()
|
|
272
272
|
|
|
273
273
|
fastify.post('/', {
|
|
274
|
-
[hook]: (req, reply, done) => {
|
|
274
|
+
[hook]: (req, reply, doneOrPayload, done) => {
|
|
275
275
|
reply.code(401)
|
|
276
|
-
done
|
|
276
|
+
endRouteHook(doneOrPayload, done, new Error('go away'))
|
|
277
277
|
}
|
|
278
278
|
}, (req, reply) => {
|
|
279
279
|
reply.send(req.body)
|
|
@@ -302,10 +302,10 @@ function testBeforeHandlerHook (hook) {
|
|
|
302
302
|
fastify.decorate('foo', 42)
|
|
303
303
|
|
|
304
304
|
fastify.post('/', {
|
|
305
|
-
[hook]: function (req, reply, done) {
|
|
305
|
+
[hook]: function (req, reply, doneOrPayload, done) {
|
|
306
306
|
t.equal(this.foo, 42)
|
|
307
307
|
this.foo += 1
|
|
308
|
-
done
|
|
308
|
+
endRouteHook(doneOrPayload, done)
|
|
309
309
|
}
|
|
310
310
|
}, function (req, reply) {
|
|
311
311
|
reply.send({ foo: this.foo })
|
|
@@ -329,10 +329,10 @@ function testBeforeHandlerHook (hook) {
|
|
|
329
329
|
fastify.decorate('foo', 42)
|
|
330
330
|
|
|
331
331
|
fastify.post('/', {
|
|
332
|
-
[hook]: [function (req, reply, done) {
|
|
332
|
+
[hook]: [function (req, reply, doneOrPayload, done) {
|
|
333
333
|
t.equal(this.foo, 42)
|
|
334
334
|
this.foo += 1
|
|
335
|
-
done
|
|
335
|
+
endRouteHook(doneOrPayload, done)
|
|
336
336
|
}]
|
|
337
337
|
}, function (req, reply) {
|
|
338
338
|
reply.send({ foo: this.foo })
|
|
@@ -423,7 +423,7 @@ test('preParsing option should be called before preValidation hook', t => {
|
|
|
423
423
|
})
|
|
424
424
|
|
|
425
425
|
fastify.post('/', {
|
|
426
|
-
preParsing: (req, reply, done) => {
|
|
426
|
+
preParsing: (req, reply, payload, done) => {
|
|
427
427
|
req.called = true
|
|
428
428
|
done()
|
|
429
429
|
}
|
|
@@ -473,7 +473,7 @@ test('onRequest option should be called before preParsing', t => {
|
|
|
473
473
|
t.plan(3)
|
|
474
474
|
const fastify = Fastify()
|
|
475
475
|
|
|
476
|
-
fastify.addHook('preParsing', (req, reply, done) => {
|
|
476
|
+
fastify.addHook('preParsing', (req, reply, payload, done) => {
|
|
477
477
|
t.ok(req.called)
|
|
478
478
|
done()
|
|
479
479
|
})
|
|
@@ -503,7 +503,7 @@ test('onTimeout on route', t => {
|
|
|
503
503
|
const fastify = Fastify({ connectionTimeout: 500 })
|
|
504
504
|
|
|
505
505
|
fastify.get('/timeout', {
|
|
506
|
-
|
|
506
|
+
handler (request, reply) { },
|
|
507
507
|
onTimeout (request, reply, done) {
|
|
508
508
|
t.pass('onTimeout called')
|
|
509
509
|
done()
|
|
@@ -565,7 +565,8 @@ test('matches only /prefix/ with a / route - prefixTrailingSlash: "slash", igno
|
|
|
565
565
|
test('calls onRoute only once when prefixing', async t => {
|
|
566
566
|
t.plan(1)
|
|
567
567
|
const fastify = Fastify({
|
|
568
|
-
ignoreTrailingSlash: false
|
|
568
|
+
ignoreTrailingSlash: false,
|
|
569
|
+
exposeHeadRoutes: false
|
|
569
570
|
})
|
|
570
571
|
|
|
571
572
|
let onRouteCalled = 0
|