swagger-tools
Version:
Various tools for using and integrating with Swagger.
272 lines (221 loc) • 7.99 kB
JavaScript
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Apigee Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
;
// Done this way to make the Browserify build smaller
var _ = {
each: require('lodash-compat/collection/each'),
indexOf: require('lodash-compat/array/indexOf'),
isArray: require('lodash-compat/lang/isArray'),
isPlainObject: require('lodash-compat/lang/isPlainObject'),
isString: require('lodash-compat/lang/isString'),
isUndefined: require('lodash-compat/lang/isUndefined'),
reduce: require('lodash-compat/collection/reduce')
};
var JsonRefs = require('json-refs');
var traverse = require('traverse');
var ZSchema = require('z-schema');
var customJsonSchemaFormats = ['byte', 'double', 'float', 'int32', 'int64', 'mime-type', 'uri-template'];
var draft04Json = require('../schemas/json-schema-draft-04.json');
var draft04Url = 'http://json-schema.org/draft-04/schema';
var specCache = {};
module.exports.registerCustomFormats = function (json) {
traverse(json).forEach(function () {
var name = this.key;
var format = this.node;
if (name === 'format' && _.indexOf(ZSchema.getRegisteredFormats(), format) === -1) {
ZSchema.registerFormat(format, function () {
return true;
});
}
});
};
module.exports.createJsonValidator = function (schemas) {
var validator = new ZSchema({
breakOnFirstError: false,
reportPathAsArray: true
});
var result;
// Add the draft-04 spec
validator.setRemoteReference(draft04Url, draft04Json);
// Swagger uses some unsupported/invalid formats so just make them all pass
_.each(customJsonSchemaFormats, function (format) {
ZSchema.registerFormat(format, function () {
return true;
});
});
// Compile and validate the schemas
if (!_.isUndefined(schemas)) {
result = validator.compileSchema(schemas);
// If there is an error, it's unrecoverable so just blow the eff up
if (result === false) {
console.error('JSON Schema file' + (schemas.length > 1 ? 's are' : ' is') + ' invalid:');
_.each(validator.getLastErrors(), function (err) {
console.error(' ' + (_.isArray(err.path) ? JsonRefs.pathToPointer(err.path) : err.path) + ': ' + err.message);
});
throw new Error('Unable to create validator due to invalid JSON Schema');
}
}
return validator;
};
module.exports.formatResults = function (results) {
if (results) {
// Update the results based on its content to indicate success/failure accordingly
results = (results.errors.length + results.warnings.length +
_.reduce(results.apiDeclarations, function (count, aResult) {
if (aResult) {
count += aResult.errors.length + aResult.warnings.length;
}
return count;
}, 0) > 0) ? results : undefined;
}
return results;
};
var getErrorCount = module.exports.getErrorCount = function (results) {
var errors = 0;
if (results) {
errors = results.errors.length;
_.each(results.apiDeclarations, function (adResults) {
if (adResults) {
errors += adResults.errors.length;
}
});
}
return errors;
};
var coerceVersion = function (version) {
// Convert the version to a number (Required for helpers.getSpec)
if (version && !_.isString(version)) {
version = version.toString();
// Handle rounding issues (Only required for when Swagger version ends in '.0')
if (version.indexOf('.') === -1) {
version += '.0';
}
}
return version;
};
/**
* Returns the proper specification based on the human readable version.
*
* @param {string} version - The human readable Swagger version (Ex: 1.2)
* @param {[boolean=false]} throwError - Throw an error if the version could not be identified
*
* @returns the corresponding Swagger Specification object or undefined if there is none
*/
module.exports.getSpec = function (version, throwError) {
var spec;
version = coerceVersion(version);
spec = specCache[version];
if (_.isUndefined(spec)) {
switch (version) {
case '1.2':
spec = require('../lib/specs').v1_2; // jshint ignore:line
break;
case '2.0':
spec = require('../lib/specs').v2_0; // jshint ignore:line
break;
default:
if (throwError === true) {
throw new Error('Unsupported Swagger version: ' + version);
}
}
}
return spec;
};
/**
* Atempts to figure out the Swagger version from the Swagger document.
*
* @param {object} document - The Swagger document
*
* @returns the Swagger version or undefined if the document is not a Swagger document
*/
module.exports.getSwaggerVersion = function (document) {
return _.isPlainObject(document) ? coerceVersion(document.swaggerVersion || document.swagger) : undefined;
};
module.exports.printValidationResults = function (version, apiDOrSO, apiDeclarations, results, printSummary) {
var hasErrors = getErrorCount(results) > 0;
var stream = hasErrors ? console.error : console.log;
var pluralize = function (string, count) {
return count === 1 ? string : string + 's';
};
var printErrorsOrWarnings = function (header, entries, indent) {
if (header) {
stream(header + ':');
stream();
}
_.each(entries, function (entry) {
stream(new Array(indent + 1).join(' ') + JsonRefs.pathToPointer(entry.path) + ': ' + entry.message);
if (entry.inner) {
printErrorsOrWarnings (undefined, entry.inner, indent + 2);
}
});
if (header) {
stream();
}
};
var errorCount = 0;
var warningCount = 0;
stream();
if (results.errors.length > 0) {
errorCount += results.errors.length;
printErrorsOrWarnings('API Errors', results.errors, 2);
}
if (results.warnings.length > 0) {
warningCount += results.warnings.length;
printErrorsOrWarnings('API Warnings', results.warnings, 2);
}
if (results.apiDeclarations) {
results.apiDeclarations.forEach(function (adResult, index) {
if (!adResult) {
return;
}
var name = apiDeclarations[index].resourcePath || index;
if (adResult.errors.length > 0) {
errorCount += adResult.errors.length;
printErrorsOrWarnings(' API Declaration (' + name + ') Errors', adResult.errors, 4);
}
if (adResult.warnings.length > 0) {
warningCount += adResult.warnings.length;
printErrorsOrWarnings(' API Declaration (' + name + ') Warnings', adResult.warnings, 4);
}
});
}
if (printSummary) {
if (errorCount > 0) {
stream(errorCount + ' ' + pluralize('error', errorCount) + ' and ' + warningCount + ' ' +
pluralize('warning', warningCount));
} else {
stream('Validation succeeded but with ' + warningCount + ' ' + pluralize('warning', warningCount));
}
}
stream();
};
module.exports.swaggerOperationMethods = [
'DELETE',
'GET',
'HEAD',
'OPTIONS',
'PATCH',
'POST',
'PUT'
];