fastify 3.24.0 → 3.24.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/docs/Ecosystem.md CHANGED
@@ -91,6 +91,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
91
91
  - [`fastify-cloudevents`](https://github.com/smartiniOnGitHub/fastify-cloudevents) Fastify plugin to generate and forward Fastify events in the Cloudevents format.
92
92
  - [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb) Fastify plugin to connect to a CockroachDB PostgreSQL instance via the Sequelize ORM.
93
93
  - [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify plugin to add CouchDB support via [nano](https://github.com/apache/nano).
94
+ - [`fastify-crud-generator`](https://github.com/heply/fastify-crud-generator) A plugin to rapidly generate CRUD routes for any entity.
94
95
  - [`fastify-custom-healthcheck`](https://github.com/gkampitakis/fastify-custom-healthcheck) Fastify plugin to add health route in your server that asserts custom functions.
95
96
  - [`fastify-decorators`](https://github.com/L2jLiga/fastify-decorators) Fastify plugin that provides the set of TypeScript decorators.
96
97
  - [`fastify-disablecache`](https://github.com/Fdawgs/fastify-disablecache) Fastify plugin to disable client-side caching, inspired by [nocache](https://github.com/helmetjs/nocache).
@@ -158,6 +159,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
158
159
  - [`fastify-orientdb`](https://github.com/mahmed8003/fastify-orientdb) Fastify OrientDB connection plugin, with which you can share the OrientDB connection across every part of your server.
159
160
  - [`fastify-piscina`](https://github.com/piscinajs/fastify-piscina) A worker thread pool plugin using [Piscina](https://github.com/piscinajs/piscina).
160
161
  - [`fastify-peekaboo`](https://github.com/simone-sanfratello/fastify-peekaboo) Fastify plugin for memoize responses by expressive settings.
162
+ - [`fastify-polyglot`](https://github.com/heply/fastify-polyglot) A plugin to handle i18n using [node-polyglot](https://www.npmjs.com/package/node-polyglot).
161
163
  - [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile) Plugin to integrate [PostGraphile](https://www.graphile.org/postgraphile/) in a Fastify project.
162
164
  - [`fastify-prettier`](https://github.com/hsynlms/fastify-prettier) A Fastify plugin that uses [prettier](https://github.com/prettier/prettier) under the hood to beautify outgoing responses and/or other things in the Fastify server.
163
165
  - [`fastify-print-routes`](https://github.com/ShogunPanda/fastify-print-routes) A Fastify plugin that prints all available routes.
@@ -262,6 +262,24 @@ async function routes (fastify, options) {
262
262
  }
263
263
  return result
264
264
  })
265
+
266
+ const animalBodyJsonSchema = {
267
+ type: 'object',
268
+ required: ['animal'],
269
+ properties: {
270
+ animal: { type: 'string' },
271
+ },
272
+ }
273
+
274
+ const schema = {
275
+ body: animalBodyJsonSchema,
276
+ }
277
+
278
+ fastify.post('/animals', { schema }, async (request, reply) => {
279
+ // we can use the `request.body` object to get the data sent by the client
280
+ const result = await collection.insertOne({ animal: request.body.animal })
281
+ return result
282
+ })
265
283
  }
266
284
 
267
285
  module.exports = routes
package/docs/Logging.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  ## Logging
4
4
 
5
+ ### Enable logging
5
6
  Logging is disabled by default, and you can enable it by passing
6
7
  `{ logger: true }` or `{ logger: { level: 'info' } }` when you create
7
8
  a fastify instance. Note that if the logger is disabled, it is impossible to
@@ -11,13 +12,34 @@ this purpose.
11
12
 
12
13
  As Fastify is focused on performance, it uses [pino](https://github.com/pinojs/pino) as its logger, with the default log level, when enabled, set to `'info'`.
13
14
 
14
- Enabling the logger is extremely easy:
15
+ Enabling the production JSON logger:
15
16
 
16
17
  ```js
17
18
  const fastify = require('fastify')({
18
19
  logger: true
19
20
  })
21
+ ```
22
+
23
+ Enabling the logger with appropriate configuration for both local development and production environment requires bit more configuration:
24
+ ```js
25
+ const fastify = require('fastify')({
26
+ logger: {
27
+ prettyPrint:
28
+ environment === 'development'
29
+ ? {
30
+ translateTime: 'HH:MM:ss Z',
31
+ ignore: 'pid,hostname'
32
+ }
33
+ : false
34
+ }
35
+ })
36
+ ```
37
+ ⚠️ `pino-pretty` needs to be installed as a dev dependency, it is not included by default for performance reasons.
20
38
 
39
+ ### Usage
40
+ You can use the logger like this in your route handlers:
41
+
42
+ ```js
21
43
  fastify.get('/', options, function (request, reply) {
22
44
  request.log.info('Some info about the current request')
23
45
  reply.send({ hello: 'world' })
package/docs/Plugins.md CHANGED
@@ -4,7 +4,7 @@
4
4
  Fastify allows the user to extend its functionalities with plugins.
5
5
  A plugin can be a set of routes, a server [decorator](Decorators.md), or whatever. The API that you will need to use one or more plugins, is `register`.<br>
6
6
 
7
- By default, `register` creates a *new scope*, this means that if you make some changes to the Fastify instance (via `decorate`), this change will not be reflected by the current context ancestors, but only to its sons. This feature allows us to achieve plugin *encapsulation* and *inheritance*, in this way we create a *direct acyclic graph* (DAG) and we will not have issues caused by cross dependencies.
7
+ By default, `register` creates a *new scope*, this means that if you make some changes to the Fastify instance (via `decorate`), this change will not be reflected by the current context ancestors, but only to its descendants. This feature allows us to achieve plugin *encapsulation* and *inheritance*, in this way we create a *direct acyclic graph* (DAG) and we will not have issues caused by cross dependencies.
8
8
 
9
9
  You already see in the [getting started](Getting-Started.md#register) section how using this API is pretty straightforward.
10
10
  ```
package/docs/Reply.md CHANGED
@@ -7,6 +7,7 @@
7
7
  - [.statusCode](#statusCode)
8
8
  - [.server](#server)
9
9
  - [.header(key, value)](#headerkey-value)
10
+ - [set-cookie](#set-cookie)
10
11
  - [.headers(object)](#headersobject)
11
12
  - [.getHeader(key)](#getheaderkey)
12
13
  - [.getHeaders()](#getheaders)
@@ -106,11 +107,23 @@ fastify.get('/', async function (req, rep) {
106
107
 
107
108
  <a name="header"></a>
108
109
  ### .header(key, value)
109
- Sets a response header. If the value is omitted or undefined, it is coerced
110
- to `''`.
111
-
110
+ Sets a response header. If the value is omitted or undefined, it is coerced to `''`.
112
111
  For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_response_setheader_name_value).
113
112
 
113
+ <a name="set-cookie"></a>
114
+ - ### set-cookie
115
+ - When sending different values as a cookie with `set-cookie` as the key, every value will be sent as a cookie instead of replacing the previous value.
116
+
117
+ ```js
118
+ reply.header('set-cookie', 'foo');
119
+ reply.header('set-cookie', 'bar');
120
+ ```
121
+ - The browser will only consider the latest reference of a key for the `set-cookie` header. This is done to avoid parsing the `set-cookie` header when added to a reply and speeds up the serialization of the reply.
122
+
123
+ - To reset the `set-cookie` header, you need to make an explicit call to `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)` [here](#removeheaderkey).
124
+
125
+
126
+
114
127
  <a name="headers"></a>
115
128
  ### .headers(object)
116
129
  Sets all the keys of the object as response headers. [`.header`](#headerkey-value) will be called under the hood.
@@ -22,6 +22,7 @@ choice with an additional snippet of code.
22
22
  ### Contents
23
23
 
24
24
  - [AWS Lambda](#aws-lambda)
25
+ - [Google Cloud Functions](#google-cloud-functions)
25
26
  - [Google Cloud Run](#google-cloud-run)
26
27
  - [Netlify Lambda](#netlify-lambda)
27
28
  - [Vercel](#vercel)
@@ -100,6 +101,128 @@ An example deployable with [claudia.js](https://claudiajs.com/tutorials/serverle
100
101
  - API Gateway does not support streams yet, so you are not able to handle [streams](https://www.fastify.io/docs/latest/Reply/#streams).
101
102
  - API Gateway has a timeout of 29 seconds, so it is important to provide a reply during this time.
102
103
 
104
+ ## Google Cloud Functions
105
+
106
+ ### Creation of Fastify instance
107
+ ```js
108
+ const fastify = require("fastify")({
109
+ logger: true // you can also define the level passing an object configuration to logger: {level: 'debug'}
110
+ });
111
+ ```
112
+
113
+ ### Add Custom `contentTypeParser` to Fastify instance
114
+
115
+ As explained [in issue #946](https://github.com/fastify/fastify/issues/946#issuecomment-766319521), since the Google Cloud Functions platform parses the body of the request before it arrives into Fastify instance, troubling the body request in case of `POST` and `PATCH` methods, you need to add a custom [`ContentTypeParser`](https://www.fastify.io/docs/latest/ContentTypeParser/) to mitigate this behavior.
116
+
117
+ ```js
118
+ fastify.addContentTypeParser('application/json', {}, (req, body, done) => {
119
+ done(null, body.body);
120
+ });
121
+ ```
122
+
123
+ ### Define your endpoint (examples)
124
+
125
+ A simple `GET` endpoint:
126
+ ```js
127
+ fastify.get('/', async (request, reply) => {
128
+ reply.send({message: 'Hello World!'})
129
+ })
130
+ ```
131
+
132
+ Or a more complete `POST` endpoint with schema validation:
133
+ ```js
134
+ fastify.route({
135
+ method: 'POST',
136
+ url: '/hello',
137
+ schema: {
138
+ body: {
139
+ type: 'object',
140
+ properties: {
141
+ name: { type: 'string'}
142
+ },
143
+ required: ['name']
144
+ },
145
+ response: {
146
+ 200: {
147
+ type: 'object',
148
+ properties: {
149
+ message: {type: 'string'}
150
+ }
151
+ }
152
+ },
153
+ },
154
+ handler: async (request, reply) => {
155
+ const { name } = request.body;
156
+ reply.code(200).send({
157
+ message: `Hello ${name}!`
158
+ })
159
+ }
160
+ })
161
+ ```
162
+
163
+ ### Implement and export the function
164
+
165
+ Final step, implement the function to handle the request and pass it to Fastify by emitting `request` event to `fastify.server`:
166
+
167
+ ```js
168
+ const fastifyFunction = async (request, reply) => {
169
+ await fastify.ready();
170
+ fastify.server.emit('request', request, reply)
171
+ }
172
+
173
+ export.fastifyFunction = fastifyFunction;
174
+ ```
175
+
176
+ ### Local test
177
+
178
+ Install [Google Functions Framework for Node.js](https://github.com/GoogleCloudPlatform/functions-framework-nodejs).
179
+
180
+ You can install it globally:
181
+ ```bash
182
+ npm i -g @google-cloud/functions-framework
183
+ ```
184
+
185
+ Or as a development library:
186
+ ```bash
187
+ npm i --save-dev @google-cloud/functions-framework
188
+ ```
189
+
190
+ Than you can run your function locally with Functions Framework:
191
+ ``` bash
192
+ npx @google-cloud/functions-framework --target=fastifyFunction
193
+ ```
194
+
195
+ Or add this command to your `package.json` scripts:
196
+ ```json
197
+ "scripts": {
198
+ ...
199
+ "dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
200
+ ...
201
+ }
202
+ ```
203
+ and run it with `npm run dev`.
204
+
205
+
206
+ ### Deploy
207
+ ```bash
208
+ gcloud functions deploy fastifyFunction \
209
+ --runtime nodejs14 --trigger-http --region $GOOGLE_REGION --allow-unauthenticated
210
+ ```
211
+
212
+ #### Read logs
213
+ ```bash
214
+ gcloud functions logs read
215
+ ```
216
+
217
+ #### Example request to `/hello` endpoint
218
+ ```bash
219
+ curl -X POST https://$GOOGLE_REGION-$GOOGLE_PROJECT.cloudfunctions.net/me -H "Content-Type: application/json" -d '{ "name": "Fastify" }'
220
+ {"message":"Hello Fastify!"}
221
+ ```
222
+
223
+ ### References
224
+ - [Google Cloud Functions - Node.js Quickstart ](https://cloud.google.com/functions/docs/quickstart-nodejs)
225
+
103
226
  ## Google Cloud Run
104
227
 
105
228
  Unlike AWS Lambda or Google Cloud Functions, Google Cloud Run is a serverless **container** environment. Its primary purpose is to provide an infrastructure-abstracted environment to run arbitrary containers. As a result, Fastify can be deployed to Google Cloud Run with little-to-no code changes from the way you would write your Fastify app normally.
@@ -549,7 +549,7 @@ fastify.post('/the/url', { schema }, handler)
549
549
  <a name="schema-serializer"></a>
550
550
  #### Serializer Compiler
551
551
 
552
- The `serializerCompiler` is a function that returns a function that must return a string from an input object. You must provide a function to serialize every route where you have defined a `response` JSON Schema.
552
+ The `serializerCompiler` is a function that returns a function that must return a string from an input object. When you define a response JSON Schema, you can change the default serialization method by providing a function to serialize every route where you do.
553
553
 
554
554
  ```js
555
555
  fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {
@@ -73,6 +73,6 @@ server.get<{
73
73
  server.listen(8080, (err, address) => {
74
74
  if (err) {
75
75
  console.error(err);
76
- process.exit(0);
76
+ process.exit(1);
77
77
  }
78
78
  });
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '3.24.0'
3
+ const VERSION = '3.24.1'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -631,8 +631,7 @@ function fastify (options) {
631
631
  function setSchemaController (schemaControllerOpts) {
632
632
  throwIfAlreadyStarted('Cannot call "setSchemaController" when fastify instance is already started!')
633
633
  const old = this[kSchemaController]
634
- const parent = old.parent || old
635
- const schemaController = SchemaController.buildSchemaController(parent, Object.assign({}, old.opts, schemaControllerOpts))
634
+ const schemaController = SchemaController.buildSchemaController(old, Object.assign({}, old.opts, schemaControllerOpts))
636
635
  this[kSchemaController] = schemaController
637
636
  this.getSchema = schemaController.getSchema.bind(schemaController)
638
637
  this.getSchemas = schemaController.getSchemas.bind(schemaController)
package/lib/logger.js CHANGED
@@ -50,7 +50,7 @@ const serializers = {
50
50
  return {
51
51
  method: req.method,
52
52
  url: req.url,
53
- version: req.headers['accept-version'],
53
+ version: req.headers && req.headers['accept-version'],
54
54
  hostname: req.hostname,
55
55
  remoteAddress: req.ip,
56
56
  remotePort: req.socket ? req.socket.remotePort : undefined
package/lib/server.js CHANGED
@@ -14,19 +14,20 @@ function createServer (options, httpHandler) {
14
14
  let server = null
15
15
  if (options.serverFactory) {
16
16
  server = options.serverFactory(httpHandler, options)
17
- } else if (options.https) {
18
- if (options.http2) {
17
+ } else if (options.http2) {
18
+ if (options.https) {
19
19
  server = http2().createSecureServer(options.https, httpHandler)
20
- server.on('session', sessionTimeout(options.http2SessionTimeout))
21
20
  } else {
22
- server = https.createServer(options.https, httpHandler)
23
- server.keepAliveTimeout = options.keepAliveTimeout
21
+ server = http2().createServer(httpHandler)
24
22
  }
25
- } else if (options.http2) {
26
- server = http2().createServer(httpHandler)
27
23
  server.on('session', sessionTimeout(options.http2SessionTimeout))
28
24
  } else {
29
- server = http.createServer(httpHandler)
25
+ // this is http1
26
+ if (options.https) {
27
+ server = https.createServer(options.https, httpHandler)
28
+ } else {
29
+ server = http.createServer(httpHandler)
30
+ }
30
31
  server.keepAliveTimeout = options.keepAliveTimeout
31
32
  server.requestTimeout = options.requestTimeout
32
33
  // we treat zero as null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.24.0",
3
+ "version": "3.24.1",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -166,7 +166,7 @@
166
166
  "tap": "^15.0.5",
167
167
  "tap-mocha-reporter": "^5.0.1",
168
168
  "then-sleep": "^1.0.1",
169
- "tsd": "^0.18.0",
169
+ "tsd": "^0.19.0",
170
170
  "typescript": "^4.0.2",
171
171
  "undici": "^3.3.5",
172
172
  "x-xss-protection": "^2.0.0",
@@ -1516,3 +1516,19 @@ test('should create a default logger if provided one is invalid', t => {
1516
1516
 
1517
1517
  t.pass()
1518
1518
  })
1519
+
1520
+ test('should not throw error when serializing custom req', t => {
1521
+ t.plan(1)
1522
+
1523
+ const lines = []
1524
+ const dest = new stream.Writable({
1525
+ write: function (chunk, enc, cb) {
1526
+ lines.push(JSON.parse(chunk))
1527
+ cb()
1528
+ }
1529
+ })
1530
+ const fastify = Fastify({ logger: { level: 'info', stream: dest } })
1531
+ fastify.log.info({ req: {} })
1532
+
1533
+ t.same(lines[0].req, {})
1534
+ })
@@ -102,3 +102,13 @@ test('maxRequestsPerSocket should 0', async (t) => {
102
102
  const initialConfig = Fastify().initialConfig
103
103
  t.same(initialConfig.maxRequestsPerSocket, 0)
104
104
  })
105
+
106
+ test('requestTimeout passed to server', t => {
107
+ t.plan(2)
108
+
109
+ const httpServer = Fastify({ maxRequestsPerSocket: 5 }).server
110
+ t.equal(httpServer.maxRequestsPerSocket, 5)
111
+
112
+ const httpsServer = Fastify({ maxRequestsPerSocket: 5, https: true }).server
113
+ t.equal(httpsServer.maxRequestsPerSocket, 5)
114
+ })
@@ -5,7 +5,7 @@ const { test } = require('tap')
5
5
  const Fastify = require('../fastify')
6
6
 
7
7
  test('requestTimeout passed to server', t => {
8
- t.plan(4)
8
+ t.plan(5)
9
9
 
10
10
  try {
11
11
  Fastify({ requestTimeout: 500.1 })
@@ -24,6 +24,9 @@ test('requestTimeout passed to server', t => {
24
24
  const httpServer = Fastify({ requestTimeout: 1000 }).server
25
25
  t.equal(httpServer.requestTimeout, 1000)
26
26
 
27
+ const httpsServer = Fastify({ requestTimeout: 1000, https: true }).server
28
+ t.equal(httpsServer.requestTimeout, 1000)
29
+
27
30
  const serverFactory = (handler, _) => {
28
31
  const server = http.createServer((req, res) => {
29
32
  handler(req, res)
@@ -1604,3 +1604,149 @@ test('setSchemaController: Inherits buildValidator from parent if not present wi
1604
1604
  t.equal(childSerializerCalled, 1, 'Should be called from the child')
1605
1605
  t.equal(res.statusCode, 400, 'Should not coearce the string into array')
1606
1606
  })
1607
+
1608
+ test('Should throw if not default validator passed', async t => {
1609
+ t.plan(4)
1610
+ const customAjv = new Ajv({ coerceTypes: false })
1611
+ const someSchema = {
1612
+ $id: 'some',
1613
+ type: 'array',
1614
+ items: {
1615
+ type: 'string'
1616
+ }
1617
+ }
1618
+ const anotherSchema = {
1619
+ $id: 'another',
1620
+ type: 'integer'
1621
+ }
1622
+ const plugin = fp(function (pluginInstance, _, pluginDone) {
1623
+ pluginInstance.setSchemaController({
1624
+ compilersFactory: {
1625
+ buildValidator: function (externalSchemas) {
1626
+ const schemaKeys = Object.keys(externalSchemas)
1627
+ t.equal(schemaKeys.length, 2)
1628
+ t.same(schemaKeys, ['some', 'another'])
1629
+
1630
+ for (const key of schemaKeys) {
1631
+ if (customAjv.getSchema(key) == null) {
1632
+ customAjv.addSchema(externalSchemas[key], key)
1633
+ }
1634
+ }
1635
+ return function validatorCompiler ({ schema }) {
1636
+ return customAjv.compile(schema)
1637
+ }
1638
+ }
1639
+ }
1640
+ })
1641
+
1642
+ pluginDone()
1643
+ })
1644
+ const server = Fastify()
1645
+
1646
+ server.addSchema(someSchema)
1647
+
1648
+ server.register((instance, opts, done) => {
1649
+ instance.addSchema(anotherSchema)
1650
+
1651
+ instance.register(plugin, {})
1652
+
1653
+ instance.post(
1654
+ '/',
1655
+ {
1656
+ schema: {
1657
+ query: {
1658
+ msg: {
1659
+ $ref: 'some#'
1660
+ }
1661
+ },
1662
+ headers: {
1663
+ 'x-another': {
1664
+ $ref: 'another#'
1665
+ }
1666
+ }
1667
+ }
1668
+ },
1669
+ (req, reply) => {
1670
+ reply.send({ noop: 'noop' })
1671
+ }
1672
+ )
1673
+
1674
+ done()
1675
+ })
1676
+
1677
+ try {
1678
+ const res = await server.inject({
1679
+ method: 'POST',
1680
+ url: '/',
1681
+ query: {
1682
+ msg: ['string']
1683
+ }
1684
+ })
1685
+
1686
+ t.equal(res.json().message, 'querystring.msg should be array')
1687
+ t.equal(res.statusCode, 400, 'Should not coearce the string into array')
1688
+ } catch (err) {
1689
+ t.error(err)
1690
+ }
1691
+ })
1692
+
1693
+ test('Should throw if not default validator passed', async t => {
1694
+ t.plan(2)
1695
+ const someSchema = {
1696
+ $id: 'some',
1697
+ type: 'array',
1698
+ items: {
1699
+ type: 'string'
1700
+ }
1701
+ }
1702
+ const anotherSchema = {
1703
+ $id: 'another',
1704
+ type: 'integer'
1705
+ }
1706
+
1707
+ const server = Fastify()
1708
+
1709
+ server.addSchema(someSchema)
1710
+
1711
+ server.register((instance, opts, done) => {
1712
+ instance.addSchema(anotherSchema)
1713
+
1714
+ instance.post(
1715
+ '/',
1716
+ {
1717
+ schema: {
1718
+ query: {
1719
+ msg: {
1720
+ $ref: 'some#'
1721
+ }
1722
+ },
1723
+ headers: {
1724
+ 'x-another': {
1725
+ $ref: 'another#'
1726
+ }
1727
+ }
1728
+ }
1729
+ },
1730
+ (req, reply) => {
1731
+ reply.send({ noop: 'noop' })
1732
+ }
1733
+ )
1734
+
1735
+ done()
1736
+ })
1737
+
1738
+ try {
1739
+ const res = await server.inject({
1740
+ method: 'POST',
1741
+ url: '/',
1742
+ query: {
1743
+ msg: ['string']
1744
+ }
1745
+ })
1746
+
1747
+ t.equal(res.json().message, 'querystring.msg should be array')
1748
+ t.equal(res.statusCode, 400, 'Should not coearce the string into array')
1749
+ } catch (err) {
1750
+ t.error(err)
1751
+ }
1752
+ })
@@ -90,6 +90,12 @@ expectAssignable<void>(server.listen('3000', '', (err, address) => {}))
90
90
  expectAssignable<void>(server.listen(3000, (err, address) => {}))
91
91
  expectAssignable<void>(server.listen('3000', (err, address) => {}))
92
92
 
93
+ // test listen method callback types
94
+ expectAssignable<void>(server.listen('3000', (err, address) => {
95
+ expectAssignable<Error|null>(err)
96
+ expectAssignable<string>(address)
97
+ }))
98
+
93
99
  // test listen method promise
94
100
  expectAssignable<PromiseLike<string>>(server.listen(3000))
95
101
  expectAssignable<PromiseLike<string>>(server.listen('3000'))
@@ -1,5 +1,5 @@
1
1
  import { expectType } from 'tsd'
2
- import fastify, { RouteHandler, RawRequestDefaultExpression, RequestBodyDefault, RequestGenericInterface } from '../../fastify'
2
+ import fastify, { RouteHandler, RawRequestDefaultExpression, RequestBodyDefault, RequestGenericInterface, FastifyContext, ContextConfigDefault, FastifyContextConfig } from '../../fastify'
3
3
  import { RequestParamsDefault, RequestHeadersDefault, RequestQuerystringDefault } from '../../types/utils'
4
4
  import { FastifyLoggerInstance } from '../../types/logger'
5
5
  import { FastifyRequest } from '../../types/request'
@@ -50,6 +50,8 @@ const getHandler: RouteHandler = function (request, _reply) {
50
50
  expectType<RawRequestDefaultExpression>(request.raw)
51
51
  expectType<RequestBodyDefault>(request.body)
52
52
  expectType<RequestParamsDefault>(request.params)
53
+ expectType<FastifyContext<ContextConfigDefault>>(request.context)
54
+ expectType<FastifyContextConfig>(request.context.config)
53
55
 
54
56
  expectType<RequestHeadersDefault & RawRequestDefaultExpression['headers']>(request.headers)
55
57
  request.headers = {}
@@ -72,6 +74,8 @@ const postHandler: Handler = function (request) {
72
74
  expectType<number>(request.params.id)
73
75
  expectType<string>(request.headers['x-foobar'])
74
76
  expectType<FastifyInstance>(request.server)
77
+ expectType<FastifyContext<ContextConfigDefault>>(request.context)
78
+ expectType<FastifyContextConfig>(request.context.config)
75
79
  }
76
80
 
77
81
  function putHandler (request: CustomRequest, reply: FastifyReply) {
@@ -84,6 +88,8 @@ function putHandler (request: CustomRequest, reply: FastifyReply) {
84
88
  expectType<number>(request.params.id)
85
89
  expectType<string>(request.headers['x-foobar'])
86
90
  expectType<FastifyInstance>(request.server)
91
+ expectType<FastifyContext<ContextConfigDefault>>(request.context)
92
+ expectType<FastifyContextConfig>(request.context.config)
87
93
  }
88
94
 
89
95
  const server = fastify()
@@ -65,6 +65,9 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
65
65
  expectType<QuerystringInterface>(req.query)
66
66
  expectType<ParamsInterface>(req.params)
67
67
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
68
+ expectType<string>(req.context.config.foo)
69
+ expectType<number>(req.context.config.bar)
70
+ expectType<boolean>(req.context.config.extra)
68
71
  expectType<string>(res.context.config.foo)
69
72
  expectType<number>(res.context.config.bar)
70
73
  expectType<boolean>(res.context.config.extra)
@@ -80,6 +83,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
80
83
  expectType<QuerystringInterface>(req.query)
81
84
  expectType<ParamsInterface>(req.params)
82
85
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
86
+ expectType<string>(req.context.config.foo)
87
+ expectType<number>(req.context.config.bar)
83
88
  expectType<string>(res.context.config.foo)
84
89
  expectType<number>(res.context.config.bar)
85
90
  },
@@ -88,6 +93,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
88
93
  expectType<QuerystringInterface>(req.query)
89
94
  expectType<ParamsInterface>(req.params)
90
95
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
96
+ expectType<string>(req.context.config.foo)
97
+ expectType<number>(req.context.config.bar)
91
98
  expectType<string>(res.context.config.foo)
92
99
  expectType<number>(res.context.config.bar)
93
100
  expectType<RequestPayload>(payload)
@@ -99,6 +106,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
99
106
  expectType<QuerystringInterface>(req.query)
100
107
  expectType<ParamsInterface>(req.params)
101
108
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
109
+ expectType<string>(req.context.config.foo)
110
+ expectType<number>(req.context.config.bar)
102
111
  expectType<string>(res.context.config.foo)
103
112
  expectType<number>(res.context.config.bar)
104
113
  },
@@ -107,6 +116,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
107
116
  expectType<QuerystringInterface>(req.query)
108
117
  expectType<ParamsInterface>(req.params)
109
118
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
119
+ expectType<string>(req.context.config.foo)
120
+ expectType<number>(req.context.config.bar)
110
121
  expectType<string>(res.context.config.foo)
111
122
  expectType<number>(res.context.config.bar)
112
123
  },
@@ -115,6 +126,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
115
126
  expectType<QuerystringInterface>(req.query)
116
127
  expectType<ParamsInterface>(req.params)
117
128
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
129
+ expectType<string>(req.context.config.foo)
130
+ expectType<number>(req.context.config.bar)
118
131
  expectType<string>(res.context.config.foo)
119
132
  expectType<number>(res.context.config.bar)
120
133
  expectType<number>(res.statusCode)
@@ -124,6 +137,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
124
137
  expectType<QuerystringInterface>(req.query)
125
138
  expectType<ParamsInterface>(req.params)
126
139
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
140
+ expectType<string>(req.context.config.foo)
141
+ expectType<number>(req.context.config.bar)
127
142
  expectType<string>(res.context.config.foo)
128
143
  expectType<number>(res.context.config.bar)
129
144
  },
@@ -132,6 +147,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
132
147
  expectType<QuerystringInterface>(req.query)
133
148
  expectType<ParamsInterface>(req.params)
134
149
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
150
+ expectType<string>(req.context.config.foo)
151
+ expectType<number>(req.context.config.bar)
135
152
  expectType<string>(res.context.config.foo)
136
153
  expectType<number>(res.context.config.bar)
137
154
  },
@@ -140,6 +157,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
140
157
  expectType<QuerystringInterface>(req.query)
141
158
  expectType<ParamsInterface>(req.params)
142
159
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
160
+ expectType<string>(req.context.config.foo)
161
+ expectType<number>(req.context.config.bar)
143
162
  expectType<string>(res.context.config.foo)
144
163
  expectType<number>(res.context.config.bar)
145
164
  },
@@ -148,6 +167,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
148
167
  expectType<QuerystringInterface>(req.query)
149
168
  expectType<ParamsInterface>(req.params)
150
169
  expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
170
+ expectType<string>(req.context.config.foo)
171
+ expectType<number>(req.context.config.bar)
151
172
  expectType<string>(res.context.config.foo)
152
173
  expectType<number>(res.context.config.bar)
153
174
  }
@@ -70,11 +70,11 @@ export interface FastifyInstance<
70
70
  inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
71
71
  inject(): LightMyRequestChain;
72
72
 
73
- listen(port: number | string, address: string, backlog: number, callback: (err: Error, address: string) => void): void;
74
- listen(port: number | string, address: string, callback: (err: Error, address: string) => void): void;
75
- listen(port: number | string, callback: (err: Error, address: string) => void): void;
73
+ listen(port: number | string, address: string, backlog: number, callback: (err: Error|null, address: string) => void): void;
74
+ listen(port: number | string, address: string, callback: (err: Error|null, address: string) => void): void;
75
+ listen(port: number | string, callback: (err: Error|null, address: string) => void): void;
76
76
  listen(port: number | string, address?: string, backlog?: number): Promise<string>;
77
- listen(opts: { port: number; host?: string; backlog?: number }, callback: (err: Error, address: string) => void): void;
77
+ listen(opts: { port: number; host?: string; backlog?: number }, callback: (err: Error|null, address: string) => void): void;
78
78
  listen(opts: { port: number; host?: string; backlog?: number }): Promise<string>;
79
79
 
80
80
  ready(): FastifyInstance<RawServer, RawRequest, RawReply> & PromiseLike<undefined>;
@@ -1,7 +1,8 @@
1
1
  import { FastifyLoggerInstance } from './logger'
2
- import { RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './utils'
2
+ import { ContextConfigDefault, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './utils'
3
3
  import { RouteGenericInterface } from './route'
4
4
  import { FastifyInstance } from './instance'
5
+ import { FastifyContext } from './context'
5
6
 
6
7
  export interface RequestGenericInterface {
7
8
  Body?: RequestBodyDefault;
@@ -18,6 +19,7 @@ export interface FastifyRequest<
18
19
  RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
19
20
  RawServer extends RawServerBase = RawServerDefault,
20
21
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
22
+ ContextConfig = ContextConfigDefault,
21
23
  > {
22
24
  id: any;
23
25
  params: RouteGeneric['Params'];
@@ -27,6 +29,7 @@ export interface FastifyRequest<
27
29
  log: FastifyLoggerInstance;
28
30
  server: FastifyInstance;
29
31
  body: RouteGeneric['Body'];
32
+ context: FastifyContext<ContextConfig>;
30
33
 
31
34
  /** in order for this to be used the user should ensure they have set the attachValidation option. */
32
35
  validationError?: Error & { validation: any; validationContext: string };
package/types/route.d.ts CHANGED
@@ -59,7 +59,7 @@ export type RouteHandlerMethod<
59
59
  ContextConfig = ContextConfigDefault
60
60
  > = (
61
61
  this: FastifyInstance<RawServer, RawRequest, RawReply>,
62
- request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
62
+ request: FastifyRequest<RouteGeneric, RawServer, RawRequest, ContextConfig>,
63
63
  reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
64
64
  ) => void | Promise<RouteGeneric['Reply'] | void>
65
65