fastify 4.1.0 → 4.3.0

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.
Files changed (56) hide show
  1. package/README.md +13 -14
  2. package/docs/Guides/Database.md +2 -2
  3. package/docs/Guides/Delay-Accepting-Requests.md +1 -1
  4. package/docs/Guides/Ecosystem.md +31 -16
  5. package/docs/Guides/Migration-Guide-V4.md +69 -1
  6. package/docs/Guides/Plugins-Guide.md +5 -0
  7. package/docs/Guides/Serverless.md +23 -10
  8. package/docs/Reference/HTTP2.md +1 -3
  9. package/docs/Reference/Hooks.md +52 -0
  10. package/docs/Reference/Plugins.md +1 -1
  11. package/docs/Reference/Reply.md +176 -0
  12. package/docs/Reference/Request.md +171 -0
  13. package/docs/Reference/Type-Providers.md +1 -15
  14. package/docs/Reference/TypeScript.md +65 -28
  15. package/docs/Reference/Validation-and-Serialization.md +11 -0
  16. package/docs/index.md +1 -1
  17. package/fastify.d.ts +3 -3
  18. package/fastify.js +2 -2
  19. package/integration/server.js +27 -0
  20. package/integration/test.sh +23 -0
  21. package/lib/contentTypeParser.js +10 -2
  22. package/lib/context.js +14 -2
  23. package/lib/error-serializer.js +24 -27
  24. package/lib/errors.js +8 -0
  25. package/lib/handleRequest.js +1 -1
  26. package/lib/reply.js +101 -24
  27. package/lib/request.js +97 -1
  28. package/lib/route.js +41 -29
  29. package/lib/symbols.js +17 -10
  30. package/lib/validation.js +2 -0
  31. package/package.json +9 -9
  32. package/test/build/error-serializer.test.js +3 -1
  33. package/test/content-parser.test.js +15 -0
  34. package/test/hooks.test.js +21 -0
  35. package/test/internals/reply-serialize.test.js +583 -0
  36. package/test/internals/request-validate.test.js +1269 -0
  37. package/test/internals/request.test.js +11 -2
  38. package/test/pretty-print.test.js +3 -3
  39. package/test/reply-error.test.js +1 -1
  40. package/test/request-error.test.js +44 -1
  41. package/test/schema-feature.test.js +2 -2
  42. package/test/schema-validation.test.js +71 -0
  43. package/test/types/fastify.test-d.ts +24 -2
  44. package/test/types/hooks.test-d.ts +1 -2
  45. package/test/types/import.ts +1 -1
  46. package/test/types/instance.test-d.ts +4 -1
  47. package/test/types/request.test-d.ts +8 -4
  48. package/test/types/type-provider.test-d.ts +87 -8
  49. package/test/validation-error-handling.test.js +38 -1
  50. package/types/hooks.d.ts +19 -39
  51. package/types/instance.d.ts +78 -130
  52. package/types/reply.d.ts +5 -0
  53. package/types/request.d.ts +16 -3
  54. package/types/route.d.ts +25 -33
  55. package/types/schema.d.ts +4 -1
  56. package/types/type-provider.d.ts +19 -11
@@ -35,6 +35,19 @@ Request is a core Fastify object containing the following fields:
35
35
  - `connection` - Deprecated, use `socket` instead. The underlying connection of
36
36
  the incoming request.
37
37
  - `socket` - the underlying connection of the incoming request
38
+ - [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
39
+ Returns a validation function for the specified schema or http part,
40
+ if any of either are set or cached.
41
+ - [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
42
+ Compiles the specified schema and returns a validation function
43
+ using the default (or customized) `ValidationCompiler`.
44
+ The optional `httpPart` is forwarded to the `ValidationCompiler`
45
+ if provided, defaults to `null`.
46
+ - [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
47
+ Validates the specified input by using the specified
48
+ schema and returns the serialized payload. If the optional
49
+ `httpPart` is provided, the function will use the serializer
50
+ function given for that HTTP Status Code. Defaults to `null`.
38
51
  - `context` - A Fastify internal object. You should not use it directly or
39
52
  modify it. It is useful to access one special key:
40
53
  - `context.config` - The route [`config`](./Routes.md#routes-config) object.
@@ -77,3 +90,161 @@ fastify.post('/:params', options, function (request, reply) {
77
90
  request.log.info('some info')
78
91
  })
79
92
  ```
93
+ ### .getValidationFunction(schema | httpPart)
94
+ <a id="getvalidationfunction"></a>
95
+
96
+ By calling this function using a provided `schema` or `httpPart`,
97
+ it will return a `validation` function that can be used to
98
+ validate diverse inputs. It returns `undefined` if no
99
+ serialization function was found using either of the provided inputs.
100
+
101
+ ```js
102
+ const validate = request
103
+ .getValidationFunction({
104
+ type: 'object',
105
+ properties: {
106
+ foo: {
107
+ type: 'string'
108
+ }
109
+ }
110
+ })
111
+ validate({ foo: 'bar' }) // true
112
+
113
+ // or
114
+
115
+ const validate = request
116
+ .getValidationFunction('body')
117
+ validate({ foo: 0.5 }) // false
118
+ ```
119
+
120
+ See [.compilaValidationSchema(schema, [httpStatus])](#compilevalidationschema)
121
+ for more information on how to compile validation function.
122
+
123
+ ### .compileValidationSchema(schema, [httpPart])
124
+ <a id="compilevalidationschema"></a>
125
+
126
+ This function will compile a validation schema and
127
+ return a function that can be used to validate data.
128
+ The function returned (a.k.a. _validation function_) is compiled
129
+ by using the provided [`SchemaControler#ValidationCompiler`](./Server.md#schema-controller).
130
+ A `WeakMap` is used to cached this, reducing compilation calls.
131
+
132
+ The optional parameter `httpPart`, if provided, is forwarded directly
133
+ the `ValidationCompiler`, so it can be used to compile the validation
134
+ function if a custom `ValidationCompiler` is provided for the route.
135
+
136
+
137
+ ```js
138
+ const validate = request
139
+ .compileValidationSchema({
140
+ type: 'object',
141
+ properties: {
142
+ foo: {
143
+ type: 'string'
144
+ }
145
+ }
146
+ })
147
+ console.log(validate({ foo: 'bar' })) // true
148
+
149
+ // or
150
+
151
+ const validate = request
152
+ .compileValidationSchema({
153
+ type: 'object',
154
+ properties: {
155
+ foo: {
156
+ type: 'string'
157
+ }
158
+ }
159
+ }, 200)
160
+ console.log(validate({ hello: 'world' })) // false
161
+ ```
162
+
163
+ Note that you should be careful when using this function, as it will cache
164
+ the compiled validation functions based on the schema provided. If the
165
+ schemas provided are mutated or changed, the validation functions will not
166
+ detect that the schema has been altered and for instance it will reuse the
167
+ previously compiled validation function, as the cache is based on
168
+ the reference of the schema (Object) previously provided.
169
+
170
+ If there is a need to change the properties of a schema, always opt to create
171
+ a totally new schema (object), otherwise the implementation will not benefit from
172
+ the cache mechanism.
173
+
174
+ Using the following schema as an example:
175
+ ```js
176
+ const schema1 = {
177
+ type: 'object',
178
+ properties: {
179
+ foo: {
180
+ type: 'string'
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ *Not*
187
+ ```js
188
+ const validate = request.compileValidationSchema(schema1)
189
+
190
+ // Later on...
191
+ schema1.properties.foo.type. = 'integer'
192
+ const newValidate = request.compileValidationSchema(schema1)
193
+
194
+ console.log(newValidate === validate) // true
195
+ ```
196
+
197
+ *Instead*
198
+ ```js
199
+ const validate = request.compileValidationSchema(schema1)
200
+
201
+ // Later on...
202
+ const newSchema = Object.assign({}, schema1)
203
+ newSchema.properties.foo.type = 'integer'
204
+
205
+ const newValidate = request.compileValidationSchema(newSchema)
206
+
207
+ console.log(newValidate === validate) // false
208
+ ```
209
+
210
+ ### .validateInput(data, [schema | httpStatus], [httpStatus])
211
+ <a id="validate"></a>
212
+
213
+ This function will validate the input based on the provided schema,
214
+ or HTTP part passed. If both are provided, the `httpPart` parameter
215
+ will take precedence.
216
+
217
+ If there is not a validation function for a given `schema`, a new validation
218
+ function will be compiled, forwarding the `httpPart` if provided.
219
+
220
+ ```js
221
+ request
222
+ .validateInput({ foo: 'bar'}, {
223
+ type: 'object',
224
+ properties: {
225
+ foo: {
226
+ type: 'string'
227
+ }
228
+ }
229
+ }) // true
230
+
231
+ // or
232
+
233
+ request
234
+ .validateInput({ foo: 'bar'}, {
235
+ type: 'object',
236
+ properties: {
237
+ foo: {
238
+ type: 'string'
239
+ }
240
+ }
241
+ }, 'body') // true
242
+
243
+ // or
244
+
245
+ request
246
+ .validateInput({ hello: 'world'}, 'query') // false
247
+ ```
248
+
249
+ See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
250
+ for more information on how to compile validation schemas.
@@ -70,14 +70,7 @@ import { Type } from '@sinclair/typebox'
70
70
 
71
71
  import fastify from 'fastify'
72
72
 
73
- const server = fastify({
74
- ajv: {
75
- customOptions: {
76
- strict: 'log',
77
- keywords: ['kind', 'modifier'],
78
- },
79
- },
80
- }).withTypeProvider<TypeBoxTypeProvider>()
73
+ const server = fastify().withTypeProvider<TypeBoxTypeProvider>()
81
74
 
82
75
  server.get('/route', {
83
76
  schema: {
@@ -94,13 +87,6 @@ server.get('/route', {
94
87
  })
95
88
  ```
96
89
 
97
- TypeBox uses the properties `kind` and `modifier` internally. These properties
98
- are not strictly valid JSON schema which will cause `AJV@7` and newer versions
99
- to throw an invalid schema error. To remove the error it's either necessary to
100
- omit the properties by using
101
- [`Type.Strict()`](https://github.com/sinclairzx81/typebox#strict) or use the AJV
102
- options for adding custom keywords.
103
-
104
90
  See also the [TypeBox
105
91
  documentation](https://github.com/sinclairzx81/typebox#validation) on how to set
106
92
  up AJV to work with TypeBox.
@@ -143,7 +143,7 @@ route-level `request` object.
143
143
  curl localhost:8080/auth?username=admin&password=Password123!
144
144
  ```
145
145
  And it should return back `logged in!`
146
- 6. But wait theres more! The generic interfaces are also available inside route
146
+ 6. But wait there's more! The generic interfaces are also available inside route
147
147
  level hook methods. Modify the previous route by adding a `preValidation`
148
148
  hook:
149
149
  ```typescript
@@ -199,17 +199,18 @@ Below is how to setup schema validation using vanilla `typebox` and
199
199
  #### typebox
200
200
 
201
201
  A useful library for building types and a schema at once is
202
- [typebox](https://www.npmjs.com/package/@sinclair/typebox). With typebox you
203
- define your schema within your code and use them directly as types or schemas as
204
- you need them.
202
+ [typebox](https://www.npmjs.com/package/@sinclair/typebox) along with
203
+ [fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox).
204
+ With typebox you define your schema within your code and use them
205
+ directly as types or schemas as you need them.
205
206
 
206
207
  When you want to use it for validation of some payload in a fastify route you
207
208
  can do it as follows:
208
209
 
209
- 1. Install `typebox` in your project.
210
+ 1. Install `typebox` and `fastify-type-provider-typebox` in your project.
210
211
 
211
212
  ```bash
212
- npm i @sinclair/typebox
213
+ npm i @sinclair/typebox @fastify/type-provider-typebox
213
214
  ```
214
215
 
215
216
  2. Define the schema you need with `Type` and create the respective type with
@@ -218,40 +219,52 @@ can do it as follows:
218
219
  ```typescript
219
220
  import { Static, Type } from '@sinclair/typebox'
220
221
 
221
- const User = Type.Object({
222
+ export const User = Type.Object({
222
223
  name: Type.String(),
223
- mail: Type.Optional(Type.String({ format: "email" })),
224
- });
225
- type UserType = Static<typeof User>;
224
+ mail: Type.Optional(Type.String({ format: 'email' })),
225
+ })
226
+
227
+ export type UserType = Static<typeof User>
226
228
  ```
227
229
 
228
230
  3. Use the defined type and schema during the definition of your route
229
231
 
230
232
  ```typescript
231
- const app = fastify();
233
+ import Fastify from 'fastify'
234
+ import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
235
+ // ...
236
+
237
+ const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
232
238
 
233
- app.post<{ Body: UserType; Reply: UserType }>(
234
- "/",
239
+ app.post<{ Body: UserType, Reply: UserType }>(
240
+ '/',
235
241
  {
236
242
  schema: {
237
243
  body: User,
238
244
  response: {
239
- 200: User,
245
+ 200: User
240
246
  },
241
247
  },
242
248
  },
243
249
  (request, reply) => {
244
- const { body: user } = request;
245
- /* user has type
246
- * const user: StaticProperties<{
247
- * name: TString;
248
- * mail: TOptional<TString>;
249
- * }>
250
- */
251
- //...
252
- reply.status(200).send(user);
250
+ // The `name` and `mail` types are automatically inferred
251
+ const { name, mail } = request.body;
252
+ reply.status(200).send({ name, mail });
253
+ }
254
+ )
255
+ ```
256
+
257
+ **Note** For Ajv version 7 and above is required to use the `ajvTypeBoxPlugin`:
258
+
259
+ ```typescript
260
+ import Fastify from 'fastify'
261
+ import { ajvTypeBoxPlugin, TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
262
+
263
+ const fastify = Fastify({
264
+ ajv: {
265
+ plugins: [ajvTypeBoxPlugin]
253
266
  }
254
- );
267
+ }).withTypeProvider<TypeBoxTypeProvider>()
255
268
  ```
256
269
 
257
270
  #### Schemas in JSON Files
@@ -390,7 +403,7 @@ definitions.
390
403
  #### json-schema-to-ts
391
404
 
392
405
  If you do not want to generate types from your schemas, but want to use them
393
- diretly from your code, you can use the package
406
+ directly from your code, you can use the package
394
407
  [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts).
395
408
 
396
409
  You can install it as dev-dependency.
@@ -648,6 +661,30 @@ However, there are a couple of suggestions to help improve this experience:
648
661
  [npm-check](https://www.npmjs.com/package/npm-check) to verify plugin
649
662
  dependencies are being used somewhere in your project.
650
663
 
664
+ Note that using `require` will not load the type definitions properly and may
665
+ cause type errors.
666
+ TypeScript can only identify the types that are directly imported into code,
667
+ which means that you can use require inline with import on top. For example:
668
+
669
+ ```typescript
670
+ import 'plugin' // here will trigger the type augmentation.
671
+
672
+ fastify.register(require('plugin'))
673
+ ```
674
+
675
+ ```typescript
676
+ import plugin from 'plugin' // here will trigger the type augmentation.
677
+
678
+ fastify.register(plugin)
679
+ ```
680
+
681
+ Or even explicit config on tsconfig
682
+ ```jsonc
683
+ {
684
+ "types": ["plugin"] // we force TypeScript to import the types
685
+ }
686
+ ```
687
+
651
688
  ## Code Completion In Vanilla JavaScript
652
689
 
653
690
  Vanilla JavaScript can use the published types to provide code completion (e.g.
@@ -1359,17 +1396,17 @@ A method for checking the existence of a type parser of a certain content type
1359
1396
 
1360
1397
  ##### fastify.FastifyError
1361
1398
 
1362
- [src](https://github.com/fastify/fastify/blob/main/types/error.d.ts#L17)
1399
+ [src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179)
1363
1400
 
1364
1401
  FastifyError is a custom error object that includes status code and validation
1365
1402
  results.
1366
1403
 
1367
1404
  It extends the Node.js `Error` type, and adds two additional, optional
1368
- properties: `statusCode: number` and `validation: ValiationResult[]`.
1405
+ properties: `statusCode: number` and `validation: ValidationResult[]`.
1369
1406
 
1370
1407
  ##### fastify.ValidationResult
1371
1408
 
1372
- [src](https://github.com/fastify/fastify/blob/main/types/error.d.ts#L4)
1409
+ [src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184)
1373
1410
 
1374
1411
  The route validation internally relies upon Ajv, which is a high-performance
1375
1412
  JSON schema validator.
@@ -484,6 +484,17 @@ fastify.post('/the/url', {
484
484
  }, handler)
485
485
  ```
486
486
 
487
+ ##### .statusCode property
488
+
489
+ All validation errors will be added a `.statusCode` property set to `400`. This guarantees
490
+ that the default error handler will set the status code of the response to `400`.
491
+
492
+ ```js
493
+ fastify.setErrorHandler(function (error, request, reply) {
494
+ request.log.error(error, `This error has status code ${error.statusCode}`)
495
+ reply.status(error.statusCode).send(error)
496
+ })
497
+ ```
487
498
 
488
499
  ##### Validation messages with other validation libraries
489
500
 
package/docs/index.md CHANGED
@@ -16,7 +16,7 @@ Complete newcomers to Fastify should first read our [Getting
16
16
  Started](./Guides/Getting-Started.md) guide.
17
17
 
18
18
  Developers experienced with Fastify should consult the [reference
19
- documentation](./Reference/index.md) directly to find the topic they are seeking
19
+ documentation](./Reference/Index.md) directly to find the topic they are seeking
20
20
  more information about.
21
21
 
22
22
  ## Additional Documentation
package/fastify.d.ts CHANGED
@@ -183,10 +183,10 @@ declare module '@fastify/error' {
183
183
 
184
184
  export interface ValidationResult {
185
185
  keyword: string;
186
- dataPath: string;
186
+ instancePath: string;
187
187
  schemaPath: string;
188
188
  params: Record<string, string | string[]>;
189
- message: string;
189
+ message?: string;
190
190
  }
191
191
 
192
192
  /* Export all additional types */
@@ -194,7 +194,7 @@ export type { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRe
194
194
  export { FastifyRequest, RequestGenericInterface } from './types/request'
195
195
  export { FastifyReply } from './types/reply'
196
196
  export { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
197
- export { FastifyInstance, PrintRoutesOptions } from './types/instance'
197
+ export { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
198
198
  export { FastifyLoggerOptions, FastifyBaseLogger, FastifyLoggerInstance, FastifyLogFn, LogLevel } from './types/logger'
199
199
  export { FastifyContext, FastifyContextConfig } from './types/context'
200
200
  export { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.1.0'
3
+ const VERSION = '4.3.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -621,7 +621,7 @@ function fastify (options) {
621
621
  // https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
622
622
 
623
623
  // If the socket is not writable, there is no reason to try to send data.
624
- if (socket.writable && socket.bytesWritten === 0) {
624
+ if (socket.writable) {
625
625
  socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
626
626
  }
627
627
  socket.destroy(err)
@@ -0,0 +1,27 @@
1
+ const Fastify = require('../fastify')
2
+
3
+ const fastify = Fastify()
4
+
5
+ fastify.listen({
6
+ host: '::',
7
+ port: 3000
8
+ })
9
+
10
+ fastify.get('/', async function (request, reply) {
11
+ reply.code(200).send({ data: 'home page' })
12
+ })
13
+
14
+ fastify.post('/post/:id', async function (request, reply) {
15
+ const { id } = request.params
16
+ reply.code(201).send({ data: `${id}` })
17
+ })
18
+
19
+ fastify.put('/put/:id', async function (request, reply) {
20
+ const { id } = request.params
21
+ reply.code(200).send({ data: `${id}` })
22
+ })
23
+
24
+ fastify.delete('/delete/:id', async function (request, reply) {
25
+ const { id } = request.params
26
+ reply.code(204).send({ data: `${id}` })
27
+ })
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/bash
2
+
3
+ set -e
4
+
5
+ NUMBER=$RANDOM
6
+ curl -i -X GET -H 'Content-Type: application/json' localhost:3000/ > GET
7
+ if [[ ! $(cat GET | head -1| cut -f2 -d" ") == "200" || ! $(cat GET | tail -1| cut -f4 -d"\"") == "home page" ]] ; then
8
+ exit 1
9
+ fi;
10
+ curl -i -X POST -H 'Content-Type: application/json' localhost:3000/post/$NUMBER --data {} > POST
11
+ if [[ ! $(cat POST | head -1| cut -f2 -d" ") == "201" || ! $(cat POST | tail -1| cut -f4 -d"\"") == $(echo $NUMBER) ]]; then
12
+ exit 1
13
+ fi;
14
+ curl -i -X PUT -H 'Content-Type: application/json' localhost:3000/put/$NUMBER --data {} > PUT
15
+ if [[ ! $(cat PUT | head -1| cut -f2 -d" ") == "200" || ! $(cat PUT | tail -1| cut -f4 -d"\"") == $(echo $NUMBER) ]]; then
16
+ exit 1
17
+ fi;
18
+ curl -i -X DELETE -H 'Content-Type: application/json' localhost:3000/delete/$NUMBER --data {} > DELETE
19
+ if [[ ! $(cat DELETE | head -1| cut -f2 -d" ") == "204" ]]; then
20
+ exit 1
21
+ fi;
22
+
23
+ rm -f GET POST PUT DELETE
@@ -92,10 +92,18 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
92
92
  }
93
93
 
94
94
  ContentTypeParser.prototype.getParser = function (contentType) {
95
+ if (contentType in this.customParsers) {
96
+ return this.customParsers[contentType]
97
+ }
98
+
99
+ if (this.cache.has(contentType)) {
100
+ return this.cache.get(contentType)
101
+ }
102
+
95
103
  // eslint-disable-next-line no-var
96
104
  for (var i = 0; i !== this.parserList.length; ++i) {
97
105
  const parserName = this.parserList[i]
98
- if (contentType.indexOf(parserName) > -1) {
106
+ if (contentType.indexOf(parserName) !== -1) {
99
107
  const parser = this.customParsers[parserName]
100
108
  this.cache.set(contentType, parser)
101
109
  return parser
@@ -137,7 +145,7 @@ ContentTypeParser.prototype.remove = function (contentType) {
137
145
  }
138
146
 
139
147
  ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
140
- const parser = this.cache.get(contentType) || this.getParser(contentType)
148
+ const parser = this.getParser(contentType)
141
149
  const resource = new AsyncResource('content-type-parser:run', request)
142
150
 
143
151
  if (parser === undefined) {
package/lib/context.js CHANGED
@@ -9,7 +9,10 @@ const {
9
9
  kRequest,
10
10
  kBodyLimit,
11
11
  kLogLevel,
12
- kContentTypeParser
12
+ kContentTypeParser,
13
+ kRouteByFastify,
14
+ kRequestValidateWeakMap,
15
+ kReplySerializeWeakMap
13
16
  } = require('./symbols.js')
14
17
 
15
18
  // Objects that holds the context of every request
@@ -23,9 +26,12 @@ function Context ({
23
26
  logLevel,
24
27
  logSerializers,
25
28
  attachValidation,
29
+ validatorCompiler,
30
+ serializerCompiler,
26
31
  replySerializer,
27
32
  schemaErrorFormatter,
28
- server
33
+ server,
34
+ isFastify
29
35
  }) {
30
36
  this.schema = schema
31
37
  this.handler = handler
@@ -50,6 +56,12 @@ function Context ({
50
56
  this.attachValidation = attachValidation
51
57
  this[kReplySerializerDefault] = replySerializer
52
58
  this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter
59
+ this[kRouteByFastify] = isFastify
60
+
61
+ this[kRequestValidateWeakMap] = null
62
+ this[kReplySerializeWeakMap] = null
63
+ this.validatorCompiler = validatorCompiler || null
64
+ this.serializerCompiler = serializerCompiler || null
53
65
 
54
66
  this.server = server
55
67
  }
@@ -39,7 +39,7 @@ class Serializer {
39
39
  } else {
40
40
  /* eslint no-undef: "off" */
41
41
  const integer = this.parseInteger(i)
42
- if (Number.isNaN(integer)) {
42
+ if (Number.isNaN(integer) || !Number.isFinite(integer)) {
43
43
  throw new Error(`The value "${i}" cannot be converted to an integer.`)
44
44
  } else {
45
45
  return '' + integer
@@ -55,6 +55,8 @@ class Serializer {
55
55
  const num = Number(i)
56
56
  if (Number.isNaN(num)) {
57
57
  throw new Error(`The value "${i}" cannot be converted to a number.`)
58
+ } else if (!Number.isFinite(num)) {
59
+ return null
58
60
  } else {
59
61
  return '' + num
60
62
  }
@@ -72,44 +74,44 @@ class Serializer {
72
74
  return bool === null ? 'null' : this.asBoolean(bool)
73
75
  }
74
76
 
75
- asDatetime (date, skipQuotes) {
76
- const quotes = skipQuotes === true ? '' : '"'
77
+ asDateTime (date) {
78
+ if (date === null) return '""'
77
79
  if (date instanceof Date) {
78
- return quotes + date.toISOString() + quotes
80
+ return '"' + date.toISOString() + '"'
79
81
  }
80
- return this.asString(date, skipQuotes)
82
+ throw new Error(`The value "${date}" cannot be converted to a date-time.`)
81
83
  }
82
84
 
83
- asDatetimeNullable (date, skipQuotes) {
84
- return date === null ? 'null' : this.asDatetime(date, skipQuotes)
85
+ asDateTimeNullable (date) {
86
+ return date === null ? 'null' : this.asDateTime(date)
85
87
  }
86
88
 
87
- asDate (date, skipQuotes) {
88
- const quotes = skipQuotes === true ? '' : '"'
89
+ asDate (date) {
90
+ if (date === null) return '""'
89
91
  if (date instanceof Date) {
90
- return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + quotes
92
+ return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + '"'
91
93
  }
92
- return this.asString(date, skipQuotes)
94
+ throw new Error(`The value "${date}" cannot be converted to a date.`)
93
95
  }
94
96
 
95
- asDateNullable (date, skipQuotes) {
96
- return date === null ? 'null' : this.asDate(date, skipQuotes)
97
+ asDateNullable (date) {
98
+ return date === null ? 'null' : this.asDate(date)
97
99
  }
98
100
 
99
- asTime (date, skipQuotes) {
100
- const quotes = skipQuotes === true ? '' : '"'
101
+ asTime (date) {
102
+ if (date === null) return '""'
101
103
  if (date instanceof Date) {
102
- return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + quotes
104
+ return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + '"'
103
105
  }
104
- return this.asString(date, skipQuotes)
106
+ throw new Error(`The value "${date}" cannot be converted to a time.`)
105
107
  }
106
108
 
107
- asTimeNullable (date, skipQuotes) {
108
- return date === null ? 'null' : this.asTime(date, skipQuotes)
109
+ asTimeNullable (date) {
110
+ return date === null ? 'null' : this.asTime(date)
109
111
  }
110
112
 
111
- asString (str, skipQuotes) {
112
- const quotes = skipQuotes === true ? '' : '"'
113
+ asString (str) {
114
+ const quotes = '"'
113
115
  if (str instanceof Date) {
114
116
  return quotes + str.toISOString() + quotes
115
117
  } else if (str === null) {
@@ -119,11 +121,6 @@ class Serializer {
119
121
  } else if (typeof str !== 'string') {
120
122
  str = str.toString()
121
123
  }
122
- // If we skipQuotes it means that we are using it as test
123
- // no need to test the string length for the render
124
- if (skipQuotes) {
125
- return str
126
- }
127
124
 
128
125
  if (str.length < 42) {
129
126
  return this.asStringSmall(str)
@@ -185,7 +182,7 @@ class Serializer {
185
182
  }
186
183
 
187
184
  function anonymous0 (input) {
188
- // main
185
+ // #
189
186
 
190
187
  var obj = (input && typeof input.toJSON === 'function')
191
188
  ? input.toJSON()