Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

swagger-tools

Package Overview
Dependencies
Maintainers
1
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

swagger-tools - npm Package Compare versions

Comparing version 0.7.0 to 0.7.1

36

lib/helpers.js

@@ -86,2 +86,18 @@ /*

module.exports.getErrorCount = function getErrorCount (results) {
var errors = 0;
if (results) {
errors = results.errors.length;
_.each(results.apiDeclarations, function (adResults) {
if (adResults) {
errors += adResults.errors.length;
}
});
}
return errors;
};
/**

@@ -145,4 +161,6 @@ * Returns the proper specification based on the human readable version.

var printErrorsOrWarnings = function printErrorsOrWarnings (header, entries, indent) {
console.error(header);
console.error();
if (header) {
console.error(header + ':');
console.error();
}

@@ -153,7 +171,9 @@ _.each(entries, function (entry) {

if (entry.inner) {
printErrorsOrWarnings (header, entry.inner, indent + 2);
printErrorsOrWarnings (undefined, entry.inner, indent + 2);
}
});
console.error();
if (header) {
console.error();
}
};

@@ -168,3 +188,3 @@ var errorCount = 0;

printErrorsOrWarnings('API Errors:', results.errors, 2);
printErrorsOrWarnings('API Errors', results.errors, 2);
}

@@ -175,3 +195,3 @@

printErrorsOrWarnings('API Warnings:', results.warnings, 2);
printErrorsOrWarnings('API Warnings', results.warnings, 2);
}

@@ -190,3 +210,3 @@

printErrorsOrWarnings(' API Declaration (' + name + ') Errors:', adResult.errors, 4);
printErrorsOrWarnings(' API Declaration (' + name + ') Errors', adResult.errors, 4);
}

@@ -197,3 +217,3 @@

printErrorsOrWarnings(' API Declaration (' + name + ') Warnings:', adResult.warnings, 4);
printErrorsOrWarnings(' API Declaration (' + name + ') Warnings', adResult.warnings, 4);
}

@@ -200,0 +220,0 @@ });

@@ -32,2 +32,3 @@ /*

var SparkMD5 = require('spark-md5');
var swaggerConverter = require('swagger-converter');
var traverse = require('traverse');

@@ -229,7 +230,12 @@ var validators = require('./validators');

var handleValidationError = function handleValidationError (results, callback) {
var err = new Error('The Swagger document is invalid and model composition is not possible');
var err = new Error('The Swagger document(s) are invalid');
err.errors = results.errors;
err.failedValidation = true;
err.warnings = results.warnings;
if (results.apiDeclarations) {
err.apiDeclarations = results.apiDeclarations;
}
callback(err);

@@ -1158,3 +1164,3 @@ };

return callback(err);
} else if (helpers.formatResults(results)) {
} else if (helpers.getErrorCount(results) > 0) {
return handleValidationError(results, callback);

@@ -1175,3 +1181,3 @@ }

if (helpers.formatResults(results)) {
if (helpers.getErrorCount(results) > 0) {
return handleValidationError(results, callback);

@@ -1364,3 +1370,3 @@ }

return callback(err);
} else if (helpers.formatResults(results)) {
} else if (helpers.getErrorCount(results) > 0) {
return handleValidationError(results, callback);

@@ -1376,3 +1382,65 @@ }

/**
* Converts the Swagger 1.2 documents to a Swagger 2.0 document.
*
* @param {object} resourceListing - The Swagger Resource Listing
* @param {object[]} [apiDeclarations] - The array of Swagger API Declarations
* @param {boolean=false} [skipValidation] - Whether or not to skip validation
* @param {resultCallback} callback - The result callback
*
* @returns the converted Swagger document
*
* @throws Error if the arguments provided are not valid
*/
Specification.prototype.convert = function (resourceListing, apiDeclarations, skipValidation, callback) {
var doConvert = function doConvert (resourceListing, apiDeclarations) {
callback(undefined, swaggerConverter(resourceListing, apiDeclarations));
}.bind(this);
if (this.version !== '1.2') {
throw new Error('Specification#convert only works for Swagger 1.2');
}
// Validate arguments
if (_.isUndefined(resourceListing)) {
throw new Error('resourceListing is required');
} else if (!_.isPlainObject(resourceListing)) {
throw new TypeError('resourceListing must be an object');
}
// API Declarations are optional because swagger-converter was written to support it
if (_.isUndefined(apiDeclarations)) {
apiDeclarations = [];
}
if (!_.isArray(apiDeclarations)) {
throw new TypeError('apiDeclarations must be an array');
}
if (arguments.length < 4) {
callback = arguments[arguments.length - 1];
}
if (_.isUndefined(callback)) {
throw new Error('callback is required');
} else if (!_.isFunction(callback)) {
throw new TypeError('callback must be a function');
}
if (skipValidation === true) {
doConvert(resourceListing, apiDeclarations);
} else {
this.validate(resourceListing, apiDeclarations, function (err, results) {
if (err) {
return callback(err);
} else if (helpers.getErrorCount(results) > 0) {
return handleValidationError(results, callback);
}
doConvert(resourceListing, apiDeclarations);
});
}
};
module.exports.v1 = module.exports.v1_2 = new Specification('1.2'); // jshint ignore:line
module.exports.v2 = module.exports.v2_0 = new Specification('2.0'); // jshint ignore:line

@@ -160,21 +160,31 @@ /*

/**
* Validates the request's content type (when necessary).
* Validates the request or response content type (when necessary).
*
* @param {string[]} gConsumes - The valid consumes at the API scope
* @param {string[]} oConsumes - The valid consumes at the operation scope
* @param {object} req - The request
* @param {string[]} gPOrC - The valid consumes at the API scope
* @param {string[]} oPOrC - The valid consumes at the operation scope
* @param {object} reqOrRes - The request or response
*
* @throws Error if the content type is invalid
*/
module.exports.validateContentType = function validateContentType (gConsumes, oConsumes, req) {
module.exports.validateContentType = function validateContentType (gPOrC, oPOrC, reqOrRes) {
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
var contentType = req.headers['content-type'] || 'application/octet-stream';
var consumes = _.union(oConsumes, gConsumes);
var isResponse = typeof reqOrRes.end === 'function';
var contentType = isResponse ? reqOrRes.getHeader('content-type') : reqOrRes.headers['content-type'];
var pOrC = _.union(gPOrC, oPOrC);
if (!contentType) {
if (isResponse) {
contentType = 'text/plain';
} else {
contentType = 'application/octet-stream';
}
}
// Get only the content type
contentType = contentType.split(';')[0];
// Validate content type (Only for POST/PUT per HTTP spec)
if (consumes.length > 0 && ['POST', 'PUT'].indexOf(req.method) !== -1 && consumes.indexOf(contentType) === -1) {
throw new Error('Invalid content type (' + contentType + '). These are valid: ' + consumes.join(', '));
if (pOrC.length > 0 && (isResponse ?
true :
['POST', 'PUT'].indexOf(reqOrRes.method) !== -1) && pOrC.indexOf(contentType) === -1) {
throw new Error('Invalid content type (' + contentType + '). These are valid: ' + pOrC.join(', '));
}

@@ -443,2 +453,5 @@ };

break;
case 'void':
result = _.isUndefined(val);
break;
}

@@ -451,3 +464,5 @@ }

throwErrorWithCode('INVALID_TYPE',
'Not a valid ' + (_.isUndefined(format) ? '' : format + ' ') + type + ': ' + val);
type !== 'void' ?
'Not a valid ' + (_.isUndefined(format) ? '' : format + ' ') + type + ': ' + val :
'Void does not allow a value');
}

@@ -492,9 +507,16 @@ };

};
var type = schema.type;
// Resolve the actual schema object
schema = resolveSchema(schema);
if (!type) {
if (!schema.schema) {
type = 'void';
} else {
schema = resolveSchema(schema);
type = schema.type || 'object';
}
}
try {
// Always perform this check even if there is no value
if (schema.type === 'array') {
if (type === 'array') {
validateArrayType(schema);

@@ -515,13 +537,13 @@ }

if (schema.type === 'array') {
if (type === 'array') {
if (!_.isUndefined(schema.items)) {
validateTypeAndFormat(val, schema.type === 'array' ? schema.items.type : schema.type,
schema.type === 'array' && schema.items.format ?
validateTypeAndFormat(val, type === 'array' ? schema.items.type : type,
type === 'array' && schema.items.format ?
schema.items.format :
schema.format);
} else {
validateTypeAndFormat(val, schema.type, schema.format);
validateTypeAndFormat(val, type, schema.format);
}
} else {
validateTypeAndFormat(val, schema.type, schema.format);
validateTypeAndFormat(val, type, schema.format);
}

@@ -533,3 +555,3 @@

// Validate maximum
validateMaximum(val, schema.maximum, schema.type, schema.exclusiveMaximum);
validateMaximum(val, schema.maximum, type, schema.exclusiveMaximum);

@@ -547,3 +569,3 @@

// Validate minimum
validateMinimum(val, schema.minimum, schema.type, schema.exclusiveMinimum);
validateMinimum(val, schema.minimum, type, schema.exclusiveMinimum);

@@ -550,0 +572,0 @@ // Validate minItems

@@ -31,7 +31,6 @@ /*

var send400 = helpers.send400;
var spec = require('../../lib/helpers').getSpec('1.2');
var validators = require('../../lib/validators');
/**
* Middleware for using Swagger information to validate API requests prior to sending the request to the route handler.
* Middleware for using Swagger information to validate API requests/responses.
*

@@ -41,5 +40,12 @@ * This middleware also requires that you use the swagger-metadata middleware before this middleware. This middleware

*
* @param {object} [options] - The middleware options
* @param {boolean} [options.validateResponse=false] - Whether or not to validate responses
*
* @returns the middleware function
*/
exports = module.exports = function swaggerValidatorMiddleware () {
exports = module.exports = function swaggerValidatorMiddleware (options) {
if (_.isUndefined(options)) {
options = {};
}
return function swaggerValidator (req, res, next) {

@@ -53,2 +59,7 @@ var operation = req.swagger ? req.swagger.operation : undefined;

// If necessary, override 'res.send'
if (options.validateResponse === true) {
helpers.wrapEnd('1.2', req, res, next);
}
// Validate the request

@@ -60,3 +71,2 @@ try {

async.map(operation.parameters, function (parameter, oCallback) {
var isModel = helpers.isModelParameter('1.2', parameter);
var val;

@@ -76,32 +86,4 @@

validators.validateSchemaConstraints('1.2', parameter, paramPath, val);
helpers.validateValue(req, parameter, paramPath, val, oCallback);
if (isModel) {
async.map(parameter.type === 'array' ? val : [val], function (aVal, callback) {
spec.validateModel(req.swagger.apiDeclaration,
'#/models/' + (parameter.items ?
parameter.items.type || parameter.items.$ref :
parameter.type),
aVal, callback);
}, function (err, allResults) {
if (!err) {
_.each(allResults, function (results) {
if (results) {
err = new Error('Failed schema validation');
err.code = 'SCHEMA_VALIDATION_FAILED';
err.errors = results.errors;
err.failedValidation = true;
return false;
}
});
}
oCallback(err);
});
} else {
oCallback();
}
paramIndex++;

@@ -108,0 +90,0 @@ }, function (err) {

@@ -129,2 +129,3 @@ /*

return function swaggerMetadata (req, res, next) {
var method = req.method.toLowerCase();
var path = parseurl(req).pathname;

@@ -149,5 +150,6 @@ var match;

if (_.isPlainObject(pathMetadata.operations[req.method.toLowerCase()])) {
metadata.operation = pathMetadata.operations[req.method.toLowerCase()].operation;
metadata.operationParameters = pathMetadata.operations[req.method.toLowerCase()].parameters || [];
if (_.isPlainObject(pathMetadata.operations[method])) {
metadata.operation = pathMetadata.operations[method].operation;
metadata.operationParameters = pathMetadata.operations[method].parameters || [];
metadata.operationPath = ['paths', pathMetadata.apiPath, method];
metadata.security = metadata.operation.security || metadata.swaggerObject.security || [];

@@ -154,0 +156,0 @@ }

@@ -34,3 +34,3 @@ /*

/**
* Middleware for using Swagger information to validate API requests prior to sending the request to the route handler.
* Middleware for using Swagger information to validate API requests/responses.
*

@@ -40,5 +40,12 @@ * This middleware also requires that you use the swagger-metadata middleware before this middleware. This middleware

*
* @param {object} [options] - The middleware options
* @param {boolean} [options.validateResponse=false] - Whether or not to validate responses
*
* @returns the middleware function
*/
exports = module.exports = function swaggerValidatorMiddleware () {
exports = module.exports = function swaggerValidatorMiddleware (options) {
if (_.isUndefined(options)) {
options = {};
}
return function swaggerValidator (req, res, next) {

@@ -51,2 +58,7 @@ var operation = req.swagger ? req.swagger.operation : undefined;

// If necessary, override 'res.send'
if (options.validateResponse === true) {
helpers.wrapEnd('2.0', req, res, next);
}
// Validate the request

@@ -59,3 +71,2 @@ try {

var parameter = paramMetadata.schema;
var isModel = helpers.isModelParameter('2.0', parameter);
var val;

@@ -75,19 +86,3 @@

validators.validateSchemaConstraints('2.0', parameter, paramPath, val);
if (isModel) {
async.map(parameter.type === 'array' ? val : [val], function (aVal, callback) {
try {
validators.validateAgainstSchema(parameter.schema, val);
} catch (err) {
return callback(err);
}
return callback();
}, function (err) {
oCallback(err);
});
} else {
oCallback();
}
helpers.validateValue(req, parameter, paramPath, val, oCallback);
}, function (err) {

@@ -94,0 +89,0 @@ if (err) {

@@ -28,7 +28,9 @@ /*

var _ = require('lodash');
var async = require('async');
var fs = require('fs');
var helpers = require('../lib/helpers');
var parseurl = require('parseurl');
var path = require('path');
var validators = require('../lib/validators');
var helpers = require('../lib/helpers');
var operationVerbs = [

@@ -48,2 +50,33 @@ 'DELETE',

var isModelParameter = module.exports.isModelParameter = function isModelParameter (version, param) {
var spec = helpers.getSpec(version);
var isModel = false;
switch (version) {
case '1.2':
if (!_.isUndefined(param.type) && isModelType(spec, param.type)) {
isModel = true;
} else if (param.type === 'array' && isModelType(spec, param.items ?
param.items.type || param.items.$ref :
undefined)) {
isModel = true;
}
break;
case '2.0':
if (param.type === 'object' || !param.type) {
isModel = true;
} else if (!_.isUndefined(param.schema) && (param.schema.type === 'object' || !_.isUndefined(param.schema.$ref))) {
isModel = true;
}
// 2.0 does not allow arrays of models in the same way Swagger 1.2 does
break;
}
return isModel;
};
/**

@@ -315,33 +348,2 @@ * Returns an Express style path for the Swagger path.

var isModelParameter = module.exports.isModelParameter = function isModelParameter (version, param) {
var spec = helpers.getSpec(version);
var isModel = false;
switch (version) {
case '1.2':
if (!_.isUndefined(spec, param.type) && isModelType(spec, param.type)) {
isModel = true;
} else if (param.type === 'array' && isModelType(spec, param.items ?
param.items.type || param.items.$ref :
undefined)) {
isModel = true;
}
break;
case '2.0':
if (param.type === 'object' || !param.type) {
isModel = true;
} else if (!_.isUndefined(param.schema) && (param.schema.type === 'object' || !_.isUndefined(param.schema.$ref))) {
isModel = true;
}
// 2.0 does not allow arrays of models in the same way Swagger 1.2 does
break;
}
return isModel;
};
module.exports.getParameterValue = function getParameterValue (version, parameter, pathKeys, match, req) {

@@ -356,2 +358,3 @@ var defaultVal = version === '1.2' ? parameter.defaultValue : parameter.default;

case 'form':
case 'formData':
if (!req.body) {

@@ -473,1 +476,143 @@ throw new Error('Server configuration error: req.body is not defined but is required');

};
var validateValue = module.exports.validateValue =
function validateValue (req, schema, path, val, callback) {
var document = req.swagger.apiDeclaration || req.swagger.swaggerObject;
var version = req.swagger.apiDeclaration ? '1.2' : '2.0';
var isModel = isModelParameter(version, schema);
var spec = helpers.getSpec(version);
try {
validators.validateSchemaConstraints(version, schema, path, val);
} catch (err) {
return callback(err);
}
if (isModel) {
if (_.isString(val)) {
try {
val = JSON.parse(val);
} catch (err) {
err.failedValidation = true;
err.message = 'Value expected to be an array/object but is not';
throw err;
}
}
async.map(schema.type === 'array' ? val : [val], function (aVal, oCallback) {
if (version === '1.2') {
spec.validateModel(document, '#/models/' + (schema.items ?
schema.items.type || schema.items.$ref :
schema.type), aVal, oCallback);
} else {
try {
validators.validateAgainstSchema(schema.schema ? schema.schema : schema, val);
oCallback();
} catch (err) {
oCallback(err);
}
}
}, function (err, allResults) {
if (!err) {
_.each(allResults, function (results) {
if (results && helpers.getErrorCount(results) > 0) {
err = new Error('Failed schema validation');
err.code = 'SCHEMA_VALIDATION_FAILED';
err.errors = results.errors;
err.warnings = results.warnings;
err.failedValidation = true;
return false;
}
});
}
callback(err);
});
} else {
callback();
}
};
module.exports.wrapEnd = function wrapEnd (version, req, res, next) {
var operation = req.swagger.operation;
var originalEnd = res.end;
var vPath = _.cloneDeep(req.swagger.operationPath);
res.end = function end (data, encoding) {
var schema = operation;
var val = data;
// Replace 'res.end' with the original
res.end = originalEnd;
// If the data is a buffer, convert it to a string so we can parse it prior to validation
if (val instanceof Buffer) {
val = data.toString(encoding);
}
try {
// Validate the content type
try {
validators.validateContentType(req.swagger.apiDeclaration ?
req.swagger.apiDeclaration.produces :
req.swagger.swaggerObject.produces,
operation.produces, res);
} catch (err) {
err.failedValidation = true;
throw err;
}
if (_.isUndefined(schema.type)) {
if (schema.schema) {
schema = schema.schema;
} else if (version === '1.2') {
schema = _.find(operation.responseMessages, function (responseMessage, index) {
if (responseMessage.code === res.statusCode) {
vPath.push(['responseMessages', index.toString()]);
return true;
}
});
if (!_.isUndefined(schema)) {
schema = schema.responseModel;
}
} else {
schema = _.find(operation.responses, function (response, code) {
if (code === res.statusCode.toString()) {
vPath.push(['responses', code]);
return true;
}
});
}
}
validateValue(req, schema, vPath, val,
function (err) {
if (err) {
throw err;
}
// 'res.end' requires a Buffer or String so if it's not one, create a String
if (!(data instanceof Buffer) && !_.isString(data)) {
data = JSON.stringify(data);
}
res.end(data, encoding);
});
} catch (err) {
if (err.failedValidation) {
err.message = 'Response validation failed: ' + err.message.charAt(0).toLowerCase() + err.message.substring(1);
}
return next(err);
}
};
};
{
"name": "swagger-tools",
"version": "0.7.0",
"version": "0.7.1",
"description": "Various tools for using and integrating with Swagger.",

@@ -67,2 +67,3 @@ "main": "index.js",

"superagent": "^0.21.0",
"swagger-converter": "0.0.5",
"traverse": "^0.6.6",

@@ -69,0 +70,0 @@ "yamljs": "^0.2.1",

@@ -22,3 +22,5 @@ The project provides various tools for integrating and interacting with Swagger. This project is in its infancy but

* Simple CLI for validating Swagger documents
* Simple CLI
* Validate Swagger document(s)
* Convert Swagger 1.2 documents to Swagger 2.0
* Schema validation: For the file(s) supported by the Swagger specification, ensure they pass structural validation

@@ -32,5 +34,6 @@ based on the [JSON Schema][json-schema] associated with that version of the specification _(Browser and Node)_

* Connect middleware for using Swagger resource documents for pre-route validation _(Node only)_
* Validate the request Content-Type based on the operation's `consumes` value(s)
* Validate the request/response Content-Type based on the operation's `consumes/produces` value(s)
* Validate the request parameter types
* Validate the request parameter values
* Validate the response values

@@ -37,0 +40,0 @@ ## Installation

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc