You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
618 lines
14 KiB
618 lines
14 KiB
'use strict'
|
|
|
|
const { test } = require('tap')
|
|
const Fastify = require('fastify')
|
|
const Swagger = require('swagger-parser')
|
|
const yaml = require('js-yaml')
|
|
const fastifySwagger = require('../../../index')
|
|
const {
|
|
swaggerOption,
|
|
schemaBody,
|
|
schemaConsumes,
|
|
schemaExtension,
|
|
schemaHeaders,
|
|
schemaHeadersParams,
|
|
schemaParams,
|
|
schemaQuerystring,
|
|
schemaSecurity
|
|
} = require('../../../examples/options')
|
|
|
|
test('swagger should return valid swagger object', t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
fastify.get('/', () => {})
|
|
fastify.post('/', () => {})
|
|
fastify.get('/example', schemaQuerystring, () => {})
|
|
fastify.post('/example', schemaBody, () => {})
|
|
fastify.get('/parameters/:id', schemaParams, () => {})
|
|
fastify.get('/headers', schemaHeaders, () => {})
|
|
fastify.get('/headers/:id', schemaHeadersParams, () => {})
|
|
fastify.get('/security', schemaSecurity, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
|
|
const swaggerObject = fastify.swagger()
|
|
t.equal(typeof swaggerObject, 'object')
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
t.pass('valid swagger object')
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('swagger should return a valid swagger yaml', t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
fastify.get('/', () => {})
|
|
fastify.post('/', () => {})
|
|
fastify.get('/example', schemaQuerystring, () => {})
|
|
fastify.post('/example', schemaBody, () => {})
|
|
fastify.get('/parameters/:id', schemaParams, () => {})
|
|
fastify.get('/headers', schemaHeaders, () => {})
|
|
fastify.get('/headers/:id', schemaHeadersParams, () => {})
|
|
fastify.get('/security', schemaSecurity, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
|
|
const swaggerYaml = fastify.swagger({ yaml: true })
|
|
t.equal(typeof swaggerYaml, 'string')
|
|
|
|
try {
|
|
yaml.load(swaggerYaml)
|
|
t.pass('valid swagger yaml')
|
|
} catch (err) {
|
|
t.fail(err)
|
|
}
|
|
})
|
|
})
|
|
|
|
test('route options - deprecated', t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
const opts = {
|
|
schema: {
|
|
deprecated: true,
|
|
body: {
|
|
type: 'object',
|
|
properties: {
|
|
hello: { type: 'string' },
|
|
obj: {
|
|
type: 'object',
|
|
properties: {
|
|
some: { type: 'string' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fastify.get('/', opts, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
t.pass('valid swagger object')
|
|
t.ok(swaggerObject.paths['/'])
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('route options - meta', t => {
|
|
t.plan(9)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
const opts = {
|
|
schema: {
|
|
operationId: 'doSomething',
|
|
summary: 'Route summary',
|
|
tags: ['tag'],
|
|
description: 'Route description',
|
|
produces: ['application/octet-stream'],
|
|
consumes: ['application/x-www-form-urlencoded'],
|
|
externalDocs: {
|
|
description: 'Find more info here',
|
|
url: 'https://swagger.io'
|
|
}
|
|
}
|
|
}
|
|
|
|
fastify.get('/', opts, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
const definedPath = api.paths['/'].get
|
|
t.ok(definedPath)
|
|
t.equal(opts.schema.operationId, definedPath.operationId)
|
|
t.equal(opts.schema.summary, definedPath.summary)
|
|
t.same(opts.schema.tags, definedPath.tags)
|
|
t.equal(opts.schema.description, definedPath.description)
|
|
t.same(opts.schema.produces, definedPath.produces)
|
|
t.same(opts.schema.consumes, definedPath.consumes)
|
|
t.equal(opts.schema.externalDocs, definedPath.externalDocs)
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('route options - consumes', t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
fastify.get('/', schemaConsumes, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
const definedPath = api.paths['/'].get
|
|
t.ok(definedPath)
|
|
t.same(definedPath.parameters, [{
|
|
in: 'formData',
|
|
name: 'hello',
|
|
description: 'hello',
|
|
required: true,
|
|
type: 'string'
|
|
}])
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('route options - extension', t => {
|
|
t.plan(5)
|
|
const fastify = Fastify()
|
|
fastify.register(fastifySwagger, { swagger: { 'x-ternal': true } })
|
|
fastify.get('/', schemaExtension, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
t.ok(api['x-ternal'])
|
|
t.same(api['x-ternal'], true)
|
|
|
|
const definedPath = api.paths['/'].get
|
|
t.ok(definedPath)
|
|
t.same(definedPath['x-tension'], true)
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('route options - querystring', t => {
|
|
t.plan(3)
|
|
|
|
const opts = {
|
|
schema: {
|
|
querystring: {
|
|
type: 'object',
|
|
properties: {
|
|
hello: { type: 'string' },
|
|
world: { type: 'string', description: 'world description' }
|
|
},
|
|
required: ['hello']
|
|
}
|
|
}
|
|
}
|
|
|
|
const fastify = Fastify()
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
fastify.get('/', opts, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
const definedPath = api.paths['/'].get
|
|
t.ok(definedPath)
|
|
t.same(definedPath.parameters, [
|
|
{
|
|
in: 'query',
|
|
name: 'hello',
|
|
type: 'string',
|
|
required: true
|
|
},
|
|
{
|
|
in: 'query',
|
|
name: 'world',
|
|
type: 'string',
|
|
required: false,
|
|
description: 'world description'
|
|
}
|
|
])
|
|
})
|
|
.catch(function (err) {
|
|
t.fail(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('swagger json output should not omit enum part in params config', t => {
|
|
t.plan(3)
|
|
const opts = {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
enumKey: { type: 'string', enum: ['enum1', 'enum2'] }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const fastify = Fastify()
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
fastify.get('/test/:enumKey', opts, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
Swagger.validate(swaggerObject)
|
|
.then((api) => {
|
|
const definedPath = api.paths['/test/{enumKey}'].get
|
|
t.ok(definedPath)
|
|
t.same(definedPath.parameters, [{
|
|
in: 'path',
|
|
name: 'enumKey',
|
|
type: 'string',
|
|
enum: ['enum1', 'enum2'],
|
|
required: true
|
|
}])
|
|
})
|
|
.catch(err => {
|
|
t.error(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('custom verbs should not be interpreted as path params', t => {
|
|
t.plan(3)
|
|
const opts = {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const fastify = Fastify()
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
fastify.get('/resource/:id/sub-resource::watch', opts, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
const swaggerObject = fastify.swagger()
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then((api) => {
|
|
const definedPath = api.paths['/resource/{id}/sub-resource:watch'].get
|
|
t.ok(definedPath)
|
|
t.same(definedPath.parameters, [{
|
|
in: 'path',
|
|
name: 'id',
|
|
type: 'string',
|
|
required: true
|
|
}])
|
|
})
|
|
.catch(err => {
|
|
console.log(err)
|
|
t.error(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('swagger json output should not omit consume in querystring schema', async (t) => {
|
|
t.plan(1)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
const schemaQuerystring = {
|
|
schema: {
|
|
querystring: {
|
|
type: 'object',
|
|
properties: {
|
|
hello: {
|
|
type: 'object',
|
|
'x-consume': 'application/json',
|
|
required: ['bar'],
|
|
properties: {
|
|
bar: { type: 'string' },
|
|
baz: { type: 'string' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fastify.get('/', schemaQuerystring, () => {})
|
|
|
|
await fastify.ready()
|
|
|
|
try {
|
|
fastify.swagger()
|
|
t.fail('error was not thrown')
|
|
} catch (err) {
|
|
if (err.message.startsWith('Complex serialization is not supported by Swagger')) {
|
|
t.pass('error was thrown')
|
|
} else {
|
|
t.error(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
test('swagger should not support Links', t => {
|
|
t.plan(2)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
fastify.get('/user/:id', {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'the user identifier, as userId'
|
|
}
|
|
},
|
|
required: ['id']
|
|
},
|
|
response: {
|
|
200: {
|
|
type: 'object',
|
|
properties: {
|
|
uuid: {
|
|
type: 'string',
|
|
format: 'uuid'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
links: {
|
|
200: {
|
|
address: {
|
|
operationId: 'getUserAddress',
|
|
parameters: {
|
|
id: '$request.path.id'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.get('/user/:id/address', {
|
|
schema: {
|
|
operationId: 'getUserAddress',
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'the user identifier, as userId'
|
|
}
|
|
},
|
|
required: ['id']
|
|
},
|
|
response: {
|
|
200: {
|
|
type: 'string'
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
|
|
t.throws(() => fastify.swagger(), new Error('Swagger (Open API v2) does not support Links. Upgrade to OpenAPI v3 (see fastify-swagger readme)'))
|
|
})
|
|
})
|
|
|
|
test('security headers ignored when declared in security and securityScheme', t => {
|
|
t.plan(7)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, swaggerOption)
|
|
|
|
fastify.get('/address1/:id', {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string' }
|
|
}
|
|
},
|
|
headers: {
|
|
type: 'object',
|
|
properties: {
|
|
apiKey: {
|
|
type: 'string',
|
|
description: 'api token'
|
|
},
|
|
somethingElse: {
|
|
type: 'string',
|
|
description: 'common field'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.get('/address2/:id', {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string' }
|
|
}
|
|
},
|
|
headers: {
|
|
type: 'object',
|
|
properties: {
|
|
authKey: {
|
|
type: 'string',
|
|
description: 'auth token'
|
|
},
|
|
somethingElse: {
|
|
type: 'string',
|
|
description: 'common field'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
|
|
const swaggerObject = fastify.swagger()
|
|
t.equal(typeof swaggerObject, 'object')
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
t.pass('valid swagger object')
|
|
t.ok(api.paths['/address1/{id}'].get.parameters.find(({ name }) => (name === 'id')))
|
|
t.ok(api.paths['/address2/{id}'].get.parameters.find(({ name }) => (name === 'id')))
|
|
t.notOk(api.paths['/address1/{id}'].get.parameters.find(({ name }) => (name === 'apiKey')))
|
|
t.ok(api.paths['/address2/{id}'].get.parameters.find(({ name }) => (name === 'authKey')))
|
|
})
|
|
.catch(function (err) {
|
|
t.error(err)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('security querystrings ignored when declared in security and securityScheme', t => {
|
|
t.plan(7)
|
|
const fastify = Fastify()
|
|
|
|
fastify.register(fastifySwagger, {
|
|
swagger: {
|
|
securityDefinitions: {
|
|
apiKey: {
|
|
type: 'apiKey',
|
|
name: 'apiKey',
|
|
in: 'query'
|
|
}
|
|
},
|
|
security: [{
|
|
apiKey: []
|
|
}]
|
|
}
|
|
})
|
|
|
|
fastify.get('/address1/:id', {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string' }
|
|
}
|
|
},
|
|
querystring: {
|
|
type: 'object',
|
|
properties: {
|
|
apiKey: {
|
|
type: 'string',
|
|
description: 'api token'
|
|
},
|
|
somethingElse: {
|
|
type: 'string',
|
|
description: 'common field'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.get('/address2/:id', {
|
|
schema: {
|
|
params: {
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string' }
|
|
}
|
|
},
|
|
querystring: {
|
|
type: 'object',
|
|
properties: {
|
|
authKey: {
|
|
type: 'string',
|
|
description: 'auth token'
|
|
},
|
|
somethingElse: {
|
|
type: 'string',
|
|
description: 'common field'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, () => {})
|
|
|
|
fastify.ready(err => {
|
|
t.error(err)
|
|
|
|
const swaggerObject = fastify.swagger()
|
|
t.equal(typeof swaggerObject, 'object')
|
|
|
|
Swagger.validate(swaggerObject)
|
|
.then(function (api) {
|
|
t.pass('valid swagger object')
|
|
t.ok(api.paths['/address1/{id}'].get.parameters.find(({ name }) => (name === 'somethingElse')))
|
|
t.ok(api.paths['/address2/{id}'].get.parameters.find(({ name }) => (name === 'somethingElse')))
|
|
t.notOk(api.paths['/address1/{id}'].get.parameters.find(({ name }) => (name === 'apiKey')))
|
|
t.ok(api.paths['/address2/{id}'].get.parameters.find(({ name }) => (name === 'authKey')))
|
|
})
|
|
.catch(function (err) {
|
|
t.error(err)
|
|
})
|
|
})
|
|
})
|