1 | 'use strict'
|
2 |
|
3 | const t = require('tap')
|
4 | const test = t.test
|
5 | const Fastify = require('..')
|
6 | const sget = require('simple-get').concat
|
7 | const http = require('http')
|
8 | const split = require('split2')
|
9 |
|
10 | test('Should register a versioned route', t => {
|
11 | t.plan(11)
|
12 | const fastify = Fastify()
|
13 |
|
14 | fastify.route({
|
15 | method: 'GET',
|
16 | url: '/',
|
17 | version: '1.2.0',
|
18 | handler: (req, reply) => {
|
19 | reply.send({ hello: 'world' })
|
20 | }
|
21 | })
|
22 |
|
23 | fastify.inject({
|
24 | method: 'GET',
|
25 | url: '/',
|
26 | headers: {
|
27 | 'Accept-Version': '1.x'
|
28 | }
|
29 | }, (err, res) => {
|
30 | t.error(err)
|
31 | t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
|
32 | t.strictEqual(res.statusCode, 200)
|
33 | })
|
34 |
|
35 | fastify.inject({
|
36 | method: 'GET',
|
37 | url: '/',
|
38 | headers: {
|
39 | 'Accept-Version': '1.2.x'
|
40 | }
|
41 | }, (err, res) => {
|
42 | t.error(err)
|
43 | t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
|
44 | t.strictEqual(res.statusCode, 200)
|
45 | })
|
46 |
|
47 | fastify.inject({
|
48 | method: 'GET',
|
49 | url: '/',
|
50 | headers: {
|
51 | 'Accept-Version': '1.2.0'
|
52 | }
|
53 | }, (err, res) => {
|
54 | t.error(err)
|
55 | t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
|
56 | t.strictEqual(res.statusCode, 200)
|
57 | })
|
58 |
|
59 | fastify.inject({
|
60 | method: 'GET',
|
61 | url: '/',
|
62 | headers: {
|
63 | 'Accept-Version': '1.2.1'
|
64 | }
|
65 | }, (err, res) => {
|
66 | t.error(err)
|
67 | t.strictEqual(res.statusCode, 404)
|
68 | })
|
69 | })
|
70 |
|
71 | test('Should register the same route with different versions', t => {
|
72 | t.plan(8)
|
73 | const fastify = Fastify()
|
74 |
|
75 | fastify.route({
|
76 | method: 'GET',
|
77 | url: '/',
|
78 | version: '1.2.0',
|
79 | handler: (req, reply) => {
|
80 | reply.send('1.2.0')
|
81 | }
|
82 | })
|
83 |
|
84 | fastify.route({
|
85 | method: 'GET',
|
86 | url: '/',
|
87 | version: '1.3.0',
|
88 | handler: (req, reply) => {
|
89 | reply.send('1.3.0')
|
90 | }
|
91 | })
|
92 |
|
93 | fastify.inject({
|
94 | method: 'GET',
|
95 | url: '/',
|
96 | headers: {
|
97 | 'Accept-Version': '1.x'
|
98 | }
|
99 | }, (err, res) => {
|
100 | t.error(err)
|
101 | t.strictEqual(res.statusCode, 200)
|
102 | t.strictEqual(res.payload, '1.3.0')
|
103 | })
|
104 |
|
105 | fastify.inject({
|
106 | method: 'GET',
|
107 | url: '/',
|
108 | headers: {
|
109 | 'Accept-Version': '1.2.x'
|
110 | }
|
111 | }, (err, res) => {
|
112 | t.error(err)
|
113 | t.strictEqual(res.statusCode, 200)
|
114 | t.strictEqual(res.payload, '1.2.0')
|
115 | })
|
116 |
|
117 | fastify.inject({
|
118 | method: 'GET',
|
119 | url: '/',
|
120 | headers: {
|
121 | 'Accept-Version': '2.x'
|
122 | }
|
123 | }, (err, res) => {
|
124 | t.error(err)
|
125 | t.strictEqual(res.statusCode, 404)
|
126 | })
|
127 | })
|
128 |
|
129 | test('The versioned route should take precedence', t => {
|
130 | t.plan(3)
|
131 | const fastify = Fastify()
|
132 |
|
133 | fastify.route({
|
134 | method: 'GET',
|
135 | url: '/',
|
136 | handler: (req, reply) => {
|
137 | reply.send({ winter: 'is coming' })
|
138 | }
|
139 | })
|
140 |
|
141 | fastify.route({
|
142 | method: 'GET',
|
143 | url: '/',
|
144 | version: '1.2.0',
|
145 | handler: (req, reply) => {
|
146 | reply.send({ hello: 'world' })
|
147 | }
|
148 | })
|
149 |
|
150 | fastify.inject({
|
151 | method: 'GET',
|
152 | url: '/',
|
153 | headers: {
|
154 | 'Accept-Version': '1.x'
|
155 | }
|
156 | }, (err, res) => {
|
157 | t.error(err)
|
158 | t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
|
159 | t.strictEqual(res.statusCode, 200)
|
160 | })
|
161 | })
|
162 |
|
163 | test('Versioned route but not version header should return a 404', t => {
|
164 | t.plan(2)
|
165 | const fastify = Fastify()
|
166 |
|
167 | fastify.route({
|
168 | method: 'GET',
|
169 | url: '/',
|
170 | version: '1.2.0',
|
171 | handler: (req, reply) => {
|
172 | reply.send({ hello: 'world' })
|
173 | }
|
174 | })
|
175 |
|
176 | fastify.inject({
|
177 | method: 'GET',
|
178 | url: '/'
|
179 | }, (err, res) => {
|
180 | t.error(err)
|
181 | t.strictEqual(res.statusCode, 404)
|
182 | })
|
183 | })
|
184 |
|
185 | test('Should register a versioned route', t => {
|
186 | t.plan(6)
|
187 | const fastify = Fastify()
|
188 |
|
189 | fastify.route({
|
190 | method: 'GET',
|
191 | url: '/',
|
192 | version: '1.2.0',
|
193 | handler: (req, reply) => {
|
194 | reply.send({ hello: 'world' })
|
195 | }
|
196 | })
|
197 |
|
198 | fastify.listen(0, err => {
|
199 | t.error(err)
|
200 | fastify.server.unref()
|
201 |
|
202 | sget({
|
203 | method: 'GET',
|
204 | url: 'http://localhost:' + fastify.server.address().port,
|
205 | headers: {
|
206 | 'Accept-Version': '1.x'
|
207 | }
|
208 | }, (err, response, body) => {
|
209 | t.error(err)
|
210 | t.strictEqual(response.statusCode, 200)
|
211 | t.deepEqual(JSON.parse(body), { hello: 'world' })
|
212 | })
|
213 |
|
214 | sget({
|
215 | method: 'GET',
|
216 | url: 'http://localhost:' + fastify.server.address().port,
|
217 | headers: {
|
218 | 'Accept-Version': '2.x'
|
219 | }
|
220 | }, (err, response, body) => {
|
221 | t.error(err)
|
222 | t.strictEqual(response.statusCode, 404)
|
223 | })
|
224 | })
|
225 | })
|
226 |
|
227 | test('Shorthand route declaration', t => {
|
228 | t.plan(5)
|
229 | const fastify = Fastify()
|
230 |
|
231 | fastify.get('/', { version: '1.2.0' }, (req, reply) => {
|
232 | reply.send({ hello: 'world' })
|
233 | })
|
234 |
|
235 | fastify.inject({
|
236 | method: 'GET',
|
237 | url: '/',
|
238 | headers: {
|
239 | 'Accept-Version': '1.x'
|
240 | }
|
241 | }, (err, res) => {
|
242 | t.error(err)
|
243 | t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
|
244 | t.strictEqual(res.statusCode, 200)
|
245 | })
|
246 |
|
247 | fastify.inject({
|
248 | method: 'GET',
|
249 | url: '/',
|
250 | headers: {
|
251 | 'Accept-Version': '1.2.1'
|
252 | }
|
253 | }, (err, res) => {
|
254 | t.error(err)
|
255 | t.strictEqual(res.statusCode, 404)
|
256 | })
|
257 | })
|
258 |
|
259 | test('The not found handler should not use the Accept-Version header', t => {
|
260 | t.plan(4)
|
261 | const fastify = Fastify()
|
262 |
|
263 | fastify.route({
|
264 | method: 'GET',
|
265 | url: '/',
|
266 | version: '1.2.0',
|
267 | handler: (req, reply) => {
|
268 | reply.send({ hello: 'world' })
|
269 | }
|
270 | })
|
271 |
|
272 | fastify.setNotFoundHandler(function (req, reply) {
|
273 | t.notOk(req.headers['accept-version'])
|
274 | reply.code(404).send('not found handler')
|
275 | })
|
276 |
|
277 | fastify.inject({
|
278 | method: 'GET',
|
279 | url: '/',
|
280 | headers: {
|
281 | 'Accept-Version': '2.x'
|
282 | }
|
283 | }, (err, res) => {
|
284 | t.error(err)
|
285 | t.deepEqual(res.payload, 'not found handler')
|
286 | t.strictEqual(res.statusCode, 404)
|
287 | })
|
288 | })
|
289 |
|
290 | test('Bad accept version (inject)', t => {
|
291 | t.plan(4)
|
292 | const fastify = Fastify()
|
293 |
|
294 | fastify.route({
|
295 | method: 'GET',
|
296 | url: '/',
|
297 | version: '1.2.0',
|
298 | handler: (req, reply) => {
|
299 | reply.send({ hello: 'world' })
|
300 | }
|
301 | })
|
302 |
|
303 | fastify.inject({
|
304 | method: 'GET',
|
305 | url: '/',
|
306 | headers: {
|
307 | 'Accept-Version': 'a.b.c'
|
308 | }
|
309 | }, (err, res) => {
|
310 | t.error(err)
|
311 | t.strictEqual(res.statusCode, 404)
|
312 | })
|
313 |
|
314 | fastify.inject({
|
315 | method: 'GET',
|
316 | url: '/',
|
317 | headers: {
|
318 | 'Accept-Version': 12
|
319 | }
|
320 | }, (err, res) => {
|
321 | t.error(err)
|
322 | t.strictEqual(res.statusCode, 404)
|
323 | })
|
324 | })
|
325 |
|
326 | test('Bas accept version (server)', t => {
|
327 | t.plan(5)
|
328 | const fastify = Fastify()
|
329 |
|
330 | fastify.route({
|
331 | method: 'GET',
|
332 | url: '/',
|
333 | version: '1.2.0',
|
334 | handler: (req, reply) => {
|
335 | reply.send({ hello: 'world' })
|
336 | }
|
337 | })
|
338 |
|
339 | fastify.listen(0, err => {
|
340 | t.error(err)
|
341 | fastify.server.unref()
|
342 |
|
343 | sget({
|
344 | method: 'GET',
|
345 | url: 'http://localhost:' + fastify.server.address().port,
|
346 | headers: {
|
347 | 'Accept-Version': 'a.b.c'
|
348 | }
|
349 | }, (err, response, body) => {
|
350 | t.error(err)
|
351 | t.strictEqual(response.statusCode, 404)
|
352 | })
|
353 |
|
354 | sget({
|
355 | method: 'GET',
|
356 | url: 'http://localhost:' + fastify.server.address().port,
|
357 | headers: {
|
358 | 'Accept-Version': 12
|
359 | }
|
360 | }, (err, response, body) => {
|
361 | t.error(err)
|
362 | t.strictEqual(response.statusCode, 404)
|
363 | })
|
364 | })
|
365 | })
|
366 |
|
367 | test('test log stream', t => {
|
368 | t.plan(3)
|
369 | const stream = split(JSON.parse)
|
370 | const fastify = Fastify({
|
371 | logger: {
|
372 | stream: stream,
|
373 | level: 'info'
|
374 | }
|
375 | })
|
376 |
|
377 | fastify.get('/', { version: '1.2.0' }, function (req, reply) {
|
378 | reply.send(new Error('kaboom'))
|
379 | })
|
380 |
|
381 | fastify.listen(0, err => {
|
382 | t.error(err)
|
383 | fastify.server.unref()
|
384 |
|
385 | http.get({
|
386 | hostname: 'localhost',
|
387 | port: fastify.server.address().port,
|
388 | path: '/',
|
389 | method: 'GET',
|
390 | headers: {
|
391 | 'Accept-Version': '1.x'
|
392 | }
|
393 | })
|
394 |
|
395 | stream.once('data', listenAtLogLine => {
|
396 | stream.once('data', line => {
|
397 | t.equal(line.req.version, '1.x')
|
398 | stream.once('data', line => {
|
399 | t.equal(line.req.version, '1.x')
|
400 | })
|
401 | })
|
402 | })
|
403 | })
|
404 | })
|
405 |
|
406 | test('Should register a versioned route with custome versioning strategy', t => {
|
407 | t.plan(8)
|
408 |
|
409 | const versioning = {
|
410 | storage: function () {
|
411 | let versions = {}
|
412 | return {
|
413 | get: (version) => { return versions[version] || null },
|
414 | set: (version, store) => { versions[version] = store },
|
415 | del: (version) => { delete versions[version] },
|
416 | empty: () => { versions = {} }
|
417 | }
|
418 | },
|
419 | deriveVersion: (req, ctx) => {
|
420 | return req.headers.accept
|
421 | }
|
422 | }
|
423 |
|
424 | const fastify = Fastify({ versioning })
|
425 |
|
426 | fastify.route({
|
427 | method: 'GET',
|
428 | url: '/',
|
429 | version: 'application/vnd.example.api+json;version=2',
|
430 | handler: (req, reply) => {
|
431 | reply.send({ hello: 'from route v2' })
|
432 | }
|
433 | })
|
434 |
|
435 | fastify.route({
|
436 | method: 'GET',
|
437 | url: '/',
|
438 | version: 'application/vnd.example.api+json;version=3',
|
439 | handler: (req, reply) => {
|
440 | reply.send({ hello: 'from route v3' })
|
441 | }
|
442 | })
|
443 |
|
444 | fastify.inject({
|
445 | method: 'GET',
|
446 | url: '/',
|
447 | headers: {
|
448 | Accept: 'application/vnd.example.api+json;version=2'
|
449 | }
|
450 | }, (err, res) => {
|
451 | t.error(err)
|
452 | t.deepEqual(JSON.parse(res.payload), { hello: 'from route v2' })
|
453 | t.strictEqual(res.statusCode, 200)
|
454 | })
|
455 |
|
456 | fastify.inject({
|
457 | method: 'GET',
|
458 | url: '/',
|
459 | headers: {
|
460 | Accept: 'application/vnd.example.api+json;version=3'
|
461 | }
|
462 | }, (err, res) => {
|
463 | t.error(err)
|
464 | t.deepEqual(JSON.parse(res.payload), { hello: 'from route v3' })
|
465 | t.strictEqual(res.statusCode, 200)
|
466 | })
|
467 |
|
468 | fastify.inject({
|
469 | method: 'GET',
|
470 | url: '/',
|
471 | headers: {
|
472 | Accept: 'application/vnd.example.api+json;version=4'
|
473 | }
|
474 | }, (err, res) => {
|
475 | t.error(err)
|
476 | t.strictEqual(res.statusCode, 404)
|
477 | })
|
478 | })
|