swagger-endpoint-validator
Advanced tools
Comparing version 2.0.0 to 2.0.1
@@ -19,2 +19,3 @@ const debug = require('debug')('swagger-endpoint-validator'); | ||
* @param {boolean} [options.validateResponses=true] - true to validate the responses. | ||
* @param {string|boolean} [options.validateFormats='fast'] - specifies the strictness of validation of string formats (one of 'fast', 'full' or false). | ||
* @param {string} [options.validationEndpoint=null] - endpoint to do schemas validation agains the OpenAPI schema. | ||
@@ -21,0 +22,0 @@ * @param {string} options.format - format of the OpenAPI specification documentation. |
const util = require('util'); | ||
function SwaggerValidator(type, message) { | ||
function SwaggerValidator(type, message, status) { | ||
Error.captureStackTrace(this, this.constructor); | ||
@@ -8,2 +8,3 @@ this.name = this.constructor.name; | ||
this.message = message; | ||
this.status = status; | ||
} | ||
@@ -13,5 +14,5 @@ | ||
const errorFactory = type => message => new SwaggerValidator(type, message); | ||
const errorFactory = type => (message, status = 500) => new SwaggerValidator(type, message, status); | ||
module.exports = errorFactory; |
@@ -23,8 +23,11 @@ const debug = require('debug')('swagger-endpoint-validator:options'); | ||
const selectedFormat = options.format || SUPPORTED_FORMATS.YAML; | ||
const normalizedOptions = { | ||
validateRequests: options.validateRequests || true, | ||
validateResponses: options.validateResponses || true, | ||
validateRequests: options.validateRequests !== undefined ? options.validateRequests : true, | ||
validateResponses: options.validateResponses !== undefined ? options.validateResponses : true, | ||
validationEndpoint: options.validationEndpoint || null, | ||
validateFormats: options.validateFormats !== undefined ? options.validateFormats : 'fast', | ||
format: options.format || SUPPORTED_FORMATS.YAML, | ||
[options.format]: formatOptions[options.format], | ||
[options.format]: formatOptions[selectedFormat], | ||
}; | ||
@@ -31,0 +34,0 @@ |
@@ -25,3 +25,3 @@ const debug = require('debug')('swagger-endpoint-validator:openapi-spec'); | ||
debug(`Converting specification from Swagger v2 to OpenAPI v3: ${JSON.stringify(doc)}`); | ||
debug('Converting specification from Swagger v2 to OpenAPI v3...'); | ||
// swagger2openapi does the conversion between OpenAPI 2.0 and OpenAPI 3.0, but it has a small error: | ||
@@ -39,3 +39,3 @@ // It doesn't add 'type: object' to the definitions. | ||
const conversion = await apiConverter.convertObj(modifiedDoc, {}); | ||
debug(`Specification converted to OpenAPI v3: ${JSON.stringify(conversion.spec)}`); | ||
debug('Specification converted to OpenAPI v3!'); | ||
@@ -55,3 +55,3 @@ return conversion.openapi; | ||
const openapi = await Enforcer(doc); | ||
debug(`Specification dereferenced and validated!: ${JSON.stringify(openapi)}`); | ||
debug('Specification dereferenced and validated!'); | ||
@@ -58,0 +58,0 @@ return { doc, openapi }; |
@@ -19,3 +19,3 @@ const debug = require('debug')('swagger-endpoint-validator:validation-endpoint'); | ||
if (result.error) { | ||
res.status(500).json(result.error); | ||
res.status(400).json(result.error); | ||
} else { | ||
@@ -22,0 +22,0 @@ res.sendStatus(200); |
@@ -26,2 +26,4 @@ const debug = require('debug')('swagger-endpoint-validator:validator'); | ||
validateResponses: options.validateResponses, | ||
validateFormats: options.validateFormats, | ||
ignorePaths: options.validationEndpoint ? new RegExp(`.*${options.validationEndpoint}$`, 'i') : null, | ||
}).install(app); | ||
@@ -52,8 +54,18 @@ | ||
fixture, | ||
input, | ||
request, | ||
method, | ||
} = body; | ||
if (!endpoint) { | ||
throw SwaggerValidatorError('Required \'endpoint\' missing in requestBody', 400); | ||
} | ||
if (!method) { | ||
throw SwaggerValidatorError('Required \'method\' missing in requestBody', 400); | ||
} | ||
if (!fixture) { | ||
throw SwaggerValidatorError('Required \'fixture\' missing in requestBody', 400); | ||
} | ||
let result; | ||
if (input) { | ||
if (request) { | ||
result = openAPISpec.request({ | ||
@@ -67,7 +79,7 @@ method, | ||
if (!path) { | ||
throw SwaggerValidatorError(`Path ${endpoint} not found in the specification`); | ||
throw SwaggerValidatorError(`endpoint '${endpoint}' not found in the specification`); | ||
} | ||
const operation = path[method]; | ||
const operation = path[method.toLowerCase()]; | ||
if (!operation) { | ||
throw SwaggerValidatorError(`Method ${method} for path ${endpoint} not found in the specification`); | ||
throw SwaggerValidatorError(`method '${method.toLowerCase()}' for endpoint '${endpoint}' not found in the specification`); | ||
} | ||
@@ -74,0 +86,0 @@ result = operation.response(200, fixture); |
{ | ||
"name": "swagger-endpoint-validator", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"description": "A validator of API endpoints to check that input and output match with the swagger specification for the API", | ||
@@ -38,3 +38,2 @@ "main": "index.js", | ||
"swagger-jsdoc": "^4.0.0", | ||
"swagger-model-validator": "^3.0.18", | ||
"swagger-ui-express": "^4.1.4", | ||
@@ -41,0 +40,0 @@ "swagger2openapi": "^6.0.2" |
311
README.md
@@ -18,6 +18,6 @@ | ||
### init(app: ExpressApp, validatorOptions: ConfigFile, format: String) | ||
### init(app: ExpressApp, options: ConfigFile) | ||
```js | ||
validator.init(app, validatorOptions, format); | ||
validator.init(app, options); | ||
``` | ||
@@ -28,307 +28,6 @@ | ||
- `app` is the Express app instance. | ||
- `format` is an string to choose the format we want to create the swagger docs: `jsdoc` or `yaml`. Default `jsdoc`. | ||
- `validatorOptions` is a configuration object that has different format depending on `format`: | ||
- `options` is the configuration object used by the validator. | ||
**`validatorOptions` for _jsdoc_** | ||
## TO DO! | ||
```js | ||
const validatorOptions = { | ||
swaggerDefinition: { | ||
info: { | ||
description: 'Documentation for Service API', | ||
title: 'Service API', | ||
version: '1.0.0', | ||
contact: { email: 'your_email@guidesmiths.com' }, | ||
}, | ||
host: 'localhost:5000', | ||
basePath: '/', | ||
produces: ['application/json'], | ||
schemes: ['http'], | ||
securityDefinitions: { | ||
JWT: { | ||
type: 'apiKey', | ||
in: 'header', | ||
name: 'Authorization', | ||
description: '', | ||
}, | ||
}, | ||
}, | ||
basedir: process.cwd(), // app absolute path | ||
files: ['./test/**/**.js'], // path to the API handle folder, related to basedir | ||
route: { | ||
url: '/test/docs/api', | ||
docs: '/test/docs/api.json', | ||
}, | ||
}; | ||
``` | ||
**`validatorOptions` for _yaml_** | ||
```js | ||
const validatorOptions = { | ||
swaggerDefinition: { | ||
info: { | ||
description: 'Documentation for Service API', | ||
title: 'Service API', | ||
version: '1.0.0', | ||
contact: { email: 'your_email@guidesmiths.com' }, | ||
}, | ||
basePath: '/', | ||
}, | ||
apis: ['./test/**/**.js'], // paths to the API files | ||
url: '/test/docs/api', // optional path to serve the API documentation | ||
}; | ||
``` | ||
### validateAPIInput(input: Object, request: RequestObject) | ||
```js | ||
validator.validateAPIInput(input, request); | ||
``` | ||
where: | ||
- `input` is the payload to be validated. | ||
- `request` is request object. | ||
It will use the configuration used in the initialization to look for the endpoint and the schema to validate. | ||
**JSDOC Example** | ||
```js | ||
/** | ||
* @typedef Input | ||
* @property {string} name.required | ||
*/ | ||
/** | ||
* @typedef Output | ||
* @property {string} name.required | ||
* @property {string} result.required | ||
*/ | ||
/** | ||
* @route GET /test-invalid-output | ||
* @summary Create a new group | ||
* @group test - Everything about tests | ||
* @param {Input.model} body.body.required | ||
* @returns {Output.model} 200 - Successful operation | ||
* @returns {Error.model} <any> - Error message | ||
* @security JWT | ||
*/ | ||
app.get('/test-invalid-input', (req, res) => { | ||
try { | ||
validator.validateAPIInput({}, req); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
``` | ||
**YAML Example** | ||
```js | ||
/** | ||
* @swagger | ||
* /test-invalid-input: | ||
* post: | ||
* description: Test POST /test-invalid-input | ||
* tags: [Test] | ||
* produces: | ||
* - application/json | ||
* parameters: | ||
* - name: body | ||
* description: Input payload | ||
* required: true | ||
* type: object | ||
* schema: | ||
* - $ref: '#/definitions/Input' | ||
* responses: | ||
* 200: | ||
* description: successful operation | ||
*/ | ||
app.post('/test-invalid-input', (req, res) => { | ||
try { | ||
const result = validator.validateAPIInput({}, req); | ||
res.status(200).json(result); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
``` | ||
### validateAPIOutput(output: Object, request: RequestObject) | ||
```js | ||
validator.validateAPIOutput(output, request); | ||
``` | ||
where: | ||
- `output` is the payload to be validated. | ||
- `request` is request object. | ||
It will use the configuration used in the initialization to look for the endpoint and the schema to validate. | ||
**JSDOC Example** | ||
```js | ||
/** | ||
* @typedef Input | ||
* @property {string} name.required | ||
*/ | ||
/** | ||
* @typedef Output | ||
* @property {string} name.required | ||
* @property {string} result.required | ||
*/ | ||
/** | ||
* @route GET /test-invalid-output | ||
* @summary Create a new group | ||
* @group test - Everything about tests | ||
* @param {Input.model} body.body.required | ||
* @returns {Output.model} 200 - Successful operation | ||
* @returns {Error.model} <any> - Error message | ||
* @security JWT | ||
*/ | ||
app.get('/test-invalid-output', (req, res) => { | ||
const validInputModel = { name: 'Name is required' }; | ||
try { | ||
validator.validateAPIInput(validInputModel, req); | ||
validator.validateAPIOutput({}, req); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
``` | ||
**YAML Example** | ||
```js | ||
/** | ||
* @swagger | ||
* /test-invalid-output: | ||
* get: | ||
* description: Test GET /test-invalid-output | ||
* tags: [Test] | ||
* produces: | ||
* - application/json | ||
* responses: | ||
* 200: | ||
* description: successful operation | ||
* schema: | ||
* $ref: '#/definitions/Output' | ||
*/ | ||
app.get('/test-invalid-output', (req, res) => { | ||
try { | ||
const result = validator.validateAPIOutput({}, req); | ||
res.status(200).json(result); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
``` | ||
### Example of a valid request with the validator | ||
**JSDOC** | ||
```js | ||
/** | ||
* @typedef Input | ||
* @property {string} name.required | ||
*/ | ||
/** | ||
* @typedef Output | ||
* @property {string} name.required | ||
* @property {string} result.required | ||
*/ | ||
/** | ||
* @route GET /test-valid | ||
* @summary Create a new group | ||
* @group test - Everything about tests | ||
* @param {Input.model} body.body.required | ||
* @returns {Output.model} 200 - Successful operation | ||
* @returns {Error.model} <any> - Error message | ||
* @security JWT | ||
*/ | ||
app.get('/test-valid', (req, res) => { | ||
const validInputModel = { name: 'Name is required' }; | ||
const validOutputModel = { name: 'Name is required', result: 'Valid result' }; | ||
validator.validateAPIInput(validInputModel, req); | ||
validator.validateAPIOutput(validOutputModel, req); | ||
res.status(200).json({ success: true }); | ||
}); | ||
``` | ||
**YAML** | ||
```js | ||
/** | ||
* @swagger | ||
* /test-valid-input: | ||
* post: | ||
* description: Test POST /test-valid-input | ||
* tags: [Test] | ||
* produces: | ||
* - application/json | ||
* parameters: | ||
* - name: body | ||
* description: Input payload | ||
* required: true | ||
* type: object | ||
* schema: | ||
* - $ref: '#/definitions/Input' | ||
* responses: | ||
* 200: | ||
* description: successful operation | ||
*/ | ||
app.post('/test-valid-input', (req, res) => { | ||
const validInputModel = { name: 'Name is required' }; | ||
try { | ||
const result = validator.validateAPIInput(validInputModel, req); | ||
res.status(200).json(result); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
/** | ||
* @swagger | ||
* /test-valid-output: | ||
* get: | ||
* description: Test GET /test-valid-output | ||
* tags: [Test] | ||
* produces: | ||
* - application/json | ||
* parameters: | ||
* - name: body | ||
* description: Input payload | ||
* required: true | ||
* type: object | ||
* schema: | ||
* - $ref: '#/definitions/Input' | ||
* responses: | ||
* 200: | ||
* description: successful operation | ||
* schema: | ||
* $ref: '#/definitions/Output' | ||
*/ | ||
app.get('/test-valid-output', (req, res) => { | ||
const validInputModel = { name: 'Name is required' }; | ||
const validOutputModel = { name: 'Name is required', result: 'Valid result' }; | ||
try { | ||
validator.validateAPIInput(validInputModel, req); | ||
const result = validator.validateAPIOutput(validOutputModel, req); | ||
res.status(200).json(result); | ||
} catch (error) { | ||
res.status(404).json({ error }); | ||
} | ||
}); | ||
``` | ||
Improve this doc. |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
8
1005
0
47963
31
- Removedswagger-model-validator@^3.0.18
- Removedswagger-model-validator@3.0.21(transitive)