fastify 3.23.0 → 3.25.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.
- package/README.md +5 -4
- package/build/sync-version.js +11 -0
- package/docs/{Benchmarking.md → Guides/Benchmarking.md} +14 -5
- package/docs/Guides/Ecosystem.md +508 -0
- package/docs/{Fluent-Schema.md → Guides/Fluent-Schema.md} +16 -7
- package/docs/{Getting-Started.md → Guides/Getting-Started.md} +191 -57
- package/docs/Guides/Index.md +30 -4
- package/docs/{Migration-Guide-V3.md → Guides/Migration-Guide-V3.md} +43 -37
- package/docs/{Plugins-Guide.md → Guides/Plugins-Guide.md} +196 -82
- package/docs/{Recommendations.md → Guides/Recommendations.md} +17 -10
- package/docs/{Serverless.md → Guides/Serverless.md} +200 -42
- package/docs/Guides/Style-Guide.md +246 -0
- package/docs/{Testing.md → Guides/Testing.md} +25 -11
- package/docs/Guides/Write-Plugin.md +102 -0
- package/docs/{ContentTypeParser.md → Reference/ContentTypeParser.md} +68 -30
- package/docs/{Decorators.md → Reference/Decorators.md} +52 -47
- package/docs/{Encapsulation.md → Reference/Encapsulation.md} +3 -3
- package/docs/{Errors.md → Reference/Errors.md} +77 -47
- package/docs/{HTTP2.md → Reference/HTTP2.md} +13 -13
- package/docs/{Hooks.md → Reference/Hooks.md} +148 -69
- package/docs/Reference/Index.md +71 -0
- package/docs/{LTS.md → Reference/LTS.md} +31 -32
- package/docs/{Lifecycle.md → Reference/Lifecycle.md} +15 -7
- package/docs/{Logging.md → Reference/Logging.md} +68 -28
- package/docs/Reference/Middleware.md +78 -0
- package/docs/{Plugins.md → Reference/Plugins.md} +91 -34
- package/docs/{Reply.md → Reference/Reply.md} +205 -94
- package/docs/{Request.md → Reference/Request.md} +32 -16
- package/docs/{Routes.md → Reference/Routes.md} +243 -111
- package/docs/{Server.md → Reference/Server.md} +516 -267
- package/docs/{TypeScript.md → Reference/TypeScript.md} +447 -187
- package/docs/{Validation-and-Serialization.md → Reference/Validation-and-Serialization.md} +178 -86
- package/docs/index.md +24 -0
- package/examples/typescript-server.ts +1 -1
- package/fastify.js +4 -23
- package/lib/decorate.js +6 -3
- package/lib/logger.js +2 -2
- package/lib/pluginUtils.js +1 -3
- package/lib/reply.js +4 -1
- package/lib/route.js +1 -1
- package/lib/schema-controller.js +11 -2
- package/lib/server.js +9 -8
- package/lib/symbols.js +1 -0
- package/package.json +10 -4
- package/test/bundler/webpack/bundler-test.js +2 -6
- package/test/constrained-routes.test.js +220 -0
- package/test/custom-parser.test.js +11 -2
- package/test/decorator.test.js +24 -0
- package/test/handler-context.test.js +11 -4
- package/test/http2/closing.test.js +14 -5
- package/test/internals/logger.test.js +20 -0
- package/test/internals/reply.test.js +42 -0
- package/test/internals/version.test.js +6 -34
- package/test/listen.test.js +36 -22
- package/test/logger.test.js +16 -0
- package/test/maxRequestsPerSocket.test.js +10 -0
- package/test/request-error.test.js +2 -8
- package/test/requestTimeout.test.js +4 -1
- package/test/route-hooks.test.js +55 -0
- package/test/router-options.test.js +10 -1
- package/test/schema-feature.test.js +461 -0
- package/test/stream.test.js +14 -3
- package/test/trust-proxy.test.js +15 -7
- package/test/types/instance.test-d.ts +52 -1
- package/test/types/request.test-d.ts +7 -1
- package/test/types/route.test-d.ts +21 -0
- package/types/instance.d.ts +11 -6
- package/types/request.d.ts +4 -1
- package/types/route.d.ts +1 -1
- package/docs/Ecosystem.md +0 -211
- package/docs/Middleware.md +0 -53
- package/docs/Style-Guide.md +0 -185
- package/docs/Write-Plugin.md +0 -58
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const Fastify = require('..')
|
|
5
5
|
const fp = require('fastify-plugin')
|
|
6
|
+
const Ajv = require('ajv')
|
|
6
7
|
const { kSchemaController } = require('../lib/symbols.js')
|
|
7
8
|
|
|
8
9
|
const echoParams = (req, reply) => { reply.send(req.params) }
|
|
@@ -1289,3 +1290,463 @@ test('setSchemaController per instance', t => {
|
|
|
1289
1290
|
|
|
1290
1291
|
fastify.ready(err => { t.error(err) })
|
|
1291
1292
|
})
|
|
1293
|
+
|
|
1294
|
+
test('setSchemaController: Inherits correctly parent schemas with a customized validator instance', async t => {
|
|
1295
|
+
t.plan(5)
|
|
1296
|
+
const customAjv = new Ajv({ coerceTypes: false })
|
|
1297
|
+
const server = Fastify()
|
|
1298
|
+
const someSchema = {
|
|
1299
|
+
$id: 'some',
|
|
1300
|
+
type: 'array',
|
|
1301
|
+
items: {
|
|
1302
|
+
type: 'string'
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
const errorResponseSchema = {
|
|
1306
|
+
$id: 'error_response',
|
|
1307
|
+
type: 'object',
|
|
1308
|
+
properties: {
|
|
1309
|
+
statusCode: {
|
|
1310
|
+
type: 'integer'
|
|
1311
|
+
},
|
|
1312
|
+
message: {
|
|
1313
|
+
type: 'string'
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
server.addSchema(someSchema)
|
|
1319
|
+
server.addSchema(errorResponseSchema)
|
|
1320
|
+
|
|
1321
|
+
server.register((instance, _, done) => {
|
|
1322
|
+
instance.setSchemaController({
|
|
1323
|
+
compilersFactory: {
|
|
1324
|
+
buildValidator: function (externalSchemas) {
|
|
1325
|
+
const schemaKeys = Object.keys(externalSchemas)
|
|
1326
|
+
t.equal(schemaKeys.length, 2, 'Contains same number of schemas')
|
|
1327
|
+
t.hasStrict([someSchema, errorResponseSchema], Object.values(externalSchemas), 'Contains expected schemas')
|
|
1328
|
+
for (const key of schemaKeys) {
|
|
1329
|
+
if (customAjv.getSchema(key) == null) {
|
|
1330
|
+
customAjv.addSchema(externalSchemas[key], key)
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return function validatorCompiler ({ schema }) {
|
|
1334
|
+
return customAjv.compile(schema)
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
})
|
|
1339
|
+
|
|
1340
|
+
instance.get(
|
|
1341
|
+
'/',
|
|
1342
|
+
{
|
|
1343
|
+
schema: {
|
|
1344
|
+
querystring: {
|
|
1345
|
+
msg: {
|
|
1346
|
+
$ref: 'some#'
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
response: {
|
|
1350
|
+
'4xx': {
|
|
1351
|
+
$ref: 'error_response#'
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
(req, reply) => {
|
|
1357
|
+
reply.send({ noop: 'noop' })
|
|
1358
|
+
}
|
|
1359
|
+
)
|
|
1360
|
+
|
|
1361
|
+
done()
|
|
1362
|
+
})
|
|
1363
|
+
|
|
1364
|
+
const res = await server.inject({
|
|
1365
|
+
method: 'GET',
|
|
1366
|
+
url: '/',
|
|
1367
|
+
query: {
|
|
1368
|
+
msg: 'string'
|
|
1369
|
+
}
|
|
1370
|
+
})
|
|
1371
|
+
const json = res.json()
|
|
1372
|
+
|
|
1373
|
+
t.equal(json.message, 'querystring.msg should be array')
|
|
1374
|
+
t.equal(json.statusCode, 400)
|
|
1375
|
+
t.equal(res.statusCode, 400, 'Should not coearce the string into array')
|
|
1376
|
+
})
|
|
1377
|
+
|
|
1378
|
+
test('setSchemaController: Inherits buildSerializer from parent if not present within the instance', async t => {
|
|
1379
|
+
t.plan(6)
|
|
1380
|
+
const customAjv = new Ajv({ coerceTypes: false })
|
|
1381
|
+
const someSchema = {
|
|
1382
|
+
$id: 'some',
|
|
1383
|
+
type: 'array',
|
|
1384
|
+
items: {
|
|
1385
|
+
type: 'string'
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const errorResponseSchema = {
|
|
1389
|
+
$id: 'error_response',
|
|
1390
|
+
type: 'object',
|
|
1391
|
+
properties: {
|
|
1392
|
+
statusCode: {
|
|
1393
|
+
type: 'integer'
|
|
1394
|
+
},
|
|
1395
|
+
message: {
|
|
1396
|
+
type: 'string'
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
let rootSerializerCalled = 0
|
|
1401
|
+
let rootValidatorCalled = 0
|
|
1402
|
+
let childValidatorCalled = 0
|
|
1403
|
+
const rootBuildSerializer = function (externalSchemas) {
|
|
1404
|
+
rootSerializerCalled++
|
|
1405
|
+
return function serializer () {
|
|
1406
|
+
return data => {
|
|
1407
|
+
return JSON.stringify({
|
|
1408
|
+
statusCode: data.statusCode,
|
|
1409
|
+
message: data.message
|
|
1410
|
+
})
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
const rootBuildValidator = function (externalSchemas) {
|
|
1415
|
+
rootValidatorCalled++
|
|
1416
|
+
return function validatorCompiler ({ schema }) {
|
|
1417
|
+
return customAjv.compile(schema)
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
const server = Fastify({
|
|
1421
|
+
schemaController: {
|
|
1422
|
+
compilersFactory: {
|
|
1423
|
+
buildValidator: rootBuildValidator,
|
|
1424
|
+
buildSerializer: rootBuildSerializer
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
})
|
|
1428
|
+
|
|
1429
|
+
server.addSchema(someSchema)
|
|
1430
|
+
server.addSchema(errorResponseSchema)
|
|
1431
|
+
|
|
1432
|
+
server.register((instance, _, done) => {
|
|
1433
|
+
instance.setSchemaController({
|
|
1434
|
+
compilersFactory: {
|
|
1435
|
+
buildValidator: function (externalSchemas) {
|
|
1436
|
+
childValidatorCalled++
|
|
1437
|
+
const schemaKeys = Object.keys(externalSchemas)
|
|
1438
|
+
for (const key of schemaKeys) {
|
|
1439
|
+
if (customAjv.getSchema(key) == null) {
|
|
1440
|
+
customAjv.addSchema(externalSchemas[key], key)
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
return function validatorCompiler ({ schema }) {
|
|
1444
|
+
return customAjv.compile(schema)
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
})
|
|
1449
|
+
|
|
1450
|
+
instance.get(
|
|
1451
|
+
'/',
|
|
1452
|
+
{
|
|
1453
|
+
schema: {
|
|
1454
|
+
querystring: {
|
|
1455
|
+
msg: {
|
|
1456
|
+
$ref: 'some#'
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
response: {
|
|
1460
|
+
'4xx': {
|
|
1461
|
+
$ref: 'error_response#'
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
},
|
|
1466
|
+
(req, reply) => {
|
|
1467
|
+
reply.send({ noop: 'noop' })
|
|
1468
|
+
}
|
|
1469
|
+
)
|
|
1470
|
+
|
|
1471
|
+
done()
|
|
1472
|
+
})
|
|
1473
|
+
|
|
1474
|
+
const res = await server.inject({
|
|
1475
|
+
method: 'GET',
|
|
1476
|
+
url: '/',
|
|
1477
|
+
query: {
|
|
1478
|
+
msg: 'string'
|
|
1479
|
+
}
|
|
1480
|
+
})
|
|
1481
|
+
const json = res.json()
|
|
1482
|
+
|
|
1483
|
+
t.equal(json.statusCode, 400)
|
|
1484
|
+
t.equal(json.message, 'querystring.msg should be array')
|
|
1485
|
+
t.equal(rootSerializerCalled, 1, 'Should be called from the child')
|
|
1486
|
+
t.equal(rootValidatorCalled, 0, 'Should not be called from the child')
|
|
1487
|
+
t.equal(childValidatorCalled, 1, 'Should be called from the child')
|
|
1488
|
+
t.equal(res.statusCode, 400, 'Should not coerce the string into array')
|
|
1489
|
+
})
|
|
1490
|
+
|
|
1491
|
+
test('setSchemaController: Inherits buildValidator from parent if not present within the instance', async t => {
|
|
1492
|
+
t.plan(6)
|
|
1493
|
+
const customAjv = new Ajv({ coerceTypes: false })
|
|
1494
|
+
const someSchema = {
|
|
1495
|
+
$id: 'some',
|
|
1496
|
+
type: 'array',
|
|
1497
|
+
items: {
|
|
1498
|
+
type: 'string'
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
const errorResponseSchema = {
|
|
1502
|
+
$id: 'error_response',
|
|
1503
|
+
type: 'object',
|
|
1504
|
+
properties: {
|
|
1505
|
+
statusCode: {
|
|
1506
|
+
type: 'integer'
|
|
1507
|
+
},
|
|
1508
|
+
message: {
|
|
1509
|
+
type: 'string'
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
let rootSerializerCalled = 0
|
|
1514
|
+
let rootValidatorCalled = 0
|
|
1515
|
+
let childSerializerCalled = 0
|
|
1516
|
+
const rootBuildSerializer = function (externalSchemas) {
|
|
1517
|
+
rootSerializerCalled++
|
|
1518
|
+
return function serializer () {
|
|
1519
|
+
return data => JSON.stringify(data)
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
const rootBuildValidator = function (externalSchemas) {
|
|
1523
|
+
rootValidatorCalled++
|
|
1524
|
+
const schemaKeys = Object.keys(externalSchemas)
|
|
1525
|
+
for (const key of schemaKeys) {
|
|
1526
|
+
if (customAjv.getSchema(key) == null) {
|
|
1527
|
+
customAjv.addSchema(externalSchemas[key], key)
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
return function validatorCompiler ({ schema }) {
|
|
1531
|
+
return customAjv.compile(schema)
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
const server = Fastify({
|
|
1535
|
+
schemaController: {
|
|
1536
|
+
compilersFactory: {
|
|
1537
|
+
buildValidator: rootBuildValidator,
|
|
1538
|
+
buildSerializer: rootBuildSerializer
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
})
|
|
1542
|
+
|
|
1543
|
+
server.register((instance, _, done) => {
|
|
1544
|
+
instance.register((subInstance, _, subDone) => {
|
|
1545
|
+
subInstance.setSchemaController({
|
|
1546
|
+
compilersFactory: {
|
|
1547
|
+
buildSerializer: function (externalSchemas) {
|
|
1548
|
+
childSerializerCalled++
|
|
1549
|
+
return function serializerCompiler () {
|
|
1550
|
+
return data => {
|
|
1551
|
+
return JSON.stringify({
|
|
1552
|
+
statusCode: data.statusCode,
|
|
1553
|
+
message: data.message
|
|
1554
|
+
})
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
})
|
|
1560
|
+
|
|
1561
|
+
subInstance.get(
|
|
1562
|
+
'/',
|
|
1563
|
+
{
|
|
1564
|
+
schema: {
|
|
1565
|
+
querystring: {
|
|
1566
|
+
msg: {
|
|
1567
|
+
$ref: 'some#'
|
|
1568
|
+
}
|
|
1569
|
+
},
|
|
1570
|
+
response: {
|
|
1571
|
+
'4xx': {
|
|
1572
|
+
$ref: 'error_response#'
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
(req, reply) => {
|
|
1578
|
+
reply.send({ noop: 'noop' })
|
|
1579
|
+
}
|
|
1580
|
+
)
|
|
1581
|
+
|
|
1582
|
+
subDone()
|
|
1583
|
+
})
|
|
1584
|
+
|
|
1585
|
+
done()
|
|
1586
|
+
})
|
|
1587
|
+
|
|
1588
|
+
server.addSchema(someSchema)
|
|
1589
|
+
server.addSchema(errorResponseSchema)
|
|
1590
|
+
|
|
1591
|
+
const res = await server.inject({
|
|
1592
|
+
method: 'GET',
|
|
1593
|
+
url: '/',
|
|
1594
|
+
query: {
|
|
1595
|
+
msg: ['string']
|
|
1596
|
+
}
|
|
1597
|
+
})
|
|
1598
|
+
const json = res.json()
|
|
1599
|
+
|
|
1600
|
+
t.equal(json.statusCode, 400)
|
|
1601
|
+
t.equal(json.message, 'querystring.msg should be array')
|
|
1602
|
+
t.equal(rootSerializerCalled, 0, 'Should be called from the child')
|
|
1603
|
+
t.equal(rootValidatorCalled, 1, 'Should not be called from the child')
|
|
1604
|
+
t.equal(childSerializerCalled, 1, 'Should be called from the child')
|
|
1605
|
+
t.equal(res.statusCode, 400, 'Should not coearce the string into array')
|
|
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
|
+
})
|
package/test/stream.test.js
CHANGED
|
@@ -16,6 +16,15 @@ const Readable = require('stream').Readable
|
|
|
16
16
|
const split = require('split2')
|
|
17
17
|
const { kDisableRequestLogging, kReplySent } = require('../lib/symbols.js')
|
|
18
18
|
|
|
19
|
+
function getUrl (app) {
|
|
20
|
+
const { address, port } = app.server.address()
|
|
21
|
+
if (address === '::1') {
|
|
22
|
+
return `http://[${address}]:${port}`
|
|
23
|
+
} else {
|
|
24
|
+
return `http://${address}:${port}`
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
test('should respond with a stream', t => {
|
|
20
29
|
t.plan(8)
|
|
21
30
|
const fastify = Fastify()
|
|
@@ -573,7 +582,7 @@ test('return a 404 if the stream emits a 404 error', t => {
|
|
|
573
582
|
})
|
|
574
583
|
})
|
|
575
584
|
|
|
576
|
-
test('should support send module 200 and 404', t => {
|
|
585
|
+
test('should support send module 200 and 404', { only: true }, t => {
|
|
577
586
|
t.plan(8)
|
|
578
587
|
const fastify = Fastify()
|
|
579
588
|
|
|
@@ -591,7 +600,9 @@ test('should support send module 200 and 404', t => {
|
|
|
591
600
|
t.error(err)
|
|
592
601
|
fastify.server.unref()
|
|
593
602
|
|
|
594
|
-
|
|
603
|
+
const url = getUrl(fastify)
|
|
604
|
+
|
|
605
|
+
sget(url, function (err, response, data) {
|
|
595
606
|
t.error(err)
|
|
596
607
|
t.equal(response.headers['content-type'], 'application/octet-stream')
|
|
597
608
|
t.equal(response.statusCode, 200)
|
|
@@ -602,7 +613,7 @@ test('should support send module 200 and 404', t => {
|
|
|
602
613
|
})
|
|
603
614
|
})
|
|
604
615
|
|
|
605
|
-
sget(
|
|
616
|
+
sget(url + '/error', function (err, response) {
|
|
606
617
|
t.error(err)
|
|
607
618
|
t.equal(response.statusCode, 404)
|
|
608
619
|
})
|
package/test/trust-proxy.test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const t = require('tap')
|
|
4
|
-
const test = t
|
|
4
|
+
const { test, before } = t
|
|
5
5
|
const sget = require('simple-get').concat
|
|
6
6
|
const fastify = require('..')
|
|
7
|
+
const dns = require('dns').promises
|
|
7
8
|
|
|
8
9
|
const sgetForwardedRequest = (app, forHeader, path, protoHeader) => {
|
|
9
10
|
const headers = {
|
|
@@ -38,6 +39,13 @@ const testRequestValues = (t, req, options) => {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
let localhost
|
|
43
|
+
|
|
44
|
+
before(async function () {
|
|
45
|
+
const lookup = await dns.lookup('localhost')
|
|
46
|
+
localhost = lookup.address
|
|
47
|
+
})
|
|
48
|
+
|
|
41
49
|
test('trust proxy, not add properties to node req', (t) => {
|
|
42
50
|
t.plan(8)
|
|
43
51
|
const app = fastify({
|
|
@@ -49,7 +57,7 @@ test('trust proxy, not add properties to node req', (t) => {
|
|
|
49
57
|
})
|
|
50
58
|
|
|
51
59
|
app.get('/trustproxychain', function (req, reply) {
|
|
52
|
-
testRequestValues(t, req, { ip: '2.2.2.2', ips: [
|
|
60
|
+
testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'] })
|
|
53
61
|
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
54
62
|
})
|
|
55
63
|
|
|
@@ -66,7 +74,7 @@ test('trust proxy, not add properties to node req', (t) => {
|
|
|
66
74
|
test('trust proxy chain', (t) => {
|
|
67
75
|
t.plan(3)
|
|
68
76
|
const app = fastify({
|
|
69
|
-
trustProxy: [
|
|
77
|
+
trustProxy: [localhost, '192.168.1.1']
|
|
70
78
|
})
|
|
71
79
|
|
|
72
80
|
app.get('/trustproxychain', function (req, reply) {
|
|
@@ -86,7 +94,7 @@ test('trust proxy chain', (t) => {
|
|
|
86
94
|
test('trust proxy function', (t) => {
|
|
87
95
|
t.plan(3)
|
|
88
96
|
const app = fastify({
|
|
89
|
-
trustProxy: (address) => address ===
|
|
97
|
+
trustProxy: (address) => address === localhost
|
|
90
98
|
})
|
|
91
99
|
app.get('/trustproxyfunc', function (req, reply) {
|
|
92
100
|
testRequestValues(t, req, { ip: '1.1.1.1' })
|
|
@@ -108,7 +116,7 @@ test('trust proxy number', (t) => {
|
|
|
108
116
|
trustProxy: 1
|
|
109
117
|
})
|
|
110
118
|
app.get('/trustproxynumber', function (req, reply) {
|
|
111
|
-
testRequestValues(t, req, { ip: '1.1.1.1', ips: [
|
|
119
|
+
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
|
|
112
120
|
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
113
121
|
})
|
|
114
122
|
|
|
@@ -124,10 +132,10 @@ test('trust proxy number', (t) => {
|
|
|
124
132
|
test('trust proxy IP addresses', (t) => {
|
|
125
133
|
t.plan(4)
|
|
126
134
|
const app = fastify({
|
|
127
|
-
trustProxy:
|
|
135
|
+
trustProxy: `${localhost}, 2.2.2.2`
|
|
128
136
|
})
|
|
129
137
|
app.get('/trustproxyipaddrs', function (req, reply) {
|
|
130
|
-
testRequestValues(t, req, { ip: '1.1.1.1', ips: [
|
|
138
|
+
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
|
|
131
139
|
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
132
140
|
})
|
|
133
141
|
|
|
@@ -3,7 +3,8 @@ import fastify, {
|
|
|
3
3
|
FastifyError,
|
|
4
4
|
FastifyInstance,
|
|
5
5
|
RawReplyDefaultExpression,
|
|
6
|
-
RawRequestDefaultExpression
|
|
6
|
+
RawRequestDefaultExpression,
|
|
7
|
+
RawServerDefault
|
|
7
8
|
} from '../../fastify'
|
|
8
9
|
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
9
10
|
import { FastifyRequest } from '../../types/request'
|
|
@@ -51,6 +52,50 @@ server.setErrorHandler(nodeJSErrorHandler)
|
|
|
51
52
|
function asyncNodeJSErrorHandler (error: NodeJS.ErrnoException) {}
|
|
52
53
|
server.setErrorHandler(asyncNodeJSErrorHandler)
|
|
53
54
|
|
|
55
|
+
class CustomError extends Error {
|
|
56
|
+
private __brand: any;
|
|
57
|
+
}
|
|
58
|
+
interface ReplyPayload {
|
|
59
|
+
Reply: {
|
|
60
|
+
test: boolean;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// typed sync error handler
|
|
64
|
+
server.setErrorHandler<CustomError, ReplyPayload>((error, request, reply) => {
|
|
65
|
+
expectType<CustomError>(error)
|
|
66
|
+
expectType<((payload?: ReplyPayload['Reply']) => FastifyReply<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>, ReplyPayload>)>(reply.send)
|
|
67
|
+
})
|
|
68
|
+
// typed async error handler send
|
|
69
|
+
server.setErrorHandler<CustomError, ReplyPayload>(async (error, request, reply) => {
|
|
70
|
+
expectType<CustomError>(error)
|
|
71
|
+
expectType<((payload?: ReplyPayload['Reply']) => FastifyReply<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>, ReplyPayload>)>(reply.send)
|
|
72
|
+
})
|
|
73
|
+
// typed async error handler return
|
|
74
|
+
server.setErrorHandler<CustomError, ReplyPayload>(async (error, request, reply) => {
|
|
75
|
+
expectType<CustomError>(error)
|
|
76
|
+
return { test: true }
|
|
77
|
+
})
|
|
78
|
+
// typed sync error handler send error
|
|
79
|
+
expectError(server.setErrorHandler<CustomError, ReplyPayload>((error, request, reply) => {
|
|
80
|
+
expectType<CustomError>(error)
|
|
81
|
+
reply.send({ test: 'foo' })
|
|
82
|
+
}))
|
|
83
|
+
// typed sync error handler return error
|
|
84
|
+
expectError(server.setErrorHandler<CustomError, ReplyPayload>((error, request, reply) => {
|
|
85
|
+
expectType<CustomError>(error)
|
|
86
|
+
return { test: 'foo' }
|
|
87
|
+
}))
|
|
88
|
+
// typed async error handler send error
|
|
89
|
+
expectError(server.setErrorHandler<CustomError, ReplyPayload>(async (error, request, reply) => {
|
|
90
|
+
expectType<CustomError>(error)
|
|
91
|
+
reply.send({ test: 'foo' })
|
|
92
|
+
}))
|
|
93
|
+
// typed async error handler return error
|
|
94
|
+
expectError(server.setErrorHandler<CustomError, ReplyPayload>(async (error, request, reply) => {
|
|
95
|
+
expectType<CustomError>(error)
|
|
96
|
+
return { test: 'foo' }
|
|
97
|
+
}))
|
|
98
|
+
|
|
54
99
|
function notFoundHandler (request: FastifyRequest, reply: FastifyReply) {}
|
|
55
100
|
function notFoundpreHandlerHandler (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) { done() }
|
|
56
101
|
async function notFoundpreHandlerAsyncHandler (request: FastifyRequest, reply: FastifyReply) {}
|
|
@@ -90,6 +135,12 @@ expectAssignable<void>(server.listen('3000', '', (err, address) => {}))
|
|
|
90
135
|
expectAssignable<void>(server.listen(3000, (err, address) => {}))
|
|
91
136
|
expectAssignable<void>(server.listen('3000', (err, address) => {}))
|
|
92
137
|
|
|
138
|
+
// test listen method callback types
|
|
139
|
+
expectAssignable<void>(server.listen('3000', (err, address) => {
|
|
140
|
+
expectAssignable<Error|null>(err)
|
|
141
|
+
expectAssignable<string>(address)
|
|
142
|
+
}))
|
|
143
|
+
|
|
93
144
|
// test listen method promise
|
|
94
145
|
expectAssignable<PromiseLike<string>>(server.listen(3000))
|
|
95
146
|
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()
|