fastify 5.2.2 → 5.3.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/SPONSORS.md +0 -1
- package/docs/Guides/Ecosystem.md +2 -0
- package/docs/Reference/Decorators.md +199 -0
- package/docs/Reference/Errors.md +2 -0
- package/fastify.js +3 -2
- package/lib/decorate.js +18 -3
- package/lib/errors.js +4 -0
- package/lib/reply.js +17 -2
- package/lib/request.js +28 -2
- package/lib/validation.js +11 -1
- package/package.json +3 -3
- package/test/build/error-serializer.test.js +1 -2
- package/test/custom-parser.0.test.js +160 -129
- package/test/custom-parser.1.test.js +77 -63
- package/test/custom-parser.4.test.js +55 -38
- package/test/custom-querystring-parser.test.js +46 -28
- package/test/decorator.test.js +174 -4
- package/test/fastify-instance.test.js +12 -2
- package/test/hooks.on-listen.test.js +17 -14
- package/test/internals/errors.test.js +14 -1
- package/test/listen.2.test.js +4 -1
- package/test/logger/instantiation.test.js +89 -96
- package/test/logger/logging.test.js +116 -120
- package/test/logger/options.test.js +97 -99
- package/test/logger/request.test.js +66 -66
- package/test/schema-validation.test.js +120 -0
- package/test/server.test.js +175 -0
- package/test/stream.4.test.js +38 -33
- package/test/toolkit.js +31 -0
- package/test/types/instance.test-d.ts +3 -0
- package/test/types/reply.test-d.ts +1 -0
- package/test/types/request.test-d.ts +4 -0
- package/test/types/type-provider.test-d.ts +40 -0
- package/test/upgrade.test.js +3 -6
- package/types/instance.d.ts +2 -0
- package/types/reply.d.ts +1 -0
- package/types/request.d.ts +2 -0
- package/types/type-provider.d.ts +12 -3
package/SPONSORS.md
CHANGED
|
@@ -16,7 +16,6 @@ _Be the first!_
|
|
|
16
16
|
- [Mercedes-Benz Group](https://github.com/mercedes-benz)
|
|
17
17
|
- [Val Town, Inc.](https://opencollective.com/valtown)
|
|
18
18
|
- [Handsontable - JavaScript Data Grid](https://handsontable.com/docs/react-data-grid/?utm_source=Fastify_GH&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024)
|
|
19
|
-
- [Jspreadsheet](https://jspreadsheet.com/)
|
|
20
19
|
- [Lokalise - A Localization and Translation Software Tool](https://lokalise.com/?utm_source=Fastify_GH&utm_medium=sponsorship)
|
|
21
20
|
|
|
22
21
|
## Tier 2
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -460,6 +460,8 @@ middlewares into Fastify plugins
|
|
|
460
460
|
Lightweight cache plugin
|
|
461
461
|
- [`fastify-list-routes`](https://github.com/chuongtrh/fastify-list-routes)
|
|
462
462
|
A simple plugin for Fastify to list all available routes.
|
|
463
|
+
- [`fastify-lm`](https://github.com/galiprandi/fastify-lm#readme)
|
|
464
|
+
Use OpenAI, Claude, Google, Deepseek, and others LMs with one Fastify plugin.
|
|
463
465
|
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from
|
|
464
466
|
a directory and inject the Fastify instance in each file.
|
|
465
467
|
- [`fastify-log-controller`](https://github.com/Eomm/fastify-log-controller/)
|
|
@@ -365,3 +365,202 @@ Will define the `foo` property on the Fastify instance:
|
|
|
365
365
|
```js
|
|
366
366
|
console.log(fastify.foo) // 'a getter'
|
|
367
367
|
```
|
|
368
|
+
|
|
369
|
+
### `getDecorator<T>` API
|
|
370
|
+
|
|
371
|
+
Fastify's `getDecorator<T>` API retrieves an existing decorator from the
|
|
372
|
+
Fastify instance, `Request`, or `Reply`. If the decorator is not defined, an
|
|
373
|
+
`FST_ERR_DEC_UNDECLARED` error is thrown.
|
|
374
|
+
|
|
375
|
+
#### Use cases
|
|
376
|
+
|
|
377
|
+
**Early Plugin Dependency Validation**
|
|
378
|
+
|
|
379
|
+
`getDecorator<T>` on Fastify instance verifies that required decorators are
|
|
380
|
+
available at registration time.
|
|
381
|
+
|
|
382
|
+
For example:
|
|
383
|
+
|
|
384
|
+
```js
|
|
385
|
+
fastify.register(async function (fastify) {
|
|
386
|
+
const usersRepository = fastify.getDecorator('usersRepository')
|
|
387
|
+
|
|
388
|
+
fastify.get('/users', async function (request, reply) {
|
|
389
|
+
// We are sure `usersRepository` exists at runtime
|
|
390
|
+
return usersRepository.findAll()
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Handling Missing Decorators**
|
|
396
|
+
|
|
397
|
+
Directly accessing a decorator may lead to unexpected behavior if it is not declared:
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
const user = request.user;
|
|
401
|
+
if (user && user.isAdmin) {
|
|
402
|
+
// Execute admin tasks.
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
If `request.user` doesn't exist, then `user` will be set to `undefined`.
|
|
407
|
+
This makes it unclear whether the user is unauthenticated or the decorator is missing.
|
|
408
|
+
|
|
409
|
+
Using `getDecorator` enforces runtime safety:
|
|
410
|
+
|
|
411
|
+
```ts
|
|
412
|
+
// If the decorator is missing, an explicit `FST_ERR_DEC_UNDECLARED`
|
|
413
|
+
// error is thrown immediately.
|
|
414
|
+
const user = request.getDecorator('user');
|
|
415
|
+
if (user && user.isAdmin) {
|
|
416
|
+
// Execute admin tasks.
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Alternative to Module Augmentation**
|
|
421
|
+
|
|
422
|
+
Decorators are typically typed via module augmentation:
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
declare module 'fastify' {
|
|
426
|
+
interface FastifyInstance {
|
|
427
|
+
usersRepository: IUsersRepository
|
|
428
|
+
}
|
|
429
|
+
interface FastifyRequest {
|
|
430
|
+
session: ISession
|
|
431
|
+
}
|
|
432
|
+
interface FastifyReply {
|
|
433
|
+
sendSuccess: SendSuccessFn
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
This approach modifies the Fastify instance globally, which may lead to
|
|
439
|
+
conflicts and inconsistent behavior in multi-server setups or with plugin
|
|
440
|
+
encapsulation.
|
|
441
|
+
|
|
442
|
+
Using `getDecorator<T>` allows to limit types scope:
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
serverOne.register(async function (fastify) {
|
|
446
|
+
const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
|
|
447
|
+
'usersRepository'
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
fastify.decorateRequest('session', null)
|
|
451
|
+
fastify.addHook('onRequest', async (req, reply) => {
|
|
452
|
+
// Yes, the request object has a setDecorator method.
|
|
453
|
+
// More information will be provided soon.
|
|
454
|
+
req.setDecorator('session', { user: 'Jean' })
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
fastify.get('/me', (request, reply) => {
|
|
458
|
+
const session = request.getDecorator<ISession>('session')
|
|
459
|
+
reply.send(session)
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
serverTwo.register(async function (fastify) {
|
|
464
|
+
const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
|
|
465
|
+
'usersRepository'
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
fastify.decorateReply('sendSuccess', function (data) {
|
|
469
|
+
return this.send({ success: true })
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
fastify.get('/success', async (request, reply) => {
|
|
473
|
+
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
|
474
|
+
await sendSuccess()
|
|
475
|
+
})
|
|
476
|
+
})
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
#### Bound functions inference
|
|
480
|
+
|
|
481
|
+
To save time, it's common to infer function types instead of
|
|
482
|
+
writing them manually:
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
function sendSuccess (this: FastifyReply) {
|
|
486
|
+
return this.send({ success: true })
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export type SendSuccess = typeof sendSuccess
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
However, `getDecorator` returns functions with the `this`
|
|
493
|
+
context already **bound**, meaning the `this` parameter disappears
|
|
494
|
+
from the function signature.
|
|
495
|
+
|
|
496
|
+
To correctly type it, you should use `OmitThisParameter` utility:
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
function sendSuccess (this: FastifyReply) {
|
|
500
|
+
return this.send({ success: true })
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
|
|
504
|
+
|
|
505
|
+
fastify.decorateReply('sendSuccess', sendSuccess)
|
|
506
|
+
fastify.get('/success', async (request, reply) => {
|
|
507
|
+
const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
|
|
508
|
+
await sendSuccess()
|
|
509
|
+
})
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### `Request.setDecorator<T>` Method
|
|
513
|
+
|
|
514
|
+
The `setDecorator<T>` method provides a safe and convenient way to
|
|
515
|
+
update the value of a `Request` decorator.
|
|
516
|
+
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error
|
|
517
|
+
is thrown.
|
|
518
|
+
|
|
519
|
+
#### Use Cases
|
|
520
|
+
|
|
521
|
+
**Runtime Safety**
|
|
522
|
+
|
|
523
|
+
A typical way to set a `Request` decorator looks like this:
|
|
524
|
+
|
|
525
|
+
```ts
|
|
526
|
+
fastify.decorateRequest('user', '')
|
|
527
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
528
|
+
req.user = 'Bob Dylan'
|
|
529
|
+
})
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
However, there is no guarantee that the decorator actually exists
|
|
533
|
+
unless you manually check beforehand.
|
|
534
|
+
Additionally, typos are common, e.g. `account`, `acount`, or `accout`.
|
|
535
|
+
|
|
536
|
+
By using `setDecorator`, you are always sure that the decorator exists:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
fastify.decorateRequest('user', '')
|
|
540
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
541
|
+
// Throws FST_ERR_DEC_UNDECLARED if the decorator does not exist
|
|
542
|
+
req.setDecorator('user-with-typo', 'Bob Dylan')
|
|
543
|
+
})
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
**Type Safety**
|
|
549
|
+
|
|
550
|
+
If the `FastifyRequest` interface does not declare the decorator, you
|
|
551
|
+
would typically need to use type assertions:
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
555
|
+
(req as typeof req & { user: string }).user = 'Bob Dylan'
|
|
556
|
+
})
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
The `setDecorator<T>` method eliminates the need for explicit type
|
|
560
|
+
assertions while allowing type safety:
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
564
|
+
req.setDecorator<string>('user', 'Bob Dylan')
|
|
565
|
+
})
|
|
566
|
+
```
|
package/docs/Reference/Errors.md
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
- [FST_ERR_DEC_MISSING_DEPENDENCY](#fst_err_dec_missing_dependency)
|
|
37
37
|
- [FST_ERR_DEC_AFTER_START](#fst_err_dec_after_start)
|
|
38
38
|
- [FST_ERR_DEC_REFERENCE_TYPE](#fst_err_dec_reference_type)
|
|
39
|
+
- [FST_ERR_DEC_UNDECLARED](#fst_err_dec_undeclared)
|
|
39
40
|
- [FST_ERR_HOOK_INVALID_TYPE](#fst_err_hook_invalid_type)
|
|
40
41
|
- [FST_ERR_HOOK_INVALID_HANDLER](#fst_err_hook_invalid_handler)
|
|
41
42
|
- [FST_ERR_HOOK_INVALID_ASYNC_HANDLER](#fst_err_hook_invalid_async_handler)
|
|
@@ -306,6 +307,7 @@ Below is a table with all the error codes used by Fastify.
|
|
|
306
307
|
| <a id="fst_err_dec_missing_dependency">FST_ERR_DEC_MISSING_DEPENDENCY</a> | The decorator cannot be registered due to a missing dependency. | Register the missing dependency. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
|
307
308
|
| <a id="fst_err_dec_after_start">FST_ERR_DEC_AFTER_START</a> | The decorator cannot be added after start. | Add the decorator before starting the server. | [#2128](https://github.com/fastify/fastify/pull/2128) |
|
|
308
309
|
| <a id="fst_err_dec_reference_type">FST_ERR_DEC_REFERENCE_TYPE</a> | The decorator cannot be a reference type. | Define the decorator with a getter/setter interface or an empty decorator with a hook. | [#5462](https://github.com/fastify/fastify/pull/5462) |
|
|
310
|
+
| <a id="fst_err_dec_undeclared">FST_ERR_DEC_UNDECLARED</a> | An attempt was made to access a decorator that has not been declared. | Declare the decorator before using it. | [#](https://github.com/fastify/fastify/pull/)
|
|
309
311
|
| <a id="fst_err_hook_invalid_type">FST_ERR_HOOK_INVALID_TYPE</a> | The hook name must be a string. | Use a string for the hook name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
|
310
312
|
| <a id="fst_err_hook_invalid_handler">FST_ERR_HOOK_INVALID_HANDLER</a> | The hook callback must be a function. | Use a function for the hook callback. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
|
311
313
|
| <a id="fst_err_hook_invalid_async_handler">FST_ERR_HOOK_INVALID_ASYNC_HANDLER</a> | Async function has too many arguments. Async hooks should not use the `done` argument. | Remove the `done` argument from the async hook. | [#4367](https://github.com/fastify/fastify/pull/4367) |
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '5.
|
|
3
|
+
const VERSION = '5.3.1'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -343,6 +343,7 @@ function fastify (options) {
|
|
|
343
343
|
decorateRequest: decorator.decorateRequest,
|
|
344
344
|
hasRequestDecorator: decorator.existRequest,
|
|
345
345
|
hasReplyDecorator: decorator.existReply,
|
|
346
|
+
getDecorator: decorator.getInstanceDecorator,
|
|
346
347
|
addHttpMethod,
|
|
347
348
|
// fake http injection
|
|
348
349
|
inject,
|
|
@@ -639,7 +640,7 @@ function fastify (options) {
|
|
|
639
640
|
resolveReady(fastify)
|
|
640
641
|
fastify[kState].booting = false
|
|
641
642
|
fastify[kState].ready = true
|
|
642
|
-
fastify[kState].
|
|
643
|
+
fastify[kState].readyPromise = null
|
|
643
644
|
}
|
|
644
645
|
}
|
|
645
646
|
|
package/lib/decorate.js
CHANGED
|
@@ -4,7 +4,7 @@ const {
|
|
|
4
4
|
kReply,
|
|
5
5
|
kRequest,
|
|
6
6
|
kState,
|
|
7
|
-
kHasBeenDecorated
|
|
7
|
+
kHasBeenDecorated,
|
|
8
8
|
} = require('./symbols.js')
|
|
9
9
|
|
|
10
10
|
const {
|
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
FST_ERR_DEC_MISSING_DEPENDENCY,
|
|
13
13
|
FST_ERR_DEC_AFTER_START,
|
|
14
14
|
FST_ERR_DEC_REFERENCE_TYPE,
|
|
15
|
-
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE
|
|
15
|
+
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE,
|
|
16
|
+
FST_ERR_DEC_UNDECLARED,
|
|
16
17
|
} = require('./errors')
|
|
17
18
|
|
|
18
19
|
function decorate (instance, name, fn, dependencies) {
|
|
@@ -32,6 +33,18 @@ function decorate (instance, name, fn, dependencies) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
function getInstanceDecorator (name) {
|
|
37
|
+
if (!checkExistence(this, name)) {
|
|
38
|
+
throw new FST_ERR_DEC_UNDECLARED(name, 'instance')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (typeof this[name] === 'function') {
|
|
42
|
+
return this[name].bind(this)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this[name]
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
function decorateConstructor (konstructor, name, fn, dependencies) {
|
|
36
49
|
const instance = konstructor.prototype
|
|
37
50
|
if (Object.hasOwn(instance, name) || hasKey(konstructor, name)) {
|
|
@@ -133,5 +146,7 @@ module.exports = {
|
|
|
133
146
|
existReply: checkReplyExistence,
|
|
134
147
|
dependencies: checkDependencies,
|
|
135
148
|
decorateReply,
|
|
136
|
-
decorateRequest
|
|
149
|
+
decorateRequest,
|
|
150
|
+
getInstanceDecorator,
|
|
151
|
+
hasKey
|
|
137
152
|
}
|
package/lib/errors.js
CHANGED
|
@@ -149,6 +149,10 @@ const codes = {
|
|
|
149
149
|
'FST_ERR_DEC_REFERENCE_TYPE',
|
|
150
150
|
"The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead."
|
|
151
151
|
),
|
|
152
|
+
FST_ERR_DEC_UNDECLARED: createError(
|
|
153
|
+
'FST_ERR_DEC_UNDECLARED',
|
|
154
|
+
"No decorator '%s' has been declared on %s."
|
|
155
|
+
),
|
|
152
156
|
|
|
153
157
|
/**
|
|
154
158
|
* hooks
|
package/lib/reply.js
CHANGED
|
@@ -22,7 +22,7 @@ const {
|
|
|
22
22
|
kReplyCacheSerializeFns,
|
|
23
23
|
kSchemaController,
|
|
24
24
|
kOptions,
|
|
25
|
-
kRouteContext
|
|
25
|
+
kRouteContext,
|
|
26
26
|
} = require('./symbols.js')
|
|
27
27
|
const {
|
|
28
28
|
onSendHookRunner,
|
|
@@ -52,8 +52,10 @@ const {
|
|
|
52
52
|
FST_ERR_BAD_TRAILER_NAME,
|
|
53
53
|
FST_ERR_BAD_TRAILER_VALUE,
|
|
54
54
|
FST_ERR_MISSING_SERIALIZATION_FN,
|
|
55
|
-
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN
|
|
55
|
+
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN,
|
|
56
|
+
FST_ERR_DEC_UNDECLARED,
|
|
56
57
|
} = require('./errors')
|
|
58
|
+
const decorators = require('./decorate')
|
|
57
59
|
|
|
58
60
|
const toString = Object.prototype.toString
|
|
59
61
|
|
|
@@ -475,6 +477,19 @@ Reply.prototype.then = function (fulfilled, rejected) {
|
|
|
475
477
|
})
|
|
476
478
|
}
|
|
477
479
|
|
|
480
|
+
Reply.prototype.getDecorator = function (name) {
|
|
481
|
+
if (!decorators.hasKey(this, name) && !decorators.exist(this, name)) {
|
|
482
|
+
throw new FST_ERR_DEC_UNDECLARED(name, 'reply')
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const decorator = this[name]
|
|
486
|
+
if (typeof decorator === 'function') {
|
|
487
|
+
return decorator.bind(this)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return decorator
|
|
491
|
+
}
|
|
492
|
+
|
|
478
493
|
function preSerializationHook (reply, payload) {
|
|
479
494
|
if (reply[kRouteContext].preSerialization !== null) {
|
|
480
495
|
preSerializationHookRunner(
|
package/lib/request.js
CHANGED
|
@@ -11,9 +11,10 @@ const {
|
|
|
11
11
|
kOptions,
|
|
12
12
|
kRequestCacheValidateFns,
|
|
13
13
|
kRouteContext,
|
|
14
|
-
kRequestOriginalUrl
|
|
14
|
+
kRequestOriginalUrl,
|
|
15
15
|
} = require('./symbols')
|
|
16
|
-
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors')
|
|
16
|
+
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
|
|
17
|
+
const decorators = require('./decorate')
|
|
17
18
|
|
|
18
19
|
const HTTP_PART_SYMBOL_MAP = {
|
|
19
20
|
body: kSchemaBody,
|
|
@@ -141,6 +142,12 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
|
|
141
142
|
return _Request
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
function assertsRequestDecoration (request, name) {
|
|
146
|
+
if (!decorators.hasKey(request, name) && !decorators.exist(request, name)) {
|
|
147
|
+
throw new FST_ERR_DEC_UNDECLARED(name, 'request')
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
144
151
|
Object.defineProperties(Request.prototype, {
|
|
145
152
|
server: {
|
|
146
153
|
get () {
|
|
@@ -343,6 +350,25 @@ Object.defineProperties(Request.prototype, {
|
|
|
343
350
|
|
|
344
351
|
return validate(input)
|
|
345
352
|
}
|
|
353
|
+
},
|
|
354
|
+
getDecorator: {
|
|
355
|
+
value: function (name) {
|
|
356
|
+
assertsRequestDecoration(this, name)
|
|
357
|
+
|
|
358
|
+
const decorator = this[name]
|
|
359
|
+
if (typeof decorator === 'function') {
|
|
360
|
+
return decorator.bind(this)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return decorator
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
setDecorator: {
|
|
367
|
+
value: function (name, value) {
|
|
368
|
+
assertsRequestDecoration(this, name)
|
|
369
|
+
|
|
370
|
+
this[name] = value
|
|
371
|
+
}
|
|
346
372
|
}
|
|
347
373
|
})
|
|
348
374
|
|
package/lib/validation.js
CHANGED
|
@@ -155,7 +155,7 @@ function validate (context, request, execution) {
|
|
|
155
155
|
validatorFunction = context[bodySchema]
|
|
156
156
|
} else if (context[bodySchema]) {
|
|
157
157
|
// TODO: add request.contentType and reuse it here
|
|
158
|
-
const contentType = request.headers['content-type']
|
|
158
|
+
const contentType = getEssenceMediaType(request.headers['content-type'])
|
|
159
159
|
const contentSchema = context[bodySchema][contentType]
|
|
160
160
|
if (contentSchema) {
|
|
161
161
|
validatorFunction = contentSchema
|
|
@@ -254,6 +254,16 @@ function wrapValidationError (result, dataVar, schemaErrorFormatter) {
|
|
|
254
254
|
return error
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/**
|
|
258
|
+
* simple function to retrieve the essence media type
|
|
259
|
+
* @param {string} header
|
|
260
|
+
* @returns {string} Mimetype string.
|
|
261
|
+
*/
|
|
262
|
+
function getEssenceMediaType (header) {
|
|
263
|
+
if (!header) return ''
|
|
264
|
+
return header.split(';', 1)[0].trim().toLowerCase()
|
|
265
|
+
}
|
|
266
|
+
|
|
257
267
|
module.exports = {
|
|
258
268
|
symbols: { bodySchema, querystringSchema, responseSchema, paramsSchema, headersSchema },
|
|
259
269
|
compileSchemasForValidation,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.1",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
"find-my-way": "^9.0.0",
|
|
210
210
|
"light-my-request": "^6.0.0",
|
|
211
211
|
"pino": "^9.0.0",
|
|
212
|
-
"process-warning": "^
|
|
212
|
+
"process-warning": "^5.0.0",
|
|
213
213
|
"rfdc": "^1.3.1",
|
|
214
|
-
"secure-json-parse": "^
|
|
214
|
+
"secure-json-parse": "^4.0.0",
|
|
215
215
|
"semver": "^7.6.0",
|
|
216
216
|
"toad-cache": "^3.7.0"
|
|
217
217
|
},
|
|
@@ -32,6 +32,5 @@ test('ensure the current error serializer is latest', { skip: !isPrepublish }, a
|
|
|
32
32
|
const current = await fs.promises.readFile(path.resolve('lib/error-serializer.js'))
|
|
33
33
|
|
|
34
34
|
// line break should not be a problem depends on system
|
|
35
|
-
|
|
36
|
-
t.assert.ok(current)
|
|
35
|
+
t.assert.strictEqual(unifyLineBreak(current), unifyLineBreak(code))
|
|
37
36
|
})
|