From 5b8267ac2d77dca959e7876b4a90a3f73202ee17 Mon Sep 17 00:00:00 2001 From: Gaara Date: Sat, 6 Jan 2018 22:53:15 +0800 Subject: [PATCH] swagger: use ajv replace z-schema breaking change: - validate error message no error.code, replaced by error.message in ajv - can not add additional properties, ajv can't set assumeAddition option --- package.json | 3 +-- src/swagger/helpers.js | 25 +++---------------------- src/swagger/index.js | 2 -- src/swagger/operation.js | 20 +++++++++++++------- src/swagger/operation.test.js | 2 +- src/swagger/parameter-value.js | 13 ++++++------- src/swagger/z-schema.js | 23 +++++++++++------------ src/swagger/z-schema.test.js | 12 ++++++------ yarn.lock | 2 +- 9 files changed, 42 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 6278a49..f178d3f 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,7 @@ "winston": "^2.2.0", "winston-common-sentry": "^0.1.1", "winston-daily-rotate-file": "^1.2.0", - "winston-logstash": "^0.2.11", - "z-schema": "^3.17.0" + "winston-logstash": "^0.2.11" }, "devDependencies": { "babel-cli": "^6.10.1", diff --git a/src/swagger/helpers.js b/src/swagger/helpers.js index 23272fa..a34cb49 100644 --- a/src/swagger/helpers.js +++ b/src/swagger/helpers.js @@ -89,20 +89,14 @@ exports.getContentType = (headers) => { return type } -exports.validateAgainstSchema = (validator, schema, value) => { - schema = _.cloneDeep(schema) // Clone the schema as z-schema alters the provided document - +exports.validateAgainstSchema = (validate, value) => { let response = { errors: [], warnings: [] } - if (!validator.validate(value, schema)) { - response.errors = _.map(validator.getLastErrors(), function (err) { - normalizeError(err) - - return err - }) + if (!validate(value)) { + response.errors = validate.errors } return response @@ -290,16 +284,3 @@ exports.convertValue = (schema, options, value) => { return value } - -function normalizeError (obj) { - // Remove superfluous error details - if (_.isUndefined(obj.schemaId)) { - delete obj.schemaId - } - - if (obj.inner) { - _.each(obj.inner, function (nObj) { - normalizeError(nObj) - }) - } -} diff --git a/src/swagger/index.js b/src/swagger/index.js index d0401fd..fea6eff 100644 --- a/src/swagger/index.js +++ b/src/swagger/index.js @@ -1,10 +1,8 @@ - const parser = require('ruo-swagger-parser') const parseUrl = require('url').parse const fs = require('fs') const _ = require('lodash') -const {resolveRefs: resolve} = require('json-refs') const Path = require('./path') const rc = require('../rc') diff --git a/src/swagger/operation.js b/src/swagger/operation.js index b663eac..72d0bfb 100644 --- a/src/swagger/operation.js +++ b/src/swagger/operation.js @@ -1,11 +1,11 @@ const _ = require('lodash') -const ZSchema = require('./z-schema') +const getAjv = require('./z-schema') const Parameter = require('./parameter') const helpers = require('./helpers') // addtional __data__ field can used with isSwitchOn to return addtional data in unit test -const validator = new ZSchema({assumeAdditional: ['__data__']}) +const ajv = getAjv() class Operation { constructor (method, definition, parent, pathToDefinition) { @@ -20,6 +20,7 @@ class Operation { }) this.consumes = this.consumes || parent.parent.consumes || [] + this.validates = {} } validateContentType (contentType, supportedTypes) { @@ -92,19 +93,24 @@ class Operation { return } - const realStatusCode = res ? String(res.statusCode) : 'default' + const maybeStatusCode = res ? String(res.statusCode) : 'default' let responseDef = _.find(this.definition.responses, (response, responseCode) => { - return responseCode === realStatusCode + return responseCode === maybeStatusCode }) - responseDef = responseDef || this.definition.responses.default + let realStatusCode = maybeStatusCode + if (!responseDef) { + realStatusCode = 'default' + responseDef = this.definition.responses.default + } + this.validates[realStatusCode] = this.validates[realStatusCode] || ajv.compile(responseDef.schema) if (responseDef && typeof responseDef === 'object') { // clone original obj const data = helpers.prune(JSON.parse(JSON.stringify(obj))) - const valid = validator.validate(data, responseDef.schema) + const valid = this.validates[realStatusCode](data) if (!valid) { - return validator.getLastErrors() + return this.validates[realStatusCode].errors } } } diff --git a/src/swagger/operation.test.js b/src/swagger/operation.test.js index e8c0b1d..405c3b4 100644 --- a/src/swagger/operation.test.js +++ b/src/swagger/operation.test.js @@ -62,7 +62,7 @@ describe('swagger/operation', () => { }]) expect(errors).to.not.eql(undefined) expect(errors.length).to.eql(1) - expect(errors[0].code).to.eql('OBJECT_MISSING_REQUIRED_PROPERTY') + expect(errors[0].message).to.eql('should have required property \'name\'') }) it('should convert value based on schema', () => { diff --git a/src/swagger/parameter-value.js b/src/swagger/parameter-value.js index 740658a..88951a3 100644 --- a/src/swagger/parameter-value.js +++ b/src/swagger/parameter-value.js @@ -1,14 +1,12 @@ const _ = require('lodash') const JsonRefs = require('json-refs') -const ZSchema = require('./z-schema') +const getAjv = require('./z-schema') const helpers = require('./helpers') -const validator = new ZSchema({ - breakOnFirstError: false, - ignoreUnknownFormats: true, - reportPathAsArray: true, - assumeAdditional: true +const ajv = getAjv({ + allErrors: process.env.NODE_ENV !== 'production', + unknownFormats: true }) class ParameterValue { @@ -86,7 +84,8 @@ class ParameterValue { if (!skipValidation) { // Validate against JSON Schema - result = helpers.validateAgainstSchema(validator, parameterObject.schema, value) + this.validate = this.validate || ajv.compile(parameterObject.schema) + result = helpers.validateAgainstSchema(this.validate, value) } if (result.errors.length > 0) { diff --git a/src/swagger/z-schema.js b/src/swagger/z-schema.js index 1c962d7..0d21489 100644 --- a/src/swagger/z-schema.js +++ b/src/swagger/z-schema.js @@ -1,5 +1,5 @@ -const _ = require('lodash') -const ZSchema = require('z-schema') +const isNumber = require('lodash.isnumber') +const Ajv = require('ajv') const validators = {} @@ -8,21 +8,20 @@ function returnTrue () { } validators.int32 = validators.int64 = function (val) { - // z-schema seems to continue processing the format even when the type is known to be invalid so we must do a type - // check prior to validating this format. - return _.isNumber(val) && val % 1 === 0 + return isNumber(val) } -// These format validators will always return 'true' because they are already type valid and there are no constraints -// on the format that would produce an invalid value. validators.byte = returnTrue validators.double = returnTrue validators.float = returnTrue validators.password = returnTrue -// Add the custom validators -_.each(validators, function (handler, name) { - ZSchema.registerFormat(name, handler) -}) +module.exports = (options) => { + const ajv = new Ajv(options) -module.exports = ZSchema + // Add the custom format validator + Object.keys(validators).forEach(function (name) { + ajv.addFormat(name, validators[name]) + }) + return ajv +} diff --git a/src/swagger/z-schema.test.js b/src/swagger/z-schema.test.js index 470c016..57a936d 100644 --- a/src/swagger/z-schema.test.js +++ b/src/swagger/z-schema.test.js @@ -1,8 +1,8 @@ const {expect} = require('chai') -const ZSchema = require('./z-schema') +const getAjv = require('./z-schema') -const validator = new ZSchema() +const validator = getAjv() describe('swagger/z-schema', () => { it('should validate full-date format', () => { @@ -22,16 +22,16 @@ describe('swagger/z-schema', () => { let valid - valid = validator.validate({ + valid = validator.validate(schema, { startedAt: 0, endedAt: '2016-01-13' - }, schema) + }) expect(valid).to.be.ok - valid = validator.validate({ + valid = validator.validate(schema, { startedAt: NaN, endedAt: '2016-01-13' - }, schema) + }) expect(valid).to.be.not.ok }) }) diff --git a/yarn.lock b/yarn.lock index 117bdeb..97d11fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4088,7 +4088,7 @@ yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" -z-schema@^3.17.0, z-schema@^3.19.0: +z-schema@^3.19.0: version "3.19.0" resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-3.19.0.tgz#d86e90e5d02113c7b8824ae477dd57208d17a5a8" dependencies: