fastify 3.21.2 → 3.21.6

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 CHANGED
@@ -1,5 +1,7 @@
1
1
  <div align="center">
2
- <img src="https://github.com/fastify/graphics/raw/HEAD/fastify-landscape-outlined.svg" width="650" height="auto"/>
2
+ <a href="https://fastify.io/">
3
+ <img src="https://github.com/fastify/graphics/raw/HEAD/fastify-landscape-outlined.svg" width="650" height="auto"/>
4
+ </a>
3
5
  </div>
4
6
 
5
7
  <div align="center">
@@ -238,7 +238,7 @@ server {
238
238
  }
239
239
  ```
240
240
 
241
- [nginx]: http://nginx.org/
241
+ [nginx]: https://nginx.org/
242
242
 
243
243
  ## Kubernetes
244
244
  <a id="kubernetes"></a>
package/docs/Reply.md CHANGED
@@ -335,7 +335,7 @@ If you pass to *send* an object that is an instance of *Error*, Fastify will aut
335
335
  }
336
336
  ```
337
337
 
338
- You can add some custom property to the Error object, such as `headers`, that will be used to enhance the HTTP response.<br>
338
+ You can add custom properties to the Error object, such as `headers`, that will be used to enhance the HTTP response.<br>
339
339
  *Note: If you are passing an error to `send` and the statusCode is less than 400, Fastify will automatically set it at 500.*
340
340
 
341
341
  Tip: you can simplify errors by using the [`http-errors`](https://npm.im/http-errors) module or [`fastify-sensible`](https://github.com/fastify/fastify-sensible) plugin to generate errors:
@@ -376,7 +376,7 @@ fastify.get('/', {
376
376
  })
377
377
  ```
378
378
 
379
- If you want to completely customize the error handling, check out [`setErrorHandler`](Server.md#seterrorhandler) API.<br>
379
+ If you want to customize error handling, check out [`setErrorHandler`](Server.md#seterrorhandler) API.<br>
380
380
  *Note: you are responsible for logging when customizing the error handler*
381
381
 
382
382
  API:
package/docs/Request.md CHANGED
@@ -3,32 +3,32 @@
3
3
  ## Request
4
4
  The first parameter of the handler function is `Request`.<br>
5
5
  Request is a core Fastify object containing the following fields:
6
- - `query` - the parsed querystring
6
+ - `query` - the parsed querystring, its format is specified by [`querystringParser`](Server.md#querystringParser)
7
7
  - `body` - the body
8
8
  - `params` - the params matching the URL
9
9
  - [`headers`](#headers) - the headers getter and setter
10
10
  - `raw` - the incoming HTTP request from Node core
11
11
  - `req` *(deprecated, use `.raw` instead)* - the incoming HTTP request from Node core
12
12
  - `server` - The Fastify server instance, scoped to the current [encapsulation context](Encapsulation.md)
13
- - `id` - the request id
13
+ - `id` - the request ID
14
14
  - `log` - the logger instance of the incoming request
15
15
  - `ip` - the IP address of the incoming request
16
16
  - `ips` - an array of the IP addresses, ordered from closest to furthest, in the `X-Forwarded-For` header of the incoming request (only when the [`trustProxy`](Server.md#factory-trust-proxy) option is enabled)
17
- - `hostname` - the hostname of the incoming request (derived from `X-Forwarded-Host` header when the [`trustProxy`](Server.md#factory-trust-proxy) option is enabled)
17
+ - `hostname` - the host of the incoming request (derived from `X-Forwarded-Host` header when the [`trustProxy`](Server.md#factory-trust-proxy) option is enabled). For HTTP/2 compatibility it returns `:authority` if no host header exists.
18
18
  - `protocol` - the protocol of the incoming request (`https` or `http`)
19
19
  - `method` - the method of the incoming request
20
- - `url` - the url of the incoming request
20
+ - `url` - the URL of the incoming request
21
21
  - `routerMethod` - the method defined for the router that is handling the request
22
22
  - `routerPath` - the path pattern defined for the router that is handling the request
23
23
  - `is404` - true if request is being handled by 404 handler, false if it is not
24
24
  - `connection` - Deprecated, use `socket` instead. The underlying connection of the incoming request.
25
25
  - `socket` - the underlying connection of the incoming request
26
- - `context` - A Fastify internal object. You should not use it directly or modify it. It is usefull to access one special key:
26
+ - `context` - A Fastify internal object. You should not use it directly or modify it. It is useful to access one special key:
27
27
  - `context.config` - The route [`config`](Routes.md#routes-config) object.
28
28
 
29
29
  ### Headers
30
30
 
31
- The `request.headers` is a getter that return an Object with the headers of the incoming request.
31
+ The `request.headers` is a getter that returns an Object with the headers of the incoming request.
32
32
  You can set custom headers like this:
33
33
 
34
34
  ```js
package/docs/Server.md CHANGED
@@ -110,7 +110,7 @@ fastify.get('/bar', function (req, reply) {
110
110
 
111
111
  <a name="factory-max-param-length"></a>
112
112
  ### `maxParamLength`
113
- You can set a custom length for parameters in parametric (standard, regex, and multi) routes by using `maxParamLength` option, the default value is 100 characters.<br>
113
+ You can set a custom length for parameters in parametric (standard, regex, and multi) routes by using `maxParamLength` option; the default value is 100 characters.<br>
114
114
  This can be useful especially if you have some regex based route, protecting you against [DoS attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).<br>
115
115
  *If the maximum length limit is reached, the not found route will be invoked.*
116
116
 
@@ -167,7 +167,7 @@ are not present on the object, they will be added accordingly:
167
167
  * `level`: the minimum logging level. If not set, it will be set to `'info'`.
168
168
  * `serializers`: a hash of serialization functions. By default, serializers
169
169
  are added for `req` (incoming request objects), `res` (outgoing response
170
- objets), and `err` (standard `Error` objects). When a log method receives
170
+ objects), and `err` (standard `Error` objects). When a log method receives
171
171
  an object with any of these properties then the respective serializer will
172
172
  be used for that property. For example:
173
173
  ```js
@@ -228,7 +228,7 @@ Please note that this setting will also disable an error log written by the defa
228
228
  <a name="custom-http-server"></a>
229
229
  ### `serverFactory`
230
230
  You can pass a custom HTTP server to Fastify by using the `serverFactory` option.<br/>
231
- `serverFactory` is a function that takes an `handler` parameter, which takes the `request` and `response` objects as parameters, and an options object, which is the same you have passed to Fastify.
231
+ `serverFactory` is a function that takes a `handler` parameter, which takes the `request` and `response` objects as parameters, and an options object, which is the same you have passed to Fastify.
232
232
 
233
233
  ```js
234
234
  const serverFactory = (handler, opts) => {
@@ -255,7 +255,7 @@ Internally Fastify uses the API of Node core HTTP server, so if you are using a
255
255
 
256
256
  + Default: `true`
257
257
 
258
- Internally, and by default, Fastify will automatically infer the root properties of JSON Schemas if it doesn't find valid root properties according to the JSON Schema spec. If you wish to implement your own schema validation compiler, for example: to parse schemas as JTD instead of JSON Schema, then you can explicitly set this option to `false` to make sure the schemas you receive are unmodified and are not being treated internally as JSON Schema.
258
+ Internally, and by default, Fastify will automatically infer the root properties of JSON Schemas if it does not find valid root properties according to the JSON Schema spec. If you wish to implement your own schema validation compiler, for example: to parse schemas as JTD instead of JSON Schema, then you can explicitly set this option to `false` to make sure the schemas you receive are unmodified and are not being treated internally as JSON Schema.
259
259
 
260
260
  ```js
261
261
  const AjvJTD = require('ajv/dist/jtd'/* only valid for AJV v7+ */)
@@ -298,6 +298,8 @@ fastify.get('/user/:username', (request, reply) => {
298
298
  Please note that setting this option to `false` goes against
299
299
  [RFC3986](https://tools.ietf.org/html/rfc3986#section-6.2.2.1).
300
300
 
301
+ Also note, this setting will not affect query strings. If you want to change the way query strings are handled take a look at [`querystringParser`](./Server.md#querystringParser).
302
+
301
303
  <a name="factory-request-id-header"></a>
302
304
  ### `requestIdHeader`
303
305
 
@@ -333,7 +335,7 @@ const fastify = require('fastify')({
333
335
  <a name="factory-trust-proxy"></a>
334
336
  ### `trustProxy`
335
337
 
336
- By enabling the `trustProxy` option, Fastify will have knowledge that it's sitting behind a proxy and that the `X-Forwarded-*` header fields may be trusted, which otherwise may be easily spoofed.
338
+ By enabling the `trustProxy` option, Fastify will know that it is sitting behind a proxy and that the `X-Forwarded-*` header fields may be trusted, which otherwise may be easily spoofed.
337
339
 
338
340
  ```js
339
341
  const fastify = Fastify({ trustProxy: true })
@@ -388,6 +390,17 @@ const fastify = require('fastify')({
388
390
  })
389
391
  ```
390
392
 
393
+ You can also use Fastify's default parser but change some handling behaviour, like the example below for case insensitive keys and values:
394
+
395
+ ```js
396
+ const querystring = require('querystring')
397
+ const fastify = require('fastify')({
398
+ querystringParser: str => querystring.parse(str.toLowerCase())
399
+ })
400
+ ```
401
+
402
+ Note, if you only want the keys (and not the values) to be case insensitive we recommend using a custom parser to convert only the keys to lowercase.
403
+
391
404
  <a name="exposeHeadRoutes"></a>
392
405
  ### `exposeHeadRoutes`
393
406
 
@@ -497,7 +510,7 @@ increased to fit the use case. Node core defaults this to `0`. `
497
510
  + Default: `null`
498
511
 
499
512
  Fastify provides default error handlers for the most common use cases.
500
- Using this option it is possible to override one or more of those handlers with custom code.
513
+ It is possible to override one or more of those handlers with custom code using this option.
501
514
 
502
515
  *Note: Only `FST_ERR_BAD_URL` is implemented at the moment.*
503
516
 
@@ -519,7 +532,7 @@ const fastify = require('fastify')({
519
532
 
520
533
  Set a [clientErrorHandler](https://nodejs.org/api/http.html#http_event_clienterror) that listens to `error` events emitted by client connections and responds with a `400`.
521
534
 
522
- Using this option it is possible to override the default `clientErrorHandler`.
535
+ It is possible to override the default `clientErrorHandler` using this option.
523
536
 
524
537
  + Default:
525
538
  ```js
@@ -649,7 +662,7 @@ fastify.ready().then(() => {
649
662
 
650
663
  <a name="listen"></a>
651
664
  #### listen
652
- Starts the server on the given port after all the plugins are loaded, internally waits for the `.ready()` event. The callback is the same as the Node core. By default, the server will listen on the address resolved by `localhost` when no specific address is provided (`127.0.0.1` or `::1` depending on the operating system). If listening on any available interface is desired, then specifying `0.0.0.0` for the address will listen on all IPv4 address. Using `::` for the address will listen on all IPv6 addresses, and, depending on OS, may also listen on all IPv4 addresses. Be careful when deciding to listen on all interfaces; it comes with inherent [security risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
665
+ Starts the server on the given port after all the plugins are loaded, internally waits for the `.ready()` event. The callback is the same as the Node core. By default, the server will listen on the address resolved by `localhost` when no specific address is provided (`127.0.0.1` or `::1` depending on the operating system). If listening on any available interface is desired, then specifying `0.0.0.0` for the address will listen on all IPv4 addresses. Using `::` for the address will listen on all IPv6 addresses and, depending on OS, may also listen on all IPv4 addresses. Be careful when deciding to listen on all interfaces; it comes with inherent [security risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
653
666
 
654
667
  ```js
655
668
  fastify.listen(3000, (err, address) => {
@@ -962,15 +975,15 @@ const fastify = Fastify({
962
975
  },
963
976
 
964
977
  /**
965
- * The compilers factory let you to fully control the validator and serializer
978
+ * The compilers factory let you fully control the validator and serializer
966
979
  * in the Fastify's lifecycle, providing the encapsulation to your compilers.
967
980
  */
968
981
  compilersFactory: {
969
982
  /**
970
983
  * This factory is called whenever a new validator instance is needed.
971
- * It may be called whenever `fastify.register()` is called only if new schemas has been added to the
984
+ * It may be called whenever `fastify.register()` is called only if new schemas have been added to the
972
985
  * encapsulation context.
973
- * It may receive as input the schemas of the parent context if some schemas has been added.
986
+ * It may receive as input the schemas of the parent context if some schemas have been added.
974
987
  * @param {object} externalSchemas these schemas will be returned by the `bucket.getSchemas()`. Needed to resolve the external references $ref.
975
988
  * @param {object} ajvServerOption the server `ajv` options to build your compilers accordingly
976
989
  */
@@ -985,9 +998,9 @@ const fastify = Fastify({
985
998
 
986
999
  /**
987
1000
  * This factory is called whenever a new serializer instance is needed.
988
- * It may be called whenever `fastify.register()` is called only if new schemas has been added to the
1001
+ * It may be called whenever `fastify.register()` is called only if new schemas have been added to the
989
1002
  * encapsulation context.
990
- * It may receive as input the schemas of the parent context if some schemas has been added.
1003
+ * It may receive as input the schemas of the parent context if some schemas have been added.
991
1004
  * @param {object} externalSchemas these schemas will be returned by the `bucket.getSchemas()`. Needed to resolve the external references $ref.
992
1005
  * @param {object} serializerOptsServerOption the server `serializerOpts` options to build your compilers accordingly
993
1006
  */
@@ -1006,7 +1019,7 @@ const fastify = Fastify({
1006
1019
  ##### Ajv 8 as default schema validator
1007
1020
 
1008
1021
  Ajv 8 is the evolution of Ajv 6, and it has a lot of improvements and new features.
1009
- To use the new Ajv 8 features such as JTD or the Standalone mode, refers to the [`@fastify/ajv-compiler` documentation](https://github.com/fastify/ajv-compiler#usage).
1022
+ To use the new Ajv 8 features such as JTD or the Standalone mode, refer to the [`@fastify/ajv-compiler` documentation](https://github.com/fastify/ajv-compiler#usage).
1010
1023
 
1011
1024
  To use Ajv 8 as default schema validator, you can use the following code:
1012
1025
 
@@ -1031,7 +1044,7 @@ const app = fastify({
1031
1044
  }
1032
1045
  })
1033
1046
 
1034
- // Done! You can now use Ajv 8 options and keywords into your schemas!
1047
+ // Done! You can now use Ajv 8 options and keywords in your schemas!
1035
1048
  ```
1036
1049
 
1037
1050
  <a name="set-not-found-handler"></a>
package/lib/decorate.js CHANGED
@@ -36,7 +36,7 @@ function decorate (instance, name, fn, dependencies) {
36
36
 
37
37
  function decorateConstructor (konstructor, name, fn, dependencies) {
38
38
  const instance = konstructor.prototype
39
- if (instance.hasOwnProperty(name) || konstructor.props.includes(name)) {
39
+ if (instance.hasOwnProperty(name) || hasKey(konstructor, name)) {
40
40
  throw new FST_ERR_DEC_ALREADY_PRESENT(name)
41
41
  }
42
42
 
@@ -47,10 +47,10 @@ function decorateConstructor (konstructor, name, fn, dependencies) {
47
47
  get: fn.getter,
48
48
  set: fn.setter
49
49
  })
50
- } else if (fn) {
50
+ } else if (typeof fn === 'function') {
51
51
  instance[name] = fn
52
52
  } else {
53
- konstructor.props.push(name)
53
+ konstructor.props.push({ key: name, value: fn })
54
54
  }
55
55
  }
56
56
 
@@ -74,11 +74,17 @@ function checkExistence (instance, name) {
74
74
  return instance in this
75
75
  }
76
76
 
77
+ function hasKey (fn, name) {
78
+ return fn.props.find(({ key }) => key === name)
79
+ }
80
+
77
81
  function checkRequestExistence (name) {
82
+ if (name && hasKey(this[kRequest], name)) return true
78
83
  return checkExistence(this[kRequest].prototype, name)
79
84
  }
80
85
 
81
86
  function checkReplyExistence (name) {
87
+ if (name && hasKey(this[kReply], name)) return true
82
88
  return checkExistence(this[kReply].prototype, name)
83
89
  }
84
90
 
@@ -4,10 +4,9 @@ const semver = require('semver')
4
4
  const assert = require('assert')
5
5
  const registeredPlugins = Symbol.for('registered-plugin')
6
6
  const {
7
- kReply,
8
- kRequest,
9
7
  kTestInternals
10
8
  } = require('./symbols.js')
9
+ const { exist, existReply, existRequest } = require('./decorate')
11
10
  const { FST_ERR_PLUGIN_VERSION_MISMATCH } = require('./errors')
12
11
 
13
12
  function getMeta (fn) {
@@ -71,20 +70,25 @@ function checkDecorators (fn) {
71
70
  const { decorators, name } = meta
72
71
  if (!decorators) return
73
72
 
74
- if (decorators.fastify) _checkDecorators.call(this, 'Fastify', decorators.fastify, name)
75
- if (decorators.reply) _checkDecorators.call(this[kReply], 'Reply', decorators.reply, name)
76
- if (decorators.request) _checkDecorators.call(this[kRequest], 'Request', decorators.request, name)
73
+ if (decorators.fastify) _checkDecorators(this, 'Fastify', decorators.fastify, name)
74
+ if (decorators.reply) _checkDecorators(this, 'Reply', decorators.reply, name)
75
+ if (decorators.request) _checkDecorators(this, 'Request', decorators.request, name)
77
76
  }
78
77
 
79
- function _checkDecorators (instance, decorators, name) {
78
+ const checks = {
79
+ Fastify: exist,
80
+ Request: existRequest,
81
+ Reply: existReply
82
+ }
83
+
84
+ function _checkDecorators (that, instance, decorators, name) {
80
85
  assert(Array.isArray(decorators), 'The decorators should be an array of strings')
81
86
 
82
87
  decorators.forEach(decorator => {
83
88
  const withPluginName = typeof name === 'string' ? ` required by '${name}'` : ''
84
- assert(
85
- instance === 'Fastify' ? decorator in this : decorator in this.prototype,
86
- `The decorator '${decorator}'${withPluginName} is not present in ${instance}`
87
- )
89
+ if (!checks[instance].call(that, decorator)) {
90
+ throw new Error(`The decorator '${decorator}'${withPluginName} is not present in ${instance}`)
91
+ }
88
92
  })
89
93
  }
90
94
 
package/lib/reply.js CHANGED
@@ -673,9 +673,12 @@ function buildReply (R) {
673
673
  this[kReplyStartTime] = undefined
674
674
  this.log = log
675
675
 
676
+ // eslint-disable-next-line no-var
677
+ var prop
676
678
  // eslint-disable-next-line no-var
677
679
  for (var i = 0; i < props.length; i++) {
678
- this[props[i]] = null
680
+ prop = props[i]
681
+ this[prop.key] = prop.value
679
682
  }
680
683
  }
681
684
  _Reply.prototype = new R()
package/lib/request.js CHANGED
@@ -54,9 +54,12 @@ function buildRegularRequest (R) {
54
54
  this.log = log
55
55
  this.body = null
56
56
 
57
+ // eslint-disable-next-line no-var
58
+ var prop
57
59
  // eslint-disable-next-line no-var
58
60
  for (var i = 0; i < props.length; i++) {
59
- this[props[i]] = null
61
+ prop = props[i]
62
+ this[prop.key] = prop.value
60
63
  }
61
64
  }
62
65
  _Request.prototype = new R()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.21.2",
3
+ "version": "3.21.6",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -17,6 +17,15 @@ test('server methods should exist', t => {
17
17
  t.ok(fastify.hasDecorator)
18
18
  })
19
19
 
20
+ test('should check if the given decoration already exist when null', t => {
21
+ t.plan(1)
22
+ const fastify = Fastify()
23
+ fastify.decorate('null', null)
24
+ fastify.ready(() => {
25
+ t.ok(fastify.hasDecorator('null'))
26
+ })
27
+ })
28
+
20
29
  test('server methods should be encapsulated via .register', t => {
21
30
  t.plan(2)
22
31
  const fastify = Fastify()
@@ -104,12 +113,11 @@ test('should pass error for missing request decorator', t => {
104
113
  })
105
114
 
106
115
  test('decorateReply inside register', t => {
107
- t.plan(12)
116
+ t.plan(11)
108
117
  const fastify = Fastify()
109
118
 
110
119
  fastify.register((instance, opts, done) => {
111
120
  instance.decorateReply('test', 'test')
112
- t.ok(instance[symbols.kReply].prototype.test)
113
121
 
114
122
  instance.get('/yes', (req, reply) => {
115
123
  t.ok(reply.test, 'test exists')
@@ -247,12 +255,11 @@ test('decorateReply as plugin (outside .after)', t => {
247
255
  })
248
256
 
249
257
  test('decorateRequest inside register', t => {
250
- t.plan(12)
258
+ t.plan(11)
251
259
  const fastify = Fastify()
252
260
 
253
261
  fastify.register((instance, opts, done) => {
254
262
  instance.decorateRequest('test', 'test')
255
- t.ok(instance[symbols.kRequest].prototype.test)
256
263
 
257
264
  instance.get('/yes', (req, reply) => {
258
265
  t.ok(req.test, 'test exists')
@@ -425,6 +432,15 @@ test('hasRequestDecorator', t => {
425
432
  t.ok(fastify.hasRequestDecorator(requestDecoratorName))
426
433
  })
427
434
 
435
+ t.test('should check if the given request decoration already exist when null', t => {
436
+ t.plan(2)
437
+ const fastify = Fastify()
438
+
439
+ t.notOk(fastify.hasRequestDecorator(requestDecoratorName))
440
+ fastify.decorateRequest(requestDecoratorName, null)
441
+ t.ok(fastify.hasRequestDecorator(requestDecoratorName))
442
+ })
443
+
428
444
  t.test('should be plugin encapsulable', t => {
429
445
  t.plan(4)
430
446
  const fastify = Fastify()
@@ -481,6 +497,15 @@ test('hasReplyDecorator', t => {
481
497
  t.ok(fastify.hasReplyDecorator(replyDecoratorName))
482
498
  })
483
499
 
500
+ t.test('should check if the given reply decoration already exist when null', t => {
501
+ t.plan(2)
502
+ const fastify = Fastify()
503
+
504
+ t.notOk(fastify.hasReplyDecorator(replyDecoratorName))
505
+ fastify.decorateReply(replyDecoratorName, null)
506
+ t.ok(fastify.hasReplyDecorator(replyDecoratorName))
507
+ })
508
+
484
509
  t.test('should be plugin encapsulable', t => {
485
510
  t.plan(4)
486
511
  const fastify = Fastify()
@@ -877,3 +902,125 @@ test('Request/reply decorators should be able to access the server instance', as
877
902
  t.equal(this.server.foo, 'bar')
878
903
  }
879
904
  })
905
+
906
+ test('plugin required decorators', async t => {
907
+ const plugin1 = fp(
908
+ async (instance) => {
909
+ instance.decorateRequest('someThing', null)
910
+
911
+ instance.addHook('onRequest', async (request, reply) => {
912
+ request.someThing = 'hello'
913
+ })
914
+ },
915
+ {
916
+ name: 'custom-plugin-one',
917
+ fastify: '3.x'
918
+ }
919
+ )
920
+
921
+ const plugin2 = fp(
922
+ async () => {
923
+ // nothing
924
+ },
925
+ {
926
+ name: 'custom-plugin-two',
927
+ fastify: '3.x',
928
+ dependencies: ['custom-plugin-one'],
929
+ decorators: {
930
+ request: ['someThing']
931
+ }
932
+ }
933
+ )
934
+
935
+ const app = Fastify()
936
+ app.register(plugin1)
937
+ app.register(plugin2)
938
+ await app.ready()
939
+ })
940
+
941
+ test('decorateRequest/decorateReply empty string', t => {
942
+ t.plan(7)
943
+ const fastify = Fastify()
944
+
945
+ fastify.decorateRequest('test', '')
946
+ fastify.decorateReply('test2', '')
947
+ fastify.get('/yes', (req, reply) => {
948
+ t.equal(req.test, '')
949
+ t.equal(reply.test2, '')
950
+ reply.send({ hello: 'world' })
951
+ })
952
+ t.teardown(fastify.close.bind(fastify))
953
+
954
+ fastify.listen(0, err => {
955
+ t.error(err)
956
+ fastify.server.unref()
957
+
958
+ sget({
959
+ method: 'GET',
960
+ url: 'http://localhost:' + fastify.server.address().port + '/yes'
961
+ }, (err, response, body) => {
962
+ t.error(err)
963
+ t.equal(response.statusCode, 200)
964
+ t.equal(response.headers['content-length'], '' + body.length)
965
+ t.same(JSON.parse(body), { hello: 'world' })
966
+ })
967
+ })
968
+ })
969
+
970
+ test('decorateRequest/decorateReply is undefined', t => {
971
+ t.plan(7)
972
+ const fastify = Fastify()
973
+
974
+ fastify.decorateRequest('test', undefined)
975
+ fastify.decorateReply('test2', undefined)
976
+ fastify.get('/yes', (req, reply) => {
977
+ t.equal(req.test, undefined)
978
+ t.equal(reply.test2, undefined)
979
+ reply.send({ hello: 'world' })
980
+ })
981
+ t.teardown(fastify.close.bind(fastify))
982
+
983
+ fastify.listen(0, err => {
984
+ t.error(err)
985
+ fastify.server.unref()
986
+
987
+ sget({
988
+ method: 'GET',
989
+ url: 'http://localhost:' + fastify.server.address().port + '/yes'
990
+ }, (err, response, body) => {
991
+ t.error(err)
992
+ t.equal(response.statusCode, 200)
993
+ t.equal(response.headers['content-length'], '' + body.length)
994
+ t.same(JSON.parse(body), { hello: 'world' })
995
+ })
996
+ })
997
+ })
998
+
999
+ test('decorateRequest/decorateReply is not set to a value', t => {
1000
+ t.plan(7)
1001
+ const fastify = Fastify()
1002
+
1003
+ fastify.decorateRequest('test')
1004
+ fastify.decorateReply('test2')
1005
+ fastify.get('/yes', (req, reply) => {
1006
+ t.equal(req.test, undefined)
1007
+ t.equal(reply.test2, undefined)
1008
+ reply.send({ hello: 'world' })
1009
+ })
1010
+ t.teardown(fastify.close.bind(fastify))
1011
+
1012
+ fastify.listen(0, err => {
1013
+ t.error(err)
1014
+ fastify.server.unref()
1015
+
1016
+ sget({
1017
+ method: 'GET',
1018
+ url: 'http://localhost:' + fastify.server.address().port + '/yes'
1019
+ }, (err, response, body) => {
1020
+ t.error(err)
1021
+ t.equal(response.statusCode, 200)
1022
+ t.equal(response.headers['content-length'], '' + body.length)
1023
+ t.same(JSON.parse(body), { hello: 'world' })
1024
+ })
1025
+ })
1026
+ })
@@ -53,8 +53,8 @@ test('checkDecorators should check if the given decorator is present in the inst
53
53
 
54
54
  function context () {}
55
55
  context.plugin = true
56
- context[symbols.kReply] = { prototype: { plugin: true } }
57
- context[symbols.kRequest] = { prototype: { plugin: true } }
56
+ context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
57
+ context[symbols.kRequest] = { prototype: { plugin: true }, props: [] }
58
58
 
59
59
  try {
60
60
  pluginUtils.checkDecorators.call(context, fn)
@@ -79,8 +79,8 @@ test('checkDecorators should check if the given decorator is present in the inst
79
79
 
80
80
  function context () {}
81
81
  context.plugin = true
82
- context[symbols.kReply] = { prototype: { plugin: true } }
83
- context[symbols.kRequest] = { prototype: {} }
82
+ context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
83
+ context[symbols.kRequest] = { prototype: {}, props: [] }
84
84
 
85
85
  try {
86
86
  pluginUtils.checkDecorators.call(context, fn)
@@ -33,6 +33,36 @@ test('same shape on Request', async (t) => {
33
33
  await app.inject('/')
34
34
  })
35
35
 
36
+ test('same shape on Request when object', async (t) => {
37
+ t.plan(1)
38
+
39
+ const app = fastify()
40
+
41
+ let request
42
+
43
+ app.decorateRequest('object', null)
44
+
45
+ app.addHook('preHandler', (req, reply, done) => {
46
+ if (request) {
47
+ req.object = {}
48
+ }
49
+ done()
50
+ })
51
+
52
+ app.get('/', (req, reply) => {
53
+ if (request) {
54
+ t.equal(%HaveSameMap(request, req), true)
55
+ }
56
+
57
+ request = req
58
+
59
+ return 'hello world'
60
+ })
61
+
62
+ await app.inject('/')
63
+ await app.inject('/')
64
+ })
65
+
36
66
  test('same shape on Reply', async (t) => {
37
67
  t.plan(1)
38
68
 
@@ -62,3 +92,33 @@ test('same shape on Reply', async (t) => {
62
92
  await app.inject('/')
63
93
  await app.inject('/')
64
94
  })
95
+
96
+ test('same shape on Reply when object', async (t) => {
97
+ t.plan(1)
98
+
99
+ const app = fastify()
100
+
101
+ let _reply
102
+
103
+ app.decorateReply('object', null)
104
+
105
+ app.addHook('preHandler', (req, reply, done) => {
106
+ if (_reply) {
107
+ reply.object = {}
108
+ }
109
+ done()
110
+ })
111
+
112
+ app.get('/', (req, reply) => {
113
+ if (_reply) {
114
+ t.equal(%HaveSameMap(_reply, reply), true)
115
+ }
116
+
117
+ _reply = reply
118
+
119
+ return 'hello world'
120
+ })
121
+
122
+ await app.inject('/')
123
+ await app.inject('/')
124
+ })