fastify 4.25.2 → 4.26.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/EXPENSE_POLICY.md +105 -0
- package/GOVERNANCE.md +2 -103
- package/LICENSE +1 -1
- package/README.md +13 -9
- package/SECURITY.md +2 -157
- package/SPONSORS.md +20 -0
- package/build/build-validation.js +3 -1
- package/docs/Guides/Ecosystem.md +29 -9
- package/docs/Guides/Getting-Started.md +16 -3
- package/docs/Guides/Style-Guide.md +7 -7
- package/docs/Reference/Decorators.md +1 -1
- package/docs/Reference/Errors.md +63 -1
- package/docs/Reference/Hooks.md +1 -1
- package/docs/Reference/Logging.md +3 -3
- package/docs/Reference/Reply.md +70 -1
- package/docs/Reference/Server.md +90 -0
- package/docs/Reference/Warnings.md +17 -2
- package/fastify.d.ts +3 -2
- package/fastify.js +25 -7
- package/lib/configValidator.js +62 -33
- package/lib/contentTypeParser.js +9 -2
- package/lib/error-handler.js +1 -1
- package/lib/error-serializer.js +30 -29
- package/lib/errors.js +6 -1
- package/lib/fourOhFour.js +4 -3
- package/lib/hooks.js +1 -5
- package/lib/reply.js +68 -10
- package/lib/reqIdGenFactory.js +5 -0
- package/lib/route.js +22 -6
- package/lib/schema-controller.js +37 -4
- package/lib/symbols.js +1 -0
- package/lib/warnings.js +6 -0
- package/package.json +18 -6
- package/test/async_hooks.test.js +69 -0
- package/test/findRoute.test.js +135 -0
- package/test/genReqId.test.js +392 -0
- package/test/hooks.on-listen.test.js +66 -14
- package/test/hooks.on-ready.test.js +1 -1
- package/test/internals/errors.test.js +17 -7
- package/test/internals/initialConfig.test.js +7 -3
- package/test/internals/reply.test.js +80 -5
- package/test/plugin.4.test.js +3 -3
- package/test/pretty-print.test.js +1 -1
- package/test/schema-serialization.test.js +41 -0
- package/test/schema-validation.test.js +115 -6
- package/test/serialize-response.test.js +187 -0
- package/test/types/instance.test-d.ts +14 -1
- package/test/types/reply.test-d.ts +4 -2
- package/test/types/request.test-d.ts +1 -1
- package/test/types/route.test-d.ts +15 -1
- package/test/useSemicolonDelimiter.test.js +113 -0
- package/test/web-api.test.js +208 -0
- package/types/instance.d.ts +23 -10
- package/types/reply.d.ts +4 -0
- package/types/request.d.ts +5 -4
|
@@ -19,7 +19,7 @@ const {
|
|
|
19
19
|
} = require('../../lib/symbols')
|
|
20
20
|
const fs = require('node:fs')
|
|
21
21
|
const path = require('node:path')
|
|
22
|
-
const { FSTDEP019,
|
|
22
|
+
const { FSTDEP010, FSTDEP019, FSTDEP020 } = require('../../lib/warnings')
|
|
23
23
|
|
|
24
24
|
const agent = new http.Agent({ keepAlive: false })
|
|
25
25
|
|
|
@@ -1598,7 +1598,40 @@ test('reply.getResponseTime() should return a number greater than 0 after the ti
|
|
|
1598
1598
|
fastify.inject({ method: 'GET', url: '/' })
|
|
1599
1599
|
})
|
|
1600
1600
|
|
|
1601
|
-
test('reply.getResponseTime() should return the time since a request started while inflight', t => {
|
|
1601
|
+
test('should emit deprecation warning when trying to use reply.getResponseTime() and should return the time since a request started while inflight', t => {
|
|
1602
|
+
t.plan(5)
|
|
1603
|
+
const fastify = Fastify()
|
|
1604
|
+
fastify.route({
|
|
1605
|
+
method: 'GET',
|
|
1606
|
+
url: '/',
|
|
1607
|
+
handler: (req, reply) => {
|
|
1608
|
+
reply.send('hello world')
|
|
1609
|
+
}
|
|
1610
|
+
})
|
|
1611
|
+
|
|
1612
|
+
process.removeAllListeners('warning')
|
|
1613
|
+
process.on('warning', onWarning)
|
|
1614
|
+
function onWarning (warning) {
|
|
1615
|
+
t.equal(warning.name, 'DeprecationWarning')
|
|
1616
|
+
t.equal(warning.code, FSTDEP020.code)
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
fastify.addHook('preValidation', (req, reply, done) => {
|
|
1620
|
+
t.equal(reply.getResponseTime(), reply.getResponseTime())
|
|
1621
|
+
done()
|
|
1622
|
+
})
|
|
1623
|
+
|
|
1624
|
+
fastify.inject({ method: 'GET', url: '/' }, (err, res) => {
|
|
1625
|
+
t.error(err)
|
|
1626
|
+
t.pass()
|
|
1627
|
+
|
|
1628
|
+
process.removeListener('warning', onWarning)
|
|
1629
|
+
})
|
|
1630
|
+
|
|
1631
|
+
FSTDEP020.emitted = false
|
|
1632
|
+
})
|
|
1633
|
+
|
|
1634
|
+
test('reply.getResponseTime() should return the same value after a request is finished', t => {
|
|
1602
1635
|
t.plan(1)
|
|
1603
1636
|
const fastify = Fastify()
|
|
1604
1637
|
fastify.route({
|
|
@@ -1609,19 +1642,61 @@ test('reply.getResponseTime() should return the time since a request started whi
|
|
|
1609
1642
|
}
|
|
1610
1643
|
})
|
|
1611
1644
|
|
|
1645
|
+
fastify.addHook('onResponse', (req, reply) => {
|
|
1646
|
+
t.equal(reply.getResponseTime(), reply.getResponseTime())
|
|
1647
|
+
t.end()
|
|
1648
|
+
})
|
|
1649
|
+
|
|
1650
|
+
fastify.inject({ method: 'GET', url: '/' })
|
|
1651
|
+
})
|
|
1652
|
+
|
|
1653
|
+
test('reply.elapsedTime should return a number greater than 0 after the timer is initialised on the reply by setting up response listeners', t => {
|
|
1654
|
+
t.plan(1)
|
|
1655
|
+
const fastify = Fastify()
|
|
1656
|
+
fastify.route({
|
|
1657
|
+
method: 'GET',
|
|
1658
|
+
url: '/',
|
|
1659
|
+
handler: (req, reply) => {
|
|
1660
|
+
reply.send('hello world')
|
|
1661
|
+
}
|
|
1662
|
+
})
|
|
1663
|
+
|
|
1664
|
+
fastify.addHook('onResponse', (req, reply) => {
|
|
1665
|
+
t.ok(reply.elapsedTime > 0)
|
|
1666
|
+
t.end()
|
|
1667
|
+
})
|
|
1668
|
+
|
|
1669
|
+
fastify.inject({ method: 'GET', url: '/' })
|
|
1670
|
+
})
|
|
1671
|
+
|
|
1672
|
+
test('reply.elapsedTime should return the time since a request started while inflight', t => {
|
|
1673
|
+
t.plan(1)
|
|
1674
|
+
const fastify = Fastify()
|
|
1675
|
+
fastify.route({
|
|
1676
|
+
method: 'GET',
|
|
1677
|
+
url: '/',
|
|
1678
|
+
handler: (req, reply) => {
|
|
1679
|
+
reply.send('hello world')
|
|
1680
|
+
}
|
|
1681
|
+
})
|
|
1682
|
+
|
|
1683
|
+
let preValidationElapsedTime
|
|
1684
|
+
|
|
1612
1685
|
fastify.addHook('preValidation', (req, reply, done) => {
|
|
1613
|
-
|
|
1686
|
+
preValidationElapsedTime = reply.elapsedTime
|
|
1687
|
+
|
|
1614
1688
|
done()
|
|
1615
1689
|
})
|
|
1616
1690
|
|
|
1617
1691
|
fastify.addHook('onResponse', (req, reply) => {
|
|
1692
|
+
t.ok(reply.elapsedTime > preValidationElapsedTime)
|
|
1618
1693
|
t.end()
|
|
1619
1694
|
})
|
|
1620
1695
|
|
|
1621
1696
|
fastify.inject({ method: 'GET', url: '/' })
|
|
1622
1697
|
})
|
|
1623
1698
|
|
|
1624
|
-
test('reply.
|
|
1699
|
+
test('reply.elapsedTime should return the same value after a request is finished', t => {
|
|
1625
1700
|
t.plan(1)
|
|
1626
1701
|
const fastify = Fastify()
|
|
1627
1702
|
fastify.route({
|
|
@@ -1633,7 +1708,7 @@ test('reply.getResponseTime() should return the same value after a request is fi
|
|
|
1633
1708
|
})
|
|
1634
1709
|
|
|
1635
1710
|
fastify.addHook('onResponse', (req, reply) => {
|
|
1636
|
-
t.equal(reply.
|
|
1711
|
+
t.equal(reply.elapsedTime, reply.elapsedTime)
|
|
1637
1712
|
t.end()
|
|
1638
1713
|
})
|
|
1639
1714
|
|
package/test/plugin.4.test.js
CHANGED
|
@@ -22,7 +22,7 @@ test('pluginTimeout', t => {
|
|
|
22
22
|
"fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // to no call done on purpose'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
23
23
|
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
24
24
|
t.ok(err.cause)
|
|
25
|
-
t.equal(err.cause.code, '
|
|
25
|
+
t.equal(err.cause.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT')
|
|
26
26
|
})
|
|
27
27
|
})
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ test('pluginTimeout - named function', t => {
|
|
|
40
40
|
"fastify-plugin: Plugin did not start in time: 'nameFunction'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
41
41
|
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
42
42
|
t.ok(err.cause)
|
|
43
|
-
t.equal(err.cause.code, '
|
|
43
|
+
t.equal(err.cause.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT')
|
|
44
44
|
})
|
|
45
45
|
})
|
|
46
46
|
|
|
@@ -60,7 +60,7 @@ test('pluginTimeout default', t => {
|
|
|
60
60
|
"fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // default time elapsed without calling done'. You may have forgotten to call 'done' function or to resolve a Promise")
|
|
61
61
|
t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
|
62
62
|
t.ok(err.cause)
|
|
63
|
-
t.equal(err.cause.code, '
|
|
63
|
+
t.equal(err.cause.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT')
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
t.teardown(clock.uninstall)
|
|
@@ -220,7 +220,7 @@ test('pretty print - empty plugins', t => {
|
|
|
220
220
|
fastify.ready(() => {
|
|
221
221
|
const tree = fastify.printPlugins()
|
|
222
222
|
t.equal(typeof tree, 'string')
|
|
223
|
-
t.match(tree,
|
|
223
|
+
t.match(tree, /root \d+ ms\n└── bound _after \d+ ms/m)
|
|
224
224
|
})
|
|
225
225
|
})
|
|
226
226
|
|
|
@@ -593,6 +593,47 @@ test('Custom setSerializerCompiler returns bad serialized output', t => {
|
|
|
593
593
|
})
|
|
594
594
|
})
|
|
595
595
|
|
|
596
|
+
test('Custom setSerializerCompiler with addSchema', t => {
|
|
597
|
+
t.plan(6)
|
|
598
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
599
|
+
|
|
600
|
+
const outSchema = {
|
|
601
|
+
$id: 'test',
|
|
602
|
+
type: 'object',
|
|
603
|
+
whatever: 'need to be parsed by the custom serializer'
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {
|
|
607
|
+
t.equal(method, 'GET')
|
|
608
|
+
t.equal(url, '/foo/:id')
|
|
609
|
+
t.equal(httpStatus, '200')
|
|
610
|
+
t.same(schema, outSchema)
|
|
611
|
+
return _data => JSON.stringify({ id: 2 })
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
// provoke re-creation of serialization compiler in setupSerializer
|
|
615
|
+
fastify.addSchema({ $id: 'dummy', type: 'object' })
|
|
616
|
+
|
|
617
|
+
fastify.get('/foo/:id', {
|
|
618
|
+
handler (_req, reply) {
|
|
619
|
+
reply.send({ id: 1 })
|
|
620
|
+
},
|
|
621
|
+
schema: {
|
|
622
|
+
response: {
|
|
623
|
+
200: outSchema
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
fastify.inject({
|
|
629
|
+
method: 'GET',
|
|
630
|
+
url: '/foo/123'
|
|
631
|
+
}, (err, res) => {
|
|
632
|
+
t.error(err)
|
|
633
|
+
t.equal(res.payload, JSON.stringify({ id: 2 }))
|
|
634
|
+
})
|
|
635
|
+
})
|
|
636
|
+
|
|
596
637
|
test('Custom serializer per route', async t => {
|
|
597
638
|
const fastify = Fastify()
|
|
598
639
|
|
|
@@ -106,7 +106,7 @@ test('Basic validation test', t => {
|
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
test('External AJV instance', t => {
|
|
109
|
-
t.plan(
|
|
109
|
+
t.plan(5)
|
|
110
110
|
|
|
111
111
|
const fastify = Fastify()
|
|
112
112
|
const ajv = new AJV()
|
|
@@ -118,6 +118,7 @@ test('External AJV instance', t => {
|
|
|
118
118
|
fastify.addSchema(schemaBRefToA)
|
|
119
119
|
|
|
120
120
|
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
|
121
|
+
t.pass('custom validator compiler called')
|
|
121
122
|
return ajv.compile(schema)
|
|
122
123
|
})
|
|
123
124
|
|
|
@@ -151,7 +152,7 @@ test('External AJV instance', t => {
|
|
|
151
152
|
})
|
|
152
153
|
|
|
153
154
|
test('Encapsulation', t => {
|
|
154
|
-
t.plan(
|
|
155
|
+
t.plan(21)
|
|
155
156
|
|
|
156
157
|
const fastify = Fastify()
|
|
157
158
|
const ajv = new AJV()
|
|
@@ -164,6 +165,7 @@ test('Encapsulation', t => {
|
|
|
164
165
|
|
|
165
166
|
fastify.register((instance, opts, done) => {
|
|
166
167
|
const validator = ({ schema, method, url, httpPart }) => {
|
|
168
|
+
t.pass('custom validator compiler called')
|
|
167
169
|
return ajv.compile(schema)
|
|
168
170
|
}
|
|
169
171
|
instance.setValidatorCompiler(validator)
|
|
@@ -271,7 +273,7 @@ test('Encapsulation', t => {
|
|
|
271
273
|
})
|
|
272
274
|
|
|
273
275
|
test('Triple $ref with a simple $id', t => {
|
|
274
|
-
t.plan(
|
|
276
|
+
t.plan(7)
|
|
275
277
|
|
|
276
278
|
const fastify = Fastify()
|
|
277
279
|
const ajv = new AJV()
|
|
@@ -285,6 +287,7 @@ test('Triple $ref with a simple $id', t => {
|
|
|
285
287
|
fastify.addSchema(schemaCRefToB)
|
|
286
288
|
|
|
287
289
|
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
|
290
|
+
t.pass('custom validator compiler called')
|
|
288
291
|
return ajv.compile(schema)
|
|
289
292
|
})
|
|
290
293
|
|
|
@@ -1024,19 +1027,125 @@ test("The same $id in route's schema must not overwrite others", t => {
|
|
|
1024
1027
|
|
|
1025
1028
|
test('Custom validator compiler should not mutate schema', async t => {
|
|
1026
1029
|
t.plan(2)
|
|
1027
|
-
class Headers {}
|
|
1030
|
+
class Headers { }
|
|
1028
1031
|
const fastify = Fastify()
|
|
1029
1032
|
|
|
1030
1033
|
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
|
1031
1034
|
t.type(schema, Headers)
|
|
1032
|
-
return () => {}
|
|
1035
|
+
return () => { }
|
|
1033
1036
|
})
|
|
1034
1037
|
|
|
1035
1038
|
fastify.get('/', {
|
|
1036
1039
|
schema: {
|
|
1037
1040
|
headers: new Headers()
|
|
1038
1041
|
}
|
|
1039
|
-
}, () => {})
|
|
1042
|
+
}, () => { })
|
|
1043
|
+
|
|
1044
|
+
await fastify.ready()
|
|
1045
|
+
})
|
|
1046
|
+
|
|
1047
|
+
test('Custom validator builder override by custom validator compiler', async t => {
|
|
1048
|
+
t.plan(3)
|
|
1049
|
+
const ajvDefaults = {
|
|
1050
|
+
removeAdditional: true,
|
|
1051
|
+
coerceTypes: true,
|
|
1052
|
+
allErrors: true
|
|
1053
|
+
}
|
|
1054
|
+
const ajv1 = new AJV(ajvDefaults).addKeyword({ keyword: 'extended_one', type: 'object', validator: () => true })
|
|
1055
|
+
const ajv2 = new AJV(ajvDefaults).addKeyword({ keyword: 'extended_two', type: 'object', validator: () => true })
|
|
1056
|
+
const fastify = Fastify({ schemaController: { compilersFactory: { buildValidator: () => (routeSchemaDef) => ajv1.compile(routeSchemaDef.schema) } } })
|
|
1057
|
+
|
|
1058
|
+
fastify.setValidatorCompiler((routeSchemaDef) => ajv2.compile(routeSchemaDef.schema))
|
|
1059
|
+
|
|
1060
|
+
fastify.post('/two/:id', {
|
|
1061
|
+
schema: {
|
|
1062
|
+
params: {
|
|
1063
|
+
type: 'object',
|
|
1064
|
+
extended_two: true,
|
|
1065
|
+
properties: {
|
|
1066
|
+
id: { type: 'number' }
|
|
1067
|
+
},
|
|
1068
|
+
required: ['id']
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
handler: (req, _reply) => {
|
|
1072
|
+
t.same(typeof req.params.id, 'number')
|
|
1073
|
+
t.same(req.params.id, 43)
|
|
1074
|
+
return 'ok'
|
|
1075
|
+
}
|
|
1076
|
+
})
|
|
1040
1077
|
|
|
1041
1078
|
await fastify.ready()
|
|
1079
|
+
|
|
1080
|
+
const two = await fastify.inject({
|
|
1081
|
+
method: 'POST',
|
|
1082
|
+
url: '/two/43'
|
|
1083
|
+
})
|
|
1084
|
+
t.equal(two.statusCode, 200)
|
|
1085
|
+
})
|
|
1086
|
+
|
|
1087
|
+
test('Custom validator builder override by custom validator compiler in child instance', async t => {
|
|
1088
|
+
t.plan(6)
|
|
1089
|
+
const ajvDefaults = {
|
|
1090
|
+
removeAdditional: true,
|
|
1091
|
+
coerceTypes: true,
|
|
1092
|
+
allErrors: true
|
|
1093
|
+
}
|
|
1094
|
+
const ajv1 = new AJV(ajvDefaults).addKeyword({ keyword: 'extended_one', type: 'object', validator: () => true })
|
|
1095
|
+
const ajv2 = new AJV(ajvDefaults).addKeyword({ keyword: 'extended_two', type: 'object', validator: () => true })
|
|
1096
|
+
const fastify = Fastify({ schemaController: { compilersFactory: { buildValidator: () => (routeSchemaDef) => ajv1.compile(routeSchemaDef.schema) } } })
|
|
1097
|
+
|
|
1098
|
+
fastify.register((embedded, _opts, done) => {
|
|
1099
|
+
embedded.setValidatorCompiler((routeSchemaDef) => ajv2.compile(routeSchemaDef.schema))
|
|
1100
|
+
embedded.post('/two/:id', {
|
|
1101
|
+
schema: {
|
|
1102
|
+
params: {
|
|
1103
|
+
type: 'object',
|
|
1104
|
+
extended_two: true,
|
|
1105
|
+
properties: {
|
|
1106
|
+
id: { type: 'number' }
|
|
1107
|
+
},
|
|
1108
|
+
required: ['id']
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
handler: (req, _reply) => {
|
|
1112
|
+
t.same(typeof req.params.id, 'number')
|
|
1113
|
+
t.same(req.params.id, 43)
|
|
1114
|
+
return 'ok'
|
|
1115
|
+
}
|
|
1116
|
+
})
|
|
1117
|
+
done()
|
|
1118
|
+
})
|
|
1119
|
+
|
|
1120
|
+
fastify.post('/one/:id', {
|
|
1121
|
+
schema: {
|
|
1122
|
+
params: {
|
|
1123
|
+
type: 'object',
|
|
1124
|
+
extended_one: true,
|
|
1125
|
+
properties: {
|
|
1126
|
+
id: { type: 'number' }
|
|
1127
|
+
},
|
|
1128
|
+
required: ['id']
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
handler: (req, _reply) => {
|
|
1132
|
+
t.same(typeof req.params.id, 'number')
|
|
1133
|
+
t.same(req.params.id, 42)
|
|
1134
|
+
return 'ok'
|
|
1135
|
+
}
|
|
1136
|
+
})
|
|
1137
|
+
|
|
1138
|
+
await fastify.ready()
|
|
1139
|
+
|
|
1140
|
+
const one = await fastify.inject({
|
|
1141
|
+
method: 'POST',
|
|
1142
|
+
url: '/one/42'
|
|
1143
|
+
})
|
|
1144
|
+
t.equal(one.statusCode, 200)
|
|
1145
|
+
|
|
1146
|
+
const two = await fastify.inject({
|
|
1147
|
+
method: 'POST',
|
|
1148
|
+
url: '/two/43'
|
|
1149
|
+
})
|
|
1150
|
+
t.equal(two.statusCode, 200)
|
|
1042
1151
|
})
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const t = require('tap')
|
|
4
|
+
const test = t.test
|
|
5
|
+
const { S } = require('fluent-json-schema')
|
|
6
|
+
const Fastify = require('../fastify')
|
|
7
|
+
const sjson = require('secure-json-parse')
|
|
8
|
+
|
|
9
|
+
const BadRequestSchema = S.object()
|
|
10
|
+
.prop('statusCode', S.number())
|
|
11
|
+
.prop('error', S.string())
|
|
12
|
+
.prop('message', S.string())
|
|
13
|
+
|
|
14
|
+
const InternalServerErrorSchema = S.object()
|
|
15
|
+
.prop('statusCode', S.number())
|
|
16
|
+
.prop('error', S.string())
|
|
17
|
+
.prop('message', S.string())
|
|
18
|
+
|
|
19
|
+
const NotFoundSchema = S.object()
|
|
20
|
+
.prop('statusCode', S.number())
|
|
21
|
+
.prop('error', S.string())
|
|
22
|
+
.prop('message', S.string())
|
|
23
|
+
|
|
24
|
+
const options = {
|
|
25
|
+
schema: {
|
|
26
|
+
body: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
id: { type: 'string' }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
response: {
|
|
33
|
+
200: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
id: { type: 'string' }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
400: {
|
|
40
|
+
description: 'Bad Request',
|
|
41
|
+
content: {
|
|
42
|
+
'application/json': {
|
|
43
|
+
schema: BadRequestSchema.valueOf()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
404: {
|
|
48
|
+
description: 'Resource not found',
|
|
49
|
+
content: {
|
|
50
|
+
'application/json': {
|
|
51
|
+
schema: NotFoundSchema.valueOf(),
|
|
52
|
+
example: {
|
|
53
|
+
statusCode: 404,
|
|
54
|
+
error: 'Not Found',
|
|
55
|
+
message: 'Not Found'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
500: {
|
|
61
|
+
description: 'Internal Server Error',
|
|
62
|
+
content: {
|
|
63
|
+
'application/json': {
|
|
64
|
+
schema: InternalServerErrorSchema.valueOf(),
|
|
65
|
+
example: {
|
|
66
|
+
message: 'Internal Server Error'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const handler = (request, reply) => {
|
|
76
|
+
if (request.body.id === '400') {
|
|
77
|
+
return reply.status(400).send({
|
|
78
|
+
statusCode: 400,
|
|
79
|
+
error: 'Bad Request',
|
|
80
|
+
message: 'Custom message',
|
|
81
|
+
extra: 'This should not be in the response'
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (request.body.id === '404') {
|
|
86
|
+
return reply.status(404).send({
|
|
87
|
+
statusCode: 404,
|
|
88
|
+
error: 'Not Found',
|
|
89
|
+
message: 'Custom Not Found',
|
|
90
|
+
extra: 'This should not be in the response'
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (request.body.id === '500') {
|
|
95
|
+
reply.status(500).send({
|
|
96
|
+
statusCode: 500,
|
|
97
|
+
error: 'Internal Server Error',
|
|
98
|
+
message: 'Custom Internal Server Error',
|
|
99
|
+
extra: 'This should not be in the response'
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
reply.send({
|
|
104
|
+
id: request.body.id,
|
|
105
|
+
extra: 'This should not be in the response'
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
test('serialize the response for a Bad Request error, as defined on the schema', async t => {
|
|
110
|
+
t.plan(2)
|
|
111
|
+
|
|
112
|
+
const fastify = Fastify({})
|
|
113
|
+
|
|
114
|
+
fastify.post('/', options, handler)
|
|
115
|
+
const response = await fastify.inject({
|
|
116
|
+
method: 'POST',
|
|
117
|
+
url: '/'
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
t.equal(response.statusCode, 400)
|
|
121
|
+
t.same(sjson(response.body), {
|
|
122
|
+
statusCode: 400,
|
|
123
|
+
error: 'Bad Request',
|
|
124
|
+
message: 'body must be object'
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test('serialize the response for a Not Found error, as defined on the schema', async t => {
|
|
129
|
+
t.plan(2)
|
|
130
|
+
|
|
131
|
+
const fastify = Fastify({})
|
|
132
|
+
|
|
133
|
+
fastify.post('/', options, handler)
|
|
134
|
+
|
|
135
|
+
const response = await fastify.inject({
|
|
136
|
+
method: 'POST',
|
|
137
|
+
url: '/',
|
|
138
|
+
body: { id: '404' }
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
t.equal(response.statusCode, 404)
|
|
142
|
+
t.same(sjson(response.body), {
|
|
143
|
+
statusCode: 404,
|
|
144
|
+
error: 'Not Found',
|
|
145
|
+
message: 'Custom Not Found'
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('serialize the response for a Internal Server Error error, as defined on the schema', async t => {
|
|
150
|
+
t.plan(2)
|
|
151
|
+
|
|
152
|
+
const fastify = Fastify({})
|
|
153
|
+
|
|
154
|
+
fastify.post('/', options, handler)
|
|
155
|
+
|
|
156
|
+
const response = await fastify.inject({
|
|
157
|
+
method: 'POST',
|
|
158
|
+
url: '/',
|
|
159
|
+
body: { id: '500' }
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
t.equal(response.statusCode, 500)
|
|
163
|
+
t.same(sjson(response.body), {
|
|
164
|
+
statusCode: 500,
|
|
165
|
+
error: 'Internal Server Error',
|
|
166
|
+
message: 'Custom Internal Server Error'
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('serialize the success response, as defined on the schema', async t => {
|
|
171
|
+
t.plan(2)
|
|
172
|
+
|
|
173
|
+
const fastify = Fastify({})
|
|
174
|
+
|
|
175
|
+
fastify.post('/', options, handler)
|
|
176
|
+
|
|
177
|
+
const response = await fastify.inject({
|
|
178
|
+
method: 'POST',
|
|
179
|
+
url: '/',
|
|
180
|
+
body: { id: 'test' }
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
t.equal(response.statusCode, 200)
|
|
184
|
+
t.same(sjson(response.body), {
|
|
185
|
+
id: 'test'
|
|
186
|
+
})
|
|
187
|
+
})
|
|
@@ -51,6 +51,18 @@ expectAssignable<FastifyInstance>(
|
|
|
51
51
|
})
|
|
52
52
|
)
|
|
53
53
|
|
|
54
|
+
expectAssignable<FastifyInstance>(
|
|
55
|
+
server.setGenReqId(function (req) {
|
|
56
|
+
expectType<RawRequestDefaultExpression>(req)
|
|
57
|
+
return 'foo'
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
function fastifySetGenReqId (req: RawRequestDefaultExpression) {
|
|
62
|
+
return 'foo'
|
|
63
|
+
}
|
|
64
|
+
server.setGenReqId(fastifySetGenReqId)
|
|
65
|
+
|
|
54
66
|
function fastifyErrorHandler (this: FastifyInstance, error: FastifyError) {}
|
|
55
67
|
server.setErrorHandler(fastifyErrorHandler)
|
|
56
68
|
|
|
@@ -330,7 +342,8 @@ type InitialConfig = Readonly<{
|
|
|
330
342
|
pluginTimeout?: number,
|
|
331
343
|
requestIdHeader?: string | false,
|
|
332
344
|
requestIdLogLabel?: string,
|
|
333
|
-
http2SessionTimeout?: number
|
|
345
|
+
http2SessionTimeout?: number,
|
|
346
|
+
useSemicolonDelimiter?: boolean
|
|
334
347
|
}>
|
|
335
348
|
|
|
336
349
|
expectType<InitialConfig>(fastify().initialConfig)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'buffer'
|
|
2
|
-
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
2
|
+
import { expectAssignable, expectDeprecated, expectError, expectType } from 'tsd'
|
|
3
3
|
import fastify, { FastifyReplyContext, FastifyReply, FastifyRequest, FastifySchema, FastifySchemaCompiler, FastifyTypeProviderDefault, RawRequestDefaultExpression, RouteHandler, RouteHandlerMethod } from '../../fastify'
|
|
4
4
|
import { FastifyInstance } from '../../types/instance'
|
|
5
5
|
import { FastifyLoggerInstance } from '../../types/logger'
|
|
@@ -19,6 +19,7 @@ const getHandler: RouteHandlerMethod = function (_request, reply) {
|
|
|
19
19
|
expectType<<Code extends number>(statusCode: Code) => DefaultFastifyReplyWithCode<Code>>(reply.code)
|
|
20
20
|
expectType<<Code extends number>(statusCode: Code) => DefaultFastifyReplyWithCode<Code>>(reply.status)
|
|
21
21
|
expectType<(payload?: unknown) => FastifyReply>(reply.code(100 as number).send)
|
|
22
|
+
expectType<number>(reply.elapsedTime)
|
|
22
23
|
expectType<number>(reply.statusCode)
|
|
23
24
|
expectType<boolean>(reply.sent)
|
|
24
25
|
expectType<((payload?: unknown) => FastifyReply)>(reply.send)
|
|
@@ -31,7 +32,8 @@ const getHandler: RouteHandlerMethod = function (_request, reply) {
|
|
|
31
32
|
expectType<{(statusCode: number, url: string): FastifyReply; (url: string): FastifyReply }>(reply.redirect)
|
|
32
33
|
expectType<() => FastifyReply>(reply.hijack)
|
|
33
34
|
expectType<() => void>(reply.callNotFound)
|
|
34
|
-
|
|
35
|
+
// Test reply.getResponseTime() deprecation
|
|
36
|
+
expectDeprecated(reply.getResponseTime)
|
|
35
37
|
expectType<(contentType: string) => FastifyReply>(reply.type)
|
|
36
38
|
expectType<(fn: (payload: any) => string) => FastifyReply>(reply.serializer)
|
|
37
39
|
expectType<(payload: any) => string | ArrayBuffer | Buffer>(reply.serialize)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import pino from 'pino'
|
|
2
1
|
import { expectAssignable, expectType } from 'tsd'
|
|
3
2
|
import fastify, {
|
|
4
3
|
ContextConfigDefault,
|
|
@@ -83,6 +82,7 @@ const getHandler: RouteHandler = function (request, _reply) {
|
|
|
83
82
|
expectType<FastifySchema>(request.routeSchema)
|
|
84
83
|
expectType<FastifySchema>(request.routeOptions.schema)
|
|
85
84
|
expectType<RouteHandlerMethod>(request.routeOptions.handler)
|
|
85
|
+
expectType<string | undefined>(request.routeOptions.url)
|
|
86
86
|
|
|
87
87
|
expectType<RequestHeadersDefault & RawRequestDefaultExpression['headers']>(request.headers)
|
|
88
88
|
request.headers = {}
|
|
@@ -3,7 +3,8 @@ import * as http from 'http'
|
|
|
3
3
|
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
4
4
|
import fastify, { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from '../../fastify'
|
|
5
5
|
import { RequestPayload } from '../../types/hooks'
|
|
6
|
-
import {
|
|
6
|
+
import { FindMyWayFindResult } from '../../types/instance'
|
|
7
|
+
import { HTTPMethods, RawServerDefault } from '../../types/utils'
|
|
7
8
|
|
|
8
9
|
/*
|
|
9
10
|
* Testing Fastify HTTP Routes and Route Shorthands.
|
|
@@ -453,6 +454,19 @@ expectType<boolean>(fastify().hasRoute({
|
|
|
453
454
|
}
|
|
454
455
|
}))
|
|
455
456
|
|
|
457
|
+
expectType<Omit<FindMyWayFindResult<RawServerDefault>, 'store'>>(
|
|
458
|
+
fastify().findRoute({
|
|
459
|
+
url: '/',
|
|
460
|
+
method: 'get'
|
|
461
|
+
})
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
// we should not expose store
|
|
465
|
+
expectError(fastify().findRoute({
|
|
466
|
+
url: '/',
|
|
467
|
+
method: 'get'
|
|
468
|
+
}).store)
|
|
469
|
+
|
|
456
470
|
expectType<FastifyInstance>(fastify().route({
|
|
457
471
|
url: '/',
|
|
458
472
|
method: 'get',
|