Socket
Socket
Sign inDemoInstall

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.5.0 to 0.5.1

lib/validators.js

652

lib/specs.js

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

var jjve = require('jjve');
var validators = require('./validators');

@@ -70,2 +71,257 @@ var draft04Json = require('../schemas/json-schema-draft-04.json');

var createErrorOrWarning = function createErrorOrWarning (code, message, data, path, dest) {
dest.push({
code: code,
message: message,
data: data,
path: path
});
};
var createUnusedErrorOrWarning = function createUnusedErrorOrWarning (data, val, codeSuffix, msgPrefix, path, dest) {
createErrorOrWarning('UNUSED_' + codeSuffix, msgPrefix + ' is defined but is not used: ' + val, data, path, dest);
};
var validateExist = function validateExist (data, val, codeSuffix, msgPrefix, path, dest) {
if (!_.isUndefined(data) && data.indexOf(val) === -1) {
createErrorOrWarning('UNRESOLVABLE_' + codeSuffix, msgPrefix + ' could not be resolved: ' + val, val, path, dest);
}
};
var validateNoExist = function validateNoExist (data, val, codeSuffix, msgPrefix, path, dest) {
if (!_.isUndefined(data) && data.indexOf(val) > -1) {
createErrorOrWarning('DUPLICATE_' + codeSuffix, msgPrefix + ' already defined: ' + val, val, path, dest);
}
};
var validateNoDuplicates = function validateNoDuplicates (data, codeSuffix, msgPrefix, path, dest) {
var name = path[path.length - 1];
if (!_.isUndefined(data) && data.length !== _.uniq(data).length) {
createErrorOrWarning('DUPLICATE_' + codeSuffix, msgPrefix + ' ' + name + ' has duplicate items', data, path, dest);
}
};
// TODO: Move this to a helper
var identifyModelInheritanceIssues = function identifyModelInheritanceIssues (modelDeps, models, result) {
var circular = {};
var composed = {};
var resolved = {};
var unresolved = {};
var addModelProps = function addModelProps (parentModel, modelName) {
var model = models[modelName];
if (model) {
_.each(model.properties, function (prop, propName) {
if (composed[propName]) {
createErrorOrWarning('CHILD_MODEL_REDECLARES_PROPERTY',
'Child model declares property already declared by ancestor: ' + propName, prop,
['models', parentModel, 'properties', propName], result.errors);
} else {
composed[propName] = propName;
}
});
}
};
var getPath = function getPath (parent, unresolved) {
var parentVisited = false;
return Object.keys(unresolved).filter(function (dep) {
if (dep === parent) {
parentVisited = true;
}
return parentVisited && unresolved[dep];
});
};
var resolver = function resolver (id, deps, circular, resolved, unresolved) {
var model = models[id];
var modelDeps = deps[id];
unresolved[id] = true;
if (modelDeps) {
if (modelDeps.length > 1) {
createErrorOrWarning('MULTIPLE_MODEL_INHERITANCE',
'Child model is sub type of multiple models: ' + modelDeps.join(' && '), model,
['models', id], result.errors);
}
modelDeps.forEach(function (dep) {
if (!resolved[dep]) {
if (unresolved[dep]) {
circular[id] = getPath(dep, unresolved);
createErrorOrWarning('CYCLICAL_MODEL_INHERITANCE',
'Model has a circular inheritance: ' + id + ' -> ' + circular[id].join(' -> '),
model.subTypes,
['models', id, 'subTypes'], result.errors);
return;
}
addModelProps(id, dep);
resolver(dep, deps, circular, resolved, unresolved);
}
});
}
resolved[id] = true;
unresolved[id] = false;
};
Object.keys(modelDeps).forEach(function (modelName) {
composed = {};
addModelProps(modelName, modelName);
resolver(modelName, modelDeps, circular, resolved, unresolved);
});
};
// TODO: Move this to a helper
var validateParameterConstraints = function validateParameterConstraints (spec, parameter, val, path, dest) {
switch (spec.version) {
case '1.2':
// TODO: Make this work with parameters that have references
// Validate the value type/format
try {
validators.validateTypeAndFormat(parameter.name, val,
parameter.type === 'array' ? parameter.items.type : parameter.type,
parameter.type === 'array' && parameter.items.format ?
parameter.items.format :
parameter.format);
} catch (err) {
// TODO: Update to notify of 'INVALID_FORMAT'
createErrorOrWarning ('INVALID_TYPE', err.message, val, path, dest);
return;
}
// Validate enum
try {
validators.validateEnum(parameter.name, val, parameter.enum);
} catch (err) {
createErrorOrWarning ('ENUM_MISMATCH', err.message, val, path, dest);
return;
}
// Validate maximum
try {
validators.validateMaximum(parameter.name, val, parameter.maximum, parameter.type);
} catch (err) {
createErrorOrWarning ('MAXIMUM', err.message, val, path, dest);
return;
}
// Validate minimum
try {
validators.validateMinimum(parameter.name, val, parameter.minimum, parameter.type);
} catch (err) {
createErrorOrWarning ('MINIMUM', err.message, val, path, dest);
return;
}
// Validate uniqueItems
try {
validators.validateUniqueItems(parameter.name, val, parameter.uniqueItems);
} catch (err) {
createErrorOrWarning ('ARRAY_UNIQUE', err.message, val, path, dest);
return;
}
break;
case '2.0':
// TODO: Make this work with parameters that have schemas/references
// Validate the value type/format
try {
validators.validateTypeAndFormat(parameter.name, val,
parameter.type === 'array' ? parameter.items.type : parameter.type,
parameter.type === 'array' && parameter.items.format ?
parameter.items.format :
parameter.format);
} catch (err) {
// TODO: Update to notify of 'INVALID_FORMAT'
createErrorOrWarning('INVALID_TYPE', err.message, val, path, dest);
return;
}
// Validate enum
try {
validators.validateEnum(parameter.name, val, parameter.enum);
} catch (err) {
createErrorOrWarning('ENUM_MISMATCH', err.message, val, path, dest);
return;
}
// Validate maximum
try {
validators.validateMaximum(parameter.name, val, parameter.maximum, parameter.type, parameter.exclusiveMaximum);
} catch (err) {
createErrorOrWarning(parameter.exclusiveMaximum === true ? 'MAXIMUM_EXCLUSIVE' : 'MAXIMUM', err.message, val,
path, dest);
return;
}
// Validate maximum items
try {
validators.validateMaxItems(parameter.name, val, parameter.maxItems);
} catch (err) {
createErrorOrWarning('ARRAY_LENGTH_LONG', err.message, val, path, dest);
return;
}
// Validate maximum length
try {
validators.validateMaxLength(parameter.name, val, parameter.maxLength);
} catch (err) {
createErrorOrWarning('MAX_LENGTH', err.message, val, path, dest);
return;
}
// Validate minimum
try {
validators.validateMinimum(parameter.name, val, parameter.minimum, parameter.type, parameter.exclusiveMinimum);
} catch (err) {
createErrorOrWarning(parameter.exclusiveMinimum === 'true' ? 'MINIMUM_EXCLUSIVE' : 'MINIMUM', err.message, val,
path, dest);
return;
}
// Validate minimum items
try {
validators.validateMinItems(parameter.name, val, parameter.minItems);
} catch (err) {
createErrorOrWarning('ARRAY_LENGTH_SHORT', err.message, val, path, dest);
return;
}
// Validate minimum length
try {
validators.validateMinLength(parameter.name, val, parameter.minLength);
} catch (err) {
createErrorOrWarning('MIN_LENGTH', err.message, val, path, dest);
return;
}
// Validate pattern
try {
validators.validatePattern(parameter.name, val, parameter.pattern);
} catch (err) {
createErrorOrWarning('PATTERN', err.message, val, path, dest);
return;
}
// Validate uniqueItems
try {
validators.validateUniqueItems(parameter.name, val, parameter.uniqueItems);
} catch (err) {
createErrorOrWarning('ARRAY_UNIQUE', err.message, val, path, dest);
return;
}
break;
}
};
/**

@@ -166,2 +422,379 @@ * Creates a new Swagger specification object.

var validateContent = function validateContent (spec, rlOrSO, apiDeclarations) {
var response = {
errors: [],
warnings: []
};
var authDefs = {}; // (1.2)
var authRefs = {}; // (1.2)
var pathDefs = []; // (1.2)
var pathRefs = []; // (1.2)
switch (spec.version) {
case '1.2':
// Build path model
_.each(rlOrSO.apis, function (api, index) {
// Validate duplicate resource paths
validateNoExist(pathDefs, api.path, 'RESOURCE_PATH', 'Resource path', ['apis', index.toString(), 'path'],
response.errors);
if (pathDefs.indexOf(api.path) === -1) {
pathDefs.push(api.path);
}
});
if (response.errors.length === 0) {
// Build the authorization model
_.each(rlOrSO.authorizations, function (authorization, name) {
authDefs[name] = _.map(authorization.scopes, function (scope) {
return scope.scope;
});
}, {});
response.apiDeclarations = [];
// Validate the API declarations
_.each(apiDeclarations, function (apiDeclaration, index) {
var result = response.apiDeclarations[index] = {
errors: [],
warnings: []
};
var apiAuthDefs = {};
var apiAuthRefs = {};
var modelDeps = {};
var modelRefs = {};
var addModelRef = function addModelRef (modelId, modelRef) {
if (_.isUndefined(modelRefs[modelId])) {
modelRefs[modelId] = [];
}
modelRefs[modelId].push(modelRef);
};
var addScopeRef = function addScopeRef (authId, scopeId) {
var auth;
if (!_.isUndefined(apiAuthDefs[authId])) {
// Local auth definition
auth = apiAuthRefs[authId];
if (_.isUndefined(auth)) {
auth = apiAuthRefs[authId] = [];
}
} else {
// Global (Or missing in which case we'll assume global)
auth = authRefs[authId];
if (_.isUndefined(auth)) {
auth = authRefs[authId] = [];
}
}
if (auth.indexOf(scopeId) === -1) {
auth.push(scopeId);
}
};
var modelsById = {};
// Build the authorization model
_.each(apiDeclaration.authorizations, function (authorization, name) {
apiAuthDefs[name] = _.map(authorization.scopes, function (scope) {
return scope.scope;
});
}, {});
// Validate duplicate resource path
validateNoExist(pathRefs, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', ['resourcePath'],
result.errors);
// Validate missing resource path definition
validateExist(pathDefs, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', ['resourcePath'],
result.errors);
// Keep track of the seen paths
if (pathRefs.indexOf(apiDeclaration.resourcePath) === -1) {
pathRefs.push(apiDeclaration.resourcePath);
}
// Validate consumes/produces uniqueness
_.each(['consumes', 'produces'], function (name) {
validateNoDuplicates(apiDeclaration[name], 'API_' + name.toUpperCase(), 'API', [name],
result.warnings);
});
// Valdate APIs
_.reduce(apiDeclaration.apis, function (seenApiPaths, api, index) {
var aPath = ['apis', index.toString()];
// Validate operations
_.reduce(api.operations, function (seenMethods, operation, index) {
var oPath = aPath.concat(['operations', index.toString()]);
// Validate consumes/produces uniqueness
_.each(['consumes', 'produces'], function (name) {
validateNoDuplicates(operation[name], 'OPERATION_' + name.toUpperCase(), 'Operation',
oPath.concat(name), result.warnings);
});
// Validate unique method
validateNoExist(seenMethods, operation.method, 'OPERATION_METHOD', 'Operation method',
oPath.concat('method'), result.errors);
// Validate authorizations
_.each(operation.authorizations, function (scopes, name) {
// Validate missing authorization
validateExist(_.uniq(Object.keys(apiAuthDefs).concat(Object.keys(authDefs))), name, 'AUTHORIZATION',
'Authorization', oPath.concat(['authorizations', name]), result.errors);
// Validate missing authorization scopes (Only when the authorization is not missing)
_.each(scopes, function (scope, index) {
if (!_.isUndefined(apiAuthDefs[name]) || !_.isUndefined(authDefs[name])) {
// Validate missing authorization scope
validateExist(_.uniq((apiAuthDefs[name] || []).concat(authDefs[name] || [])), scope.scope,
'AUTHORIZATION_SCOPE', 'Authorization scope',
oPath.concat(['authorizations', name, index.toString(), 'scope']), result.errors);
}
addScopeRef(name, scope.scope);
});
});
// Validate parameters
_.each(operation.parameters, function (parameter, index) {
// Add model references from parameter type/items
if (spec.primitives.indexOf(parameter.type) === -1) {
addModelRef(parameter.type, oPath.concat(['parameters', index.toString(), 'type']));
} else if (parameter.type === 'array' && parameter.items.$ref) {
addModelRef(parameter.items.$ref, oPath.concat(['parameters', index.toString(), 'items', '$ref']));
}
if (_.isUndefined(parameter.defaultValue)) {
return;
}
// Validate default value against constraints
validateParameterConstraints(spec, parameter, parameter.defaultValue,
oPath.concat('parameters', index.toString(), 'defaultValue'),
result.errors);
});
// Validate duplicate resource path
validateNoExist(seenApiPaths, api.path, 'API_PATH', 'API path', aPath.concat('path'), result.errors);
// Validate unique response code
_.reduce(operation.responseMessages, function (seenResponseCodes, responseMessage, index) {
validateNoExist(seenResponseCodes, responseMessage.code, 'RESPONSE_MESSAGE_CODE', 'Response message code',
oPath.concat(['responseMessages', index.toString(), 'code']), result.errors);
// Add model references from responseMessages responseModel
if (responseMessage.responseModel) {
addModelRef(responseMessage.responseModel,
oPath.concat(['responseMessages', index.toString(), 'responseModel']));
}
return seenResponseCodes.concat(responseMessage.code);
}, []);
// Add model references from type/items
if (operation.type === 'array' && operation.items.$ref) {
addModelRef(operation.items.$ref, oPath.concat(['items', '$ref']));
} else if (spec.primitives.indexOf(operation.type) === -1) {
addModelRef(operation.type, oPath.concat(['type']));
}
return seenMethods.concat(operation.method);
}, []);
return seenApiPaths.concat(api.path);
}, []);
// Validate models
_.each(apiDeclaration.models, function (model, name) {
var mPath = ['models', name];
var modelId = model.id;
// Validate the model is not already defined (by id)
validateNoExist(Object.keys(modelsById), modelId, 'MODEL_DEFINITION', 'Model',
mPath.concat('id'), result.errors);
// Add model references from properties and validate the default values
_.each(model.properties, function (property, name) {
var pPath = mPath.concat('properties', name);
// Keep track of the model references
if (property.$ref) {
addModelRef(property.$ref, pPath.concat(['$ref']));
} else if (property.type === 'array' && property.items.$ref) {
addModelRef(property.items.$ref, pPath.concat(['items', '$ref']));
}
// Validate the default value against constraints
if (!_.isUndefined(property.defaultValue)) {
validateParameterConstraints(spec, property, property.defaultValue, pPath.concat('defaultValue'),
result.errors);
}
});
// Validate required properties
if (!_.isUndefined(model.required)) {
var props = model.properties || {};
_.each(model.required, function (propName, index) {
if (_.isUndefined(props[propName])) {
createErrorOrWarning('MISSING_REQUIRED_MODEL_PROPERTY',
'Model requires property but it is not defined: ' + propName, propName,
mPath.concat(['required', index.toString()]), result.errors);
}
});
}
// Keep track of model references in subTypes
_.each(_.uniq(model.subTypes), function (subType, index) {
var deps = modelDeps[subType];
addModelRef(subType, mPath.concat(['subTypes', index.toString()]));
if (deps) {
modelDeps[subType].push(name);
} else {
modelDeps[subType] = [name];
}
});
// Keep track of the seen model ids
modelsById[modelId] = model;
}, []);
// Validate unused authorizations
_.each(_.difference(Object.keys(apiAuthDefs), Object.keys(apiAuthRefs)), function (unused) {
createUnusedErrorOrWarning(apiDeclaration.authorizations[unused], unused, 'AUTHORIZATION', 'Authorization',
['authorizations', unused], result.warnings);
});
// Validate unused authorization scopes
_.each(apiAuthDefs, function (scopes, name) {
var path = ['authorizations', name];
var authDef = apiDeclaration.authorizations[name];
_.each(_.difference(scopes, apiAuthRefs[name] || []), function (scope, index) {
var sIndex = scopes.indexOf(scope);
createUnusedErrorOrWarning(authDef.scopes[sIndex], scope, 'AUTHORIZATION_SCOPE',
'Authorization scope', path.concat(['scopes', sIndex.toString()]),
result.warnings);
});
});
// Identify missing models (referenced but not declared)
_.each(_.difference(Object.keys(modelRefs), Object.keys(modelsById)), function (missing) {
modelRefs[missing].forEach(function (modelRef) {
createErrorOrWarning('UNRESOLVABLE_MODEL', 'Model could not be resolved: ' + missing,
missing, modelRef, result.errors);
});
});
// Identify unused models (declared but not referenced)
_.each(_.difference(Object.keys(modelsById), Object.keys(modelRefs)), function (unused) {
var modelName = Object.keys(apiDeclaration.models)[Object.keys(modelsById).indexOf(unused)];
createUnusedErrorOrWarning(modelsById[unused], unused, 'MODEL', 'Model', ['models', modelName],
result.warnings);
});
// Validate model inheritance issues
identifyModelInheritanceIssues(modelDeps, apiDeclaration.models, result);
});
// Validate unused resources
_.each(_.difference(pathDefs, pathRefs), function (unused) {
var index = _.map(rlOrSO.apis, function (api) { return api.path; }).indexOf(unused);
createUnusedErrorOrWarning(rlOrSO.apis[index].path, unused, 'RESOURCE_PATH', 'Resource path',
['apis', index.toString(), 'path'], response.errors);
});
// Validate unused authorizations
_.each(_.difference(Object.keys(authDefs), Object.keys(authRefs)), function (unused) {
createUnusedErrorOrWarning(rlOrSO.authorizations[unused], unused, 'AUTHORIZATION', 'Authorization',
['authorizations', unused], response.warnings);
});
// Validate unused authorization scopes
_.each(authRefs, function (scopes, name) {
var path = ['authorizations', name];
_.each(_.difference(scopes, authRefs[name]), function (unused) {
var index = scopes.indexOf(unused);
createUnusedErrorOrWarning(rlOrSO.authorizations[name].scopes[index], unused, 'AUTHORIZATION_SCOPE',
'Authorization scope', path.concat(['scopes', index.toString()]),
response.warnings);
});
});
}
break;
case '2.0':
// Validate (for now) unique consumes/produces/schemes
_.each(['consumes', 'produces', 'schemes'], function (name) {
validateNoDuplicates(rlOrSO[name], 'API_' + name.toUpperCase(), 'API', [name], response.warnings);
});
if (response.errors.length === 0 && response.warnings.length === 0) {
// Validate the Paths
_.each(rlOrSO.paths, function (path, name) {
var aPath = ['paths', name];
// Validate parameter constraints
_.each(path.parameters, function (parameter, index) {
if (!_.isUndefined(parameter.schema)) {
parameter = parameter.schema;
validateParameterConstraints(spec, parameter, parameter.default,
aPath.concat('parameters', index.toString(), 'schema', 'default'),
response.errors);
}
});
// Validate the Operations
_.each(path, function (operation, method) {
var oPath = aPath.concat(method);
if (method === 'parameters') {
return;
}
// Validate (for now) consumes/produces/schemes uniqueness
_.each(['consumes', 'produces', 'schemes'], function (name) {
validateNoDuplicates(operation[name], 'OPERATION_' + name.toUpperCase(), 'Operation',
oPath.concat(name), response.warnings);
});
// Validate parameter constraints
_.each(path.parameters, function (parameter, index) {
if (!_.isUndefined(parameter.schema)) {
parameter = parameter.schema;
if (_.isUndefined(parameter.default)) {
return;
}
validateParameterConstraints(spec, parameter, parameter.default,
oPath.concat('parameters', index.toString(), 'schema', 'default'),
response.errors);
}
});
});
// TODO: Validate the definitions
// TODO: Validate definition references
});
}
break;
}
return response;
};
/**

@@ -171,3 +804,3 @@ * Returns the result of the validation of the Swagger document(s).

* @param {object} rlOrSO - The Swagger Resource Listing (1.2) or Swagger Object (2.0)
* @param {object[]} apiDeclarations - The array of Swagger API Declarations (1.2)
* @param {object[]} [apiDeclarations] - The array of Swagger API Declarations (1.2)
*

@@ -210,6 +843,16 @@ * @returns undefined if validation passes or an object containing errors and/or warnings

response.apiDeclarations[index] = validateWithSchema(this, 'apiDeclaration.json', apiDeclaration);
if (response.apiDeclarations[index].errors.length > 0) {
skipRemaining = true;
// Skip the remaining validation
return false;
}
}.bind(this));
}
// TODO: Validate semantically
// Validate semantically
if (!skipRemaining) {
response = validateContent(this, rlOrSO, apiDeclarations);
}

@@ -241,3 +884,6 @@ // Set the response

// TODO: Validate semantically
// Validate semantically
if (!skipRemaining) {
response = validateContent(this, rlOrSO);
}

@@ -244,0 +890,0 @@ // Set the response

@@ -49,2 +49,8 @@ /*

* @param {object} [options] - The middleware options
* @param {(string|object|string[]) [options.controllers=./controllers] - If this is a string or string array, this is
* the path, or paths, to find the controllers
* in. If it's an object, the keys are the
* controller "name" (as described above) and the
* value is a function.
* @param {boolean} [options.useStubs=false] - Whether or not to stub missing controllers and methods
*

@@ -74,5 +80,10 @@ * @returns the middleware function

return function swaggerRouter (req, res, next) {
var operation = req.swagger ? req.swagger.operation : undefined;
var handler;
var operation;
if (req.swagger) {
operation = req.swagger.operation;
req.swagger.useStubs = options.useStubs;
}
if (!_.isUndefined(operation)) {

@@ -79,0 +90,0 @@ handler = handlerCache[operation.nickname];

2

middleware/1.2/swagger-validator.js

@@ -28,3 +28,3 @@ /*

var _ = require('lodash');
var validators = require('../validators');
var validators = require('../../lib/validators');

@@ -31,0 +31,0 @@ /**

@@ -51,2 +51,8 @@ /*

* @param {object} [options] - The middleware options
* @param {(string|object|string[]) [options.controllers=./controllers] - If this is a string or string array, this is
* the path, or paths, to find the controllers
* in. If it's an object, the keys are the
* controller "name" (as described above) and the
* value is a function.
* @param {boolean} [options.useStubs=false] - Whether or not to stub missing controllers and methods
*

@@ -76,6 +82,11 @@ * @returns the middleware function

return function swaggerRouter (req, res, next) {
var operation = req.swagger ? req.swagger.operation : undefined;
var handler;
var handlerName;
var operation;
if (req.swagger) {
operation = req.swagger.operation;
req.swagger.useStubs = options.useStubs;
}
if (!_.isUndefined(operation)) {

@@ -82,0 +93,0 @@ handlerName = (operation['x-swagger-router-controller'] ?

@@ -28,3 +28,3 @@ /*

var _ = require('lodash');
var validators = require('../validators');
var validators = require('../../lib/validators');

@@ -31,0 +31,0 @@ /**

@@ -32,23 +32,34 @@ /*

module.exports.handlerCacheFromDir = function handlerCacheFromDir (dir) {
module.exports.handlerCacheFromDir = function handlerCacheFromDir (dirOrDirs) {
var handlerCache = {};
var jsFileRegex = /\.js$/;
var dirs = [];
_.each(fs.readdirSync(dir), function (file) {
var controllerName = file.replace(jsFileRegex, '');
var controller;
if (_.isArray(dirOrDirs)) {
dirs = dirOrDirs;
} else {
dirs.push(dirOrDirs);
}
if (file.match(jsFileRegex)) {
controller = require(path.resolve(path.join(dir, controllerName)));
_.each(dirs, function (dir) {
_.each(fs.readdirSync(dir), function (file) {
var controllerName = file.replace(jsFileRegex, '');
var controller;
if (!_.isPlainObject(controller)) {
throw new Error('Controller module expected to export an object: ' + path.join(dir, file));
}
if (file.match(jsFileRegex)) {
controller = require(path.resolve(path.join(dir, controllerName)));
_.each(controller, function (value, name) {
if (_.isFunction(value)) {
handlerCache[controllerName + '_' + name] = value;
if (_.isPlainObject(controller)) {
_.each(controller, function (value, name) {
var handlerId = controllerName + '_' + name;
// TODO: Log this situation
if (_.isFunction(value) && !handlerCache[handlerId]) {
handlerCache[handlerId] = value;
}
});
}
});
}
}
});
});

@@ -55,0 +66,0 @@

{
"name": "swagger-tools",
"version": "0.5.0",
"version": "0.5.1",
"description": "Various tools for using and integrating with Swagger.",

@@ -15,9 +15,9 @@ "main": "index.js",

"bugs": {
"url": "https://github.com/apigee/connect-swagger/issues"
"url": "https://github.com/apigee-127/swagger-tools/issues"
},
"homepage": "https://github.com/apigee/connect-swagger",
"homepage": "https://github.com/apigee-127/swagger-tools",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/apigee/connect-swagger.git"
"url": "git://github.com/apigee-127/swagger-tools.git"
},

@@ -24,0 +24,0 @@ "keywords": [

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

* Downloads: [![NPM Downloads Per Month](http://img.shields.io/npm/dm/swagger-tools.svg)](https://www.npmjs.org/package/swagger-tools)
* License: [![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/apigee-127/swagger-tools/blob/master/LICENSE)
* License: [![License](http://img.shields.io/npm/l/swagger-tools.svg)](https://github.com/apigee-127/swagger-tools/blob/master/LICENSE)
* Version: [![NPM Version](http://img.shields.io/npm/v/swagger-tools.svg)](https://www.npmjs.org/package/swagger-tools)

@@ -24,3 +24,3 @@

based on the [JSON Schema][json-schema] associated with that version of the specification
* ~~Semantic validation: Validates Swagger files above and beyond the structure of the file~~ _(Coming back shortly)_
* Semantic validation: Validates Swagger files above and beyond the structure of the file
* Connect middleware for adding pertinent Swagger information to your requests (swagger-metadata)

@@ -48,3 +48,3 @@ * Connect middleware for wiring request handlers to requests based on Swagger documentation (swagger-router)

* `validate`: This is a function used to validate your Swagger document(s) based on the schema(s) for that
specifications schemas ~~and semantically~~ _(Coming back soon)_
specifications schemas and semantically

@@ -51,0 +51,0 @@ Here is an example showing how to use both versions of the `validate` function *(For more details, the sources are

@@ -9,2 +9,16 @@ {

"definitions": {
"externalDocs": {
"type": "object",
"description": "information about external documentation",
"required": [ "url" ],
"properties": {
"description": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
}
}
},
"info": {

@@ -112,6 +126,4 @@ "type": "object",

},
"docsUrl": {
"type": "string",
"format": "uri",
"description": "Location of external documentation."
"externalDocs": {
"$ref": "#/definitions/externalDocs"
},

@@ -157,5 +169,49 @@ "operationId": {

}
},
"security": {
"$ref": "#/definitions/security"
}
}
},
"pathItem": {
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^x-": {
"$ref": "#/definitions/vendorExtension"
}
},
"properties": {
"$ref": {
"type": "string"
},
"get": {
"$ref": "#/definitions/operation"
},
"put": {
"$ref": "#/definitions/operation"
},
"post": {
"$ref": "#/definitions/operation"
},
"delete": {
"$ref": "#/definitions/operation"
},
"options": {
"$ref": "#/definitions/operation"
},
"head": {
"$ref": "#/definitions/operation"
},
"patch": {
"$ref": "#/definitions/operation"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/definitions/parameter"
}
}
}
},
"responses": {

@@ -237,4 +293,3 @@ "type": "object",

"description": "Determines the location of the parameter.",
"enum": [ "query", "header", "path", "formData" ],
"default": "query"
"enum": [ "query", "header", "path", "formData" ]
},

@@ -251,3 +306,3 @@ "description": {

"type": "string",
"enum": [ "string", "number", "boolean", "integer", "array" ]
"enum": [ "string", "number", "boolean", "integer", "array", "file" ]
},

@@ -280,4 +335,3 @@ "format": {

"description": "Determines the location of the parameter.",
"enum": [ "body" ],
"default": "body"
"enum": [ "body" ]
},

@@ -341,2 +395,3 @@ "description": {

"required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" },
"externalDocs": { "$ref": "#/definitions/externalDocs" },
"definitions": {

@@ -354,2 +409,5 @@ "type": "object",

"type": { "$ref": "http://json-schema.org/draft-04/schema#/properties/type" },
"example": {
},
"allOf": {

@@ -362,2 +420,6 @@ "type": "array",

},
"security": {
"type": "array",
"description": "defines security requirements"
},
"xml": {

@@ -372,2 +434,16 @@ "properties": {

"additionalProperties": false
},
"tag": {
"type": "object",
"properties": {
"externalDocs": { "$ref": "#/definitions/externalDocs" }
},
"patternProperties": {
"^x-": {
"$ref": "#/definitions/vendorExtension"
},
"^/.*[^\/]$": {
"type": "string"
}
}
}

@@ -390,2 +466,5 @@ },

},
"externalDocs": {
"$ref": "#/definitions/externalDocs"
},
"host": {

@@ -426,52 +505,12 @@ "type": "string",

"type": "object",
"description": "Relative paths to the individual endpoints. They should be relative to the 'basePath'.",
"description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.",
"patternProperties": {
"^x-": {
"$ref": "#/definitions/vendorExtension"
},
"^/.*[^\/]$": {
"$ref": "#/definitions/pathItem"
}
},
"additionalProperties": {
"type": "object",
"minProperties": 1,
"additionalProperties": false,
"patternProperties": {
"^x-": {
"$ref": "#/definitions/vendorExtension"
}
},
"properties": {
"$ref": {
"type": "string"
},
"get": {
"$ref": "#/definitions/operation"
},
"put": {
"$ref": "#/definitions/operation"
},
"post": {
"$ref": "#/definitions/operation"
},
"delete": {
"$ref": "#/definitions/operation"
},
"options": {
"$ref": "#/definitions/operation"
},
"head": {
"$ref": "#/definitions/operation"
},
"patch": {
"$ref": "#/definitions/operation"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/definitions/parameter"
}
}
}
}
"additionalProperties": false
},

@@ -486,5 +525,11 @@ "definitions": {

"security": {
"type": "array"
"$ref": "#/definitions/security"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/tag"
}
}
}
}
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