fastify 2.10.0 → 2.11.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 +7 -0
- package/build/build-validation.js +8 -0
- package/docs/Ecosystem.md +5 -1
- package/docs/Hooks.md +32 -14
- package/docs/Plugins.md +1 -0
- package/docs/Routes.md +95 -6
- package/docs/Server.md +50 -1
- package/docs/TypeScript.md +30 -7
- package/docs/Validation-and-Serialization.md +74 -1
- package/fastify.d.ts +25 -1
- package/fastify.js +38 -2
- package/lib/configValidator.js +99 -52
- package/lib/contentTypeParser.js +4 -4
- package/lib/context.js +2 -1
- package/lib/logger.js +2 -2
- package/lib/route.js +18 -3
- package/lib/schemas.js +1 -1
- package/lib/symbols.js +1 -0
- package/lib/validation.js +10 -5
- package/package.json +20 -19
- package/test/404s.test.js +40 -0
- package/test/decorator.test.js +48 -0
- package/test/fastify-instance.test.js +29 -0
- package/test/hooks.test.js +23 -7
- package/test/input-validation.test.js +126 -0
- package/test/internals/initialConfig.test.js +2 -0
- package/test/logger.test.js +309 -0
- package/test/proto-poisoning.test.js +76 -0
- package/test/route-hooks.test.js +23 -14
- package/test/schemas.test.js +126 -0
- package/test/types/index.ts +31 -1
package/test/logger.test.js
CHANGED
|
@@ -567,6 +567,40 @@ test('Should set a custom logLevel for a plugin', t => {
|
|
|
567
567
|
})
|
|
568
568
|
})
|
|
569
569
|
|
|
570
|
+
test('Should set a custom logSerializers for a plugin', t => {
|
|
571
|
+
t.plan(3)
|
|
572
|
+
|
|
573
|
+
const splitStream = split(JSON.parse)
|
|
574
|
+
splitStream.on('data', (line) => {
|
|
575
|
+
if (line.test) {
|
|
576
|
+
t.is(line.test, 'XHello')
|
|
577
|
+
}
|
|
578
|
+
})
|
|
579
|
+
|
|
580
|
+
const logger = pino({ level: 'error' }, splitStream)
|
|
581
|
+
|
|
582
|
+
const fastify = Fastify({
|
|
583
|
+
logger
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
fastify.register(function (instance, opts, next) {
|
|
587
|
+
instance.get('/plugin', (req, reply) => {
|
|
588
|
+
req.log.info({ test: 'Hello' }) // we should see this log
|
|
589
|
+
reply.send({ hello: 'world' })
|
|
590
|
+
})
|
|
591
|
+
next()
|
|
592
|
+
}, { logLevel: 'info', logSerializers: { test: value => 'X' + value } })
|
|
593
|
+
|
|
594
|
+
fastify.inject({
|
|
595
|
+
method: 'GET',
|
|
596
|
+
url: '/plugin'
|
|
597
|
+
}, (err, res) => {
|
|
598
|
+
t.error(err)
|
|
599
|
+
const payload = JSON.parse(res.payload)
|
|
600
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
601
|
+
})
|
|
602
|
+
})
|
|
603
|
+
|
|
570
604
|
test('Should set a custom logLevel for every plugin', t => {
|
|
571
605
|
const lines = ['incoming request', 'request completed', 'info', 'debug']
|
|
572
606
|
t.plan(18)
|
|
@@ -634,6 +668,281 @@ test('Should set a custom logLevel for every plugin', t => {
|
|
|
634
668
|
})
|
|
635
669
|
})
|
|
636
670
|
|
|
671
|
+
test('Should set a custom logSerializers for every plugin', t => {
|
|
672
|
+
const lines = ['Hello', 'XHello', 'ZHello']
|
|
673
|
+
t.plan(9)
|
|
674
|
+
|
|
675
|
+
const splitStream = split(JSON.parse)
|
|
676
|
+
splitStream.on('data', (line) => {
|
|
677
|
+
if (line.test) {
|
|
678
|
+
t.is(line.test, lines.shift())
|
|
679
|
+
}
|
|
680
|
+
})
|
|
681
|
+
|
|
682
|
+
const logger = pino({ level: 'info' }, splitStream)
|
|
683
|
+
const fastify = Fastify({
|
|
684
|
+
logger
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
fastify.get('/', (req, reply) => {
|
|
688
|
+
req.log.warn({ test: 'Hello' })
|
|
689
|
+
reply.send({ hello: 'world' })
|
|
690
|
+
})
|
|
691
|
+
|
|
692
|
+
fastify.register(function (instance, opts, next) {
|
|
693
|
+
instance.get('/test1', (req, reply) => {
|
|
694
|
+
req.log.info({ test: 'Hello' })
|
|
695
|
+
reply.send({ hello: 'world' })
|
|
696
|
+
})
|
|
697
|
+
next()
|
|
698
|
+
}, { logSerializers: { test: value => 'X' + value } })
|
|
699
|
+
|
|
700
|
+
fastify.register(function (instance, opts, next) {
|
|
701
|
+
instance.get('/test2', (req, reply) => {
|
|
702
|
+
req.log.info({ test: 'Hello' })
|
|
703
|
+
reply.send({ hello: 'world' })
|
|
704
|
+
})
|
|
705
|
+
next()
|
|
706
|
+
}, { logSerializers: { test: value => 'Z' + value } })
|
|
707
|
+
|
|
708
|
+
fastify.inject({
|
|
709
|
+
method: 'GET',
|
|
710
|
+
url: '/'
|
|
711
|
+
}, (err, res) => {
|
|
712
|
+
t.error(err)
|
|
713
|
+
const payload = JSON.parse(res.payload)
|
|
714
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
fastify.inject({
|
|
718
|
+
method: 'GET',
|
|
719
|
+
url: '/test1'
|
|
720
|
+
}, (err, res) => {
|
|
721
|
+
t.error(err)
|
|
722
|
+
const payload = JSON.parse(res.payload)
|
|
723
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
724
|
+
})
|
|
725
|
+
|
|
726
|
+
fastify.inject({
|
|
727
|
+
method: 'GET',
|
|
728
|
+
url: '/test2'
|
|
729
|
+
}, (err, res) => {
|
|
730
|
+
t.error(err)
|
|
731
|
+
const payload = JSON.parse(res.payload)
|
|
732
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
733
|
+
})
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
test('Should override serializers from route', t => {
|
|
737
|
+
t.plan(3)
|
|
738
|
+
|
|
739
|
+
const splitStream = split(JSON.parse)
|
|
740
|
+
splitStream.on('data', (line) => {
|
|
741
|
+
if (line.test) {
|
|
742
|
+
t.is(line.test, 'ZHello')
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
const logger = pino({ level: 'info' }, splitStream)
|
|
747
|
+
const fastify = Fastify({
|
|
748
|
+
logger
|
|
749
|
+
})
|
|
750
|
+
|
|
751
|
+
fastify.register(function (instance, opts, next) {
|
|
752
|
+
instance.get('/', {
|
|
753
|
+
logSerializers: {
|
|
754
|
+
test: value => 'Z' + value // should override
|
|
755
|
+
}
|
|
756
|
+
}, (req, reply) => {
|
|
757
|
+
req.log.info({ test: 'Hello' })
|
|
758
|
+
reply.send({ hello: 'world' })
|
|
759
|
+
})
|
|
760
|
+
next()
|
|
761
|
+
}, { logSerializers: { test: value => 'X' + value } })
|
|
762
|
+
|
|
763
|
+
fastify.inject({
|
|
764
|
+
method: 'GET',
|
|
765
|
+
url: '/'
|
|
766
|
+
}, (err, res) => {
|
|
767
|
+
t.error(err)
|
|
768
|
+
const payload = JSON.parse(res.payload)
|
|
769
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
770
|
+
})
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
test('Should override serializers from plugin', t => {
|
|
774
|
+
t.plan(3)
|
|
775
|
+
|
|
776
|
+
const splitStream = split(JSON.parse)
|
|
777
|
+
splitStream.on('data', (line) => {
|
|
778
|
+
if (line.test) {
|
|
779
|
+
t.is(line.test, 'ZHello')
|
|
780
|
+
}
|
|
781
|
+
})
|
|
782
|
+
|
|
783
|
+
const logger = pino({ level: 'info' }, splitStream)
|
|
784
|
+
const fastify = Fastify({
|
|
785
|
+
logger
|
|
786
|
+
})
|
|
787
|
+
|
|
788
|
+
fastify.register(function (instance, opts, next) {
|
|
789
|
+
instance.register(context1, {
|
|
790
|
+
logSerializers: {
|
|
791
|
+
test: value => 'Z' + value // should override
|
|
792
|
+
}
|
|
793
|
+
})
|
|
794
|
+
next()
|
|
795
|
+
}, { logSerializers: { test: value => 'X' + value } })
|
|
796
|
+
|
|
797
|
+
function context1 (instance, opts, next) {
|
|
798
|
+
instance.get('/', (req, reply) => {
|
|
799
|
+
req.log.info({ test: 'Hello' })
|
|
800
|
+
reply.send({ hello: 'world' })
|
|
801
|
+
})
|
|
802
|
+
next()
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
fastify.inject({
|
|
806
|
+
method: 'GET',
|
|
807
|
+
url: '/'
|
|
808
|
+
}, (err, res) => {
|
|
809
|
+
t.error(err)
|
|
810
|
+
const payload = JSON.parse(res.payload)
|
|
811
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
812
|
+
})
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
test('Should use serializers from plugin and route', t => {
|
|
816
|
+
t.plan(4)
|
|
817
|
+
|
|
818
|
+
const splitStream = split(JSON.parse)
|
|
819
|
+
splitStream.on('data', (line) => {
|
|
820
|
+
if (line.test) {
|
|
821
|
+
t.is(line.test, 'XHello')
|
|
822
|
+
}
|
|
823
|
+
if (line.test2) {
|
|
824
|
+
t.is(line.test2, 'ZHello')
|
|
825
|
+
}
|
|
826
|
+
})
|
|
827
|
+
|
|
828
|
+
const logger = pino({ level: 'info' }, splitStream)
|
|
829
|
+
const fastify = Fastify({
|
|
830
|
+
logger
|
|
831
|
+
})
|
|
832
|
+
|
|
833
|
+
fastify.register(context1, {
|
|
834
|
+
logSerializers: { test: value => 'X' + value }
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
function context1 (instance, opts, next) {
|
|
838
|
+
instance.get('/', {
|
|
839
|
+
logSerializers: {
|
|
840
|
+
test2: value => 'Z' + value
|
|
841
|
+
}
|
|
842
|
+
}, (req, reply) => {
|
|
843
|
+
req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
|
|
844
|
+
reply.send({ hello: 'world' })
|
|
845
|
+
})
|
|
846
|
+
next()
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
fastify.inject({
|
|
850
|
+
method: 'GET',
|
|
851
|
+
url: '/'
|
|
852
|
+
}, (err, res) => {
|
|
853
|
+
t.error(err)
|
|
854
|
+
const payload = JSON.parse(res.payload)
|
|
855
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
856
|
+
})
|
|
857
|
+
})
|
|
858
|
+
|
|
859
|
+
test('Should use serializers from instance fastify and route', t => {
|
|
860
|
+
t.plan(4)
|
|
861
|
+
|
|
862
|
+
const splitStream = split(JSON.parse)
|
|
863
|
+
splitStream.on('data', (line) => {
|
|
864
|
+
if (line.test) {
|
|
865
|
+
t.is(line.test, 'XHello')
|
|
866
|
+
}
|
|
867
|
+
if (line.test2) {
|
|
868
|
+
t.is(line.test2, 'ZHello')
|
|
869
|
+
}
|
|
870
|
+
})
|
|
871
|
+
|
|
872
|
+
const logger = pino({
|
|
873
|
+
level: 'info',
|
|
874
|
+
serializers: {
|
|
875
|
+
test: value => 'X' + value,
|
|
876
|
+
test2: value => 'This should be override - ' + value
|
|
877
|
+
}
|
|
878
|
+
}, splitStream)
|
|
879
|
+
const fastify = Fastify({
|
|
880
|
+
logger
|
|
881
|
+
})
|
|
882
|
+
|
|
883
|
+
fastify.get('/', {
|
|
884
|
+
logSerializers: {
|
|
885
|
+
test2: value => 'Z' + value
|
|
886
|
+
}
|
|
887
|
+
}, (req, reply) => {
|
|
888
|
+
req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
|
|
889
|
+
reply.send({ hello: 'world' })
|
|
890
|
+
})
|
|
891
|
+
|
|
892
|
+
fastify.inject({
|
|
893
|
+
method: 'GET',
|
|
894
|
+
url: '/'
|
|
895
|
+
}, (err, res) => {
|
|
896
|
+
t.error(err)
|
|
897
|
+
const payload = JSON.parse(res.payload)
|
|
898
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
899
|
+
})
|
|
900
|
+
})
|
|
901
|
+
|
|
902
|
+
test('Should use serializers inherit from contexts', t => {
|
|
903
|
+
t.plan(5)
|
|
904
|
+
|
|
905
|
+
const splitStream = split(JSON.parse)
|
|
906
|
+
splitStream.on('data', (line) => {
|
|
907
|
+
if (line.test && line.test2 && line.test3) {
|
|
908
|
+
t.is(line.test, 'XHello')
|
|
909
|
+
t.is(line.test2, 'YHello')
|
|
910
|
+
t.is(line.test3, 'ZHello')
|
|
911
|
+
}
|
|
912
|
+
})
|
|
913
|
+
|
|
914
|
+
const logger = pino({
|
|
915
|
+
level: 'info',
|
|
916
|
+
serializers: {
|
|
917
|
+
test: value => 'X' + value
|
|
918
|
+
}
|
|
919
|
+
}, splitStream)
|
|
920
|
+
|
|
921
|
+
const fastify = Fastify({ logger })
|
|
922
|
+
fastify.register(context1, { logSerializers: { test2: value => 'Y' + value } })
|
|
923
|
+
|
|
924
|
+
function context1 (instance, opts, next) {
|
|
925
|
+
instance.get('/', {
|
|
926
|
+
logSerializers: {
|
|
927
|
+
test3: value => 'Z' + value
|
|
928
|
+
}
|
|
929
|
+
}, (req, reply) => {
|
|
930
|
+
req.log.info({ test: 'Hello', test2: 'Hello', test3: 'Hello' }) // { test: 'XHello', test2: 'YHello', test3: 'ZHello' }
|
|
931
|
+
reply.send({ hello: 'world' })
|
|
932
|
+
})
|
|
933
|
+
next()
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
fastify.inject({
|
|
937
|
+
method: 'GET',
|
|
938
|
+
url: '/'
|
|
939
|
+
}, (err, res) => {
|
|
940
|
+
t.error(err)
|
|
941
|
+
const payload = JSON.parse(res.payload)
|
|
942
|
+
t.deepEqual(payload, { hello: 'world' })
|
|
943
|
+
})
|
|
944
|
+
})
|
|
945
|
+
|
|
637
946
|
test('Should increase the log level for a specific plugin', t => {
|
|
638
947
|
t.plan(4)
|
|
639
948
|
|
|
@@ -81,3 +81,79 @@ test('proto-poisoning ignore', t => {
|
|
|
81
81
|
})
|
|
82
82
|
})
|
|
83
83
|
})
|
|
84
|
+
|
|
85
|
+
test('constructor-poisoning ignore (default in v2)', t => {
|
|
86
|
+
t.plan(3)
|
|
87
|
+
|
|
88
|
+
const fastify = Fastify()
|
|
89
|
+
t.tearDown(fastify.close.bind(fastify))
|
|
90
|
+
|
|
91
|
+
fastify.post('/', (request, reply) => {
|
|
92
|
+
reply.send('ok')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
fastify.listen(0, function (err) {
|
|
96
|
+
t.error(err)
|
|
97
|
+
|
|
98
|
+
sget({
|
|
99
|
+
method: 'POST',
|
|
100
|
+
url: 'http://localhost:' + fastify.server.address().port,
|
|
101
|
+
headers: { 'Content-Type': 'application/json' },
|
|
102
|
+
body: '{ "constructor": { "prototype": { "foo": "bar" } } }'
|
|
103
|
+
}, (err, response, body) => {
|
|
104
|
+
t.error(err)
|
|
105
|
+
t.strictEqual(response.statusCode, 200)
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('constructor-poisoning error', t => {
|
|
111
|
+
t.plan(3)
|
|
112
|
+
|
|
113
|
+
const fastify = Fastify({ onConstructorPoisoning: 'error' })
|
|
114
|
+
t.tearDown(fastify.close.bind(fastify))
|
|
115
|
+
|
|
116
|
+
fastify.post('/', (request, reply) => {
|
|
117
|
+
t.fail('handler should not be called')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
fastify.listen(0, function (err) {
|
|
121
|
+
t.error(err)
|
|
122
|
+
|
|
123
|
+
sget({
|
|
124
|
+
method: 'POST',
|
|
125
|
+
url: 'http://localhost:' + fastify.server.address().port,
|
|
126
|
+
headers: { 'Content-Type': 'application/json' },
|
|
127
|
+
body: '{ "constructor": { "prototype": { "foo": "bar" } } }'
|
|
128
|
+
}, (err, response, body) => {
|
|
129
|
+
t.error(err)
|
|
130
|
+
t.strictEqual(response.statusCode, 400)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('constructor-poisoning remove', t => {
|
|
136
|
+
t.plan(4)
|
|
137
|
+
|
|
138
|
+
const fastify = Fastify({ onProtoPoisoning: 'remove' })
|
|
139
|
+
t.tearDown(fastify.close.bind(fastify))
|
|
140
|
+
|
|
141
|
+
fastify.post('/', (request, reply) => {
|
|
142
|
+
t.equal(undefined, Object.assign({}, request.body).foo)
|
|
143
|
+
reply.send({ ok: true })
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
fastify.listen(0, function (err) {
|
|
147
|
+
t.error(err)
|
|
148
|
+
|
|
149
|
+
sget({
|
|
150
|
+
method: 'POST',
|
|
151
|
+
url: 'http://localhost:' + fastify.server.address().port,
|
|
152
|
+
headers: { 'Content-Type': 'application/json' },
|
|
153
|
+
body: '{ "constructor": { "prototype": { "foo": "bar" } } }'
|
|
154
|
+
}, (err, response, body) => {
|
|
155
|
+
t.error(err)
|
|
156
|
+
t.strictEqual(response.statusCode, 200)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
})
|
package/test/route-hooks.test.js
CHANGED
|
@@ -3,15 +3,23 @@
|
|
|
3
3
|
const test = require('tap').test
|
|
4
4
|
const Fastify = require('../')
|
|
5
5
|
|
|
6
|
+
function endMiddleware (nextOrPayload, next) {
|
|
7
|
+
if (typeof nextOrPayload === 'function') {
|
|
8
|
+
nextOrPayload()
|
|
9
|
+
} else {
|
|
10
|
+
next()
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
function testExecutionHook (hook) {
|
|
7
15
|
test(`${hook}`, t => {
|
|
8
16
|
t.plan(3)
|
|
9
17
|
const fastify = Fastify()
|
|
10
18
|
|
|
11
19
|
fastify.post('/', {
|
|
12
|
-
[hook]: (req, reply,
|
|
20
|
+
[hook]: (req, reply, nextOrPayload, next) => {
|
|
13
21
|
t.pass('hook called')
|
|
14
|
-
|
|
22
|
+
endMiddleware(nextOrPayload, next)
|
|
15
23
|
}
|
|
16
24
|
}, (req, reply) => {
|
|
17
25
|
reply.send(req.body)
|
|
@@ -35,15 +43,15 @@ function testExecutionHook (hook) {
|
|
|
35
43
|
get: function () { return ++this.calledTimes }
|
|
36
44
|
})
|
|
37
45
|
|
|
38
|
-
fastify.addHook(hook, (req, reply, next) => {
|
|
46
|
+
fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
|
|
39
47
|
t.equal(checker.check, 1)
|
|
40
|
-
next
|
|
48
|
+
endMiddleware(nextOrPayload, next)
|
|
41
49
|
})
|
|
42
50
|
|
|
43
51
|
fastify.post('/', {
|
|
44
|
-
[hook]: (req, reply,
|
|
52
|
+
[hook]: (req, reply, nextOrPayload, next) => {
|
|
45
53
|
t.equal(checker.check, 2)
|
|
46
|
-
|
|
54
|
+
endMiddleware(nextOrPayload, next)
|
|
47
55
|
}
|
|
48
56
|
}, (req, reply) => {
|
|
49
57
|
reply.send({})
|
|
@@ -67,13 +75,13 @@ function testExecutionHook (hook) {
|
|
|
67
75
|
|
|
68
76
|
fastify.post('/', {
|
|
69
77
|
[hook]: [
|
|
70
|
-
(req, reply,
|
|
78
|
+
(req, reply, nextOrPayload, next) => {
|
|
71
79
|
t.equal(checker.check, 1)
|
|
72
|
-
|
|
80
|
+
endMiddleware(nextOrPayload, next)
|
|
73
81
|
},
|
|
74
|
-
(req, reply,
|
|
82
|
+
(req, reply, nextOrPayload, next) => {
|
|
75
83
|
t.equal(checker.check, 2)
|
|
76
|
-
|
|
84
|
+
endMiddleware(nextOrPayload, next)
|
|
77
85
|
}
|
|
78
86
|
]
|
|
79
87
|
}, (req, reply) => {
|
|
@@ -96,15 +104,15 @@ function testExecutionHook (hook) {
|
|
|
96
104
|
get: function () { return ++this.calledTimes }
|
|
97
105
|
})
|
|
98
106
|
|
|
99
|
-
fastify.addHook(hook, (req, reply, next) => {
|
|
107
|
+
fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
|
|
100
108
|
t.equal(checker.check, 1)
|
|
101
|
-
next
|
|
109
|
+
endMiddleware(nextOrPayload, next)
|
|
102
110
|
})
|
|
103
111
|
|
|
104
112
|
fastify.post('/', {
|
|
105
|
-
[hook]: (req, reply,
|
|
113
|
+
[hook]: (req, reply, nextOrPayload, next) => {
|
|
106
114
|
t.equal(checker.check, 2)
|
|
107
|
-
|
|
115
|
+
endMiddleware(nextOrPayload, next)
|
|
108
116
|
}
|
|
109
117
|
}, handler)
|
|
110
118
|
|
|
@@ -286,6 +294,7 @@ function testBeforeHandlerHook (hook) {
|
|
|
286
294
|
}
|
|
287
295
|
|
|
288
296
|
testExecutionHook('preHandler')
|
|
297
|
+
testExecutionHook('onSend')
|
|
289
298
|
testExecutionHook('onRequest')
|
|
290
299
|
testExecutionHook('onResponse')
|
|
291
300
|
testExecutionHook('preValidation')
|
package/test/schemas.test.js
CHANGED
|
@@ -4,6 +4,7 @@ const t = require('tap')
|
|
|
4
4
|
const test = t.test
|
|
5
5
|
const Fastify = require('..')
|
|
6
6
|
|
|
7
|
+
const ajvMergePatch = require('ajv-merge-patch')
|
|
7
8
|
const AJV = require('ajv')
|
|
8
9
|
const fastClone = require('rfdc')({ circles: false, proto: true })
|
|
9
10
|
|
|
@@ -322,3 +323,128 @@ test('$ref with a simple $id', t => {
|
|
|
322
323
|
t.deepEquals(JSON.parse(res.payload), { foo: { foo: 'bar' } })
|
|
323
324
|
})
|
|
324
325
|
})
|
|
326
|
+
|
|
327
|
+
test('Should handle root $merge keywords in header', t => {
|
|
328
|
+
t.plan(5)
|
|
329
|
+
const fastify = Fastify({
|
|
330
|
+
ajv: {
|
|
331
|
+
plugins: [
|
|
332
|
+
ajvMergePatch
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
fastify.route({
|
|
338
|
+
method: 'GET',
|
|
339
|
+
url: '/',
|
|
340
|
+
schema: {
|
|
341
|
+
headers: {
|
|
342
|
+
$merge: {
|
|
343
|
+
source: {
|
|
344
|
+
type: 'object',
|
|
345
|
+
properties: {
|
|
346
|
+
q: {
|
|
347
|
+
type: 'string'
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
with: {
|
|
352
|
+
required: ['q']
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
handler (req, reply) {
|
|
358
|
+
reply.send({ ok: 1 })
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
fastify.ready(err => {
|
|
363
|
+
t.error(err)
|
|
364
|
+
|
|
365
|
+
fastify.inject({
|
|
366
|
+
method: 'GET',
|
|
367
|
+
url: '/'
|
|
368
|
+
}, (err, res) => {
|
|
369
|
+
t.error(err)
|
|
370
|
+
t.equals(res.statusCode, 400)
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
fastify.inject({
|
|
374
|
+
method: 'GET',
|
|
375
|
+
url: '/',
|
|
376
|
+
headers: {
|
|
377
|
+
q: 'foo'
|
|
378
|
+
}
|
|
379
|
+
}, (err, res) => {
|
|
380
|
+
t.error(err)
|
|
381
|
+
t.equals(res.statusCode, 200)
|
|
382
|
+
})
|
|
383
|
+
})
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
test('Should handle root $patch keywords in header', t => {
|
|
387
|
+
t.plan(5)
|
|
388
|
+
const fastify = Fastify({
|
|
389
|
+
ajv: {
|
|
390
|
+
plugins: [
|
|
391
|
+
ajvMergePatch
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
fastify.route({
|
|
397
|
+
method: 'GET',
|
|
398
|
+
url: '/',
|
|
399
|
+
schema: {
|
|
400
|
+
headers: {
|
|
401
|
+
$patch: {
|
|
402
|
+
source: {
|
|
403
|
+
type: 'object',
|
|
404
|
+
properties: {
|
|
405
|
+
q: {
|
|
406
|
+
type: 'string'
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
with: [
|
|
411
|
+
{
|
|
412
|
+
op: 'add',
|
|
413
|
+
path: '/properties/q',
|
|
414
|
+
value: { type: 'number' }
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
handler (req, reply) {
|
|
421
|
+
reply.send({ ok: 1 })
|
|
422
|
+
}
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
fastify.ready(err => {
|
|
426
|
+
t.error(err)
|
|
427
|
+
|
|
428
|
+
fastify.inject({
|
|
429
|
+
method: 'GET',
|
|
430
|
+
url: '/',
|
|
431
|
+
headers: {
|
|
432
|
+
q: 'foo'
|
|
433
|
+
}
|
|
434
|
+
}, (err, res) => {
|
|
435
|
+
t.error(err)
|
|
436
|
+
t.equals(res.statusCode, 400)
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
fastify.inject({
|
|
440
|
+
method: 'GET',
|
|
441
|
+
url: '/',
|
|
442
|
+
headers: {
|
|
443
|
+
q: 10
|
|
444
|
+
}
|
|
445
|
+
}, (err, res) => {
|
|
446
|
+
t.error(err)
|
|
447
|
+
t.equals(res.statusCode, 200)
|
|
448
|
+
})
|
|
449
|
+
})
|
|
450
|
+
})
|
package/test/types/index.ts
CHANGED
|
@@ -64,7 +64,31 @@ const cors = require('cors')
|
|
|
64
64
|
maxParamLength: 200,
|
|
65
65
|
querystringParser: (str: string) => ({ str: str, strArray: [str] }),
|
|
66
66
|
modifyCoreObjects: true,
|
|
67
|
-
return503OnClosing: true
|
|
67
|
+
return503OnClosing: true,
|
|
68
|
+
genReqId: () => {
|
|
69
|
+
if (Math.random() > 0.5) {
|
|
70
|
+
return Math.random().toString()
|
|
71
|
+
}
|
|
72
|
+
return Math.random()
|
|
73
|
+
},
|
|
74
|
+
requestIdHeader: 'request-id',
|
|
75
|
+
requestIdLogLabel: 'reqId',
|
|
76
|
+
serverFactory: (handler, options) => {
|
|
77
|
+
const server = http.createServer((req, res) => {
|
|
78
|
+
handler(req, res)
|
|
79
|
+
})
|
|
80
|
+
return server
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// http2 server factory option
|
|
85
|
+
const otherHttp2Server = fastify({
|
|
86
|
+
serverFactory: (handler, options) => {
|
|
87
|
+
const server = http2.createServer((req, res) => {
|
|
88
|
+
handler(req, res)
|
|
89
|
+
})
|
|
90
|
+
return server
|
|
91
|
+
}
|
|
68
92
|
})
|
|
69
93
|
|
|
70
94
|
// custom types
|
|
@@ -102,6 +126,11 @@ server.use('/', (req, res, next) => {
|
|
|
102
126
|
console.log(`${req.method} ${req.url}`)
|
|
103
127
|
})
|
|
104
128
|
|
|
129
|
+
// Custom middleware with multiple paths
|
|
130
|
+
server.use(['/foo', '/bar'], (req, res, next) => {
|
|
131
|
+
console.log(`${req.method} ${req.url}`)
|
|
132
|
+
})
|
|
133
|
+
|
|
105
134
|
// Third party plugin
|
|
106
135
|
// Also check if async functions are allowed to be passed to .register()
|
|
107
136
|
// https://github.com/fastify/fastify/pull/1841
|
|
@@ -233,6 +262,7 @@ const opts: fastify.RouteShorthandOptions<http2.Http2SecureServer, http2.Http2Se
|
|
|
233
262
|
schemaCompiler: (schema: Object) => () => {},
|
|
234
263
|
bodyLimit: 5000,
|
|
235
264
|
logLevel: 'trace',
|
|
265
|
+
version: '1.0.0',
|
|
236
266
|
config: { }
|
|
237
267
|
}
|
|
238
268
|
const optsWithHandler: fastify.RouteShorthandOptions<http2.Http2SecureServer, http2.Http2ServerRequest, http2.Http2ServerResponse> = {
|