swagger-tools
Advanced tools
Comparing version 0.6.13 to 0.7.0
99
index.js
/* | ||
* The MIT License (MIT) | ||
* | ||
* | ||
* Copyright (c) 2014 Apigee Corporation | ||
* | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
@@ -12,6 +12,6 @@ * of this software and associated documentation files (the "Software"), to deal | ||
* 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 | ||
@@ -28,5 +28,94 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
var _ = require('lodash'); | ||
var helpers = require('./lib/helpers'); | ||
var initializeMiddleware = function initializeMiddleware (rlOrSO, resources, callback) { | ||
var args; | ||
var spec; | ||
var swaggerVersion; | ||
if (_.isUndefined(rlOrSO)) { | ||
throw new Error('rlOrSO is required'); | ||
} else if (!_.isPlainObject(rlOrSO)) { | ||
throw new TypeError('rlOrSO must be an object'); | ||
} | ||
args = [rlOrSO]; | ||
swaggerVersion = helpers.getSwaggerVersion(rlOrSO); | ||
if (!swaggerVersion) { | ||
throw new Error('Unable to identify the Swagger version based on rlOrSO'); | ||
} else if (swaggerVersion === '1.2') { | ||
if (_.isUndefined(resources)) { | ||
throw new Error('resources is required'); | ||
} else if (!_.isArray(resources)) { | ||
throw new TypeError('resources must be an array'); | ||
} | ||
args.push(resources); | ||
} else { | ||
callback = arguments[1]; | ||
} | ||
if (_.isUndefined(callback)) { | ||
throw new Error('callback is required'); | ||
} else if (!_.isFunction(callback)) { | ||
throw new TypeError('callback must be a function'); | ||
} | ||
args.push(function (err, results) { | ||
if (results && results.errors.length + _.reduce(results.apiDeclarations || [], function (count, apiDeclaration) { | ||
return count += (apiDeclaration ? apiDeclaration.errors.length : 0); | ||
}, 0) > 0) { | ||
err = new Error('Swagger document(s) failed validation so the server cannot start'); | ||
err.results = results; | ||
} | ||
if (err) { | ||
if (process.env.NODE_ENV === 'test') { | ||
throw err; | ||
} else { | ||
return helpers.printValidationResults(swaggerVersion, rlOrSO, resources, results, true, true); | ||
} | ||
} | ||
callback({ | ||
// Create a wrapper to avoid having to pass the non-optional arguments back to the swaggerMetadata middleware | ||
swaggerMetadata: function () { | ||
var swaggerMetadata = require('./middleware/' + swaggerVersion + '/swagger-metadata'); | ||
return swaggerMetadata.apply(undefined, args.slice(0, args.length - 1)); | ||
}, | ||
swaggerRouter: require('./middleware/' + swaggerVersion + '/swagger-router'), | ||
swaggerSecurity: require('./middleware/' + swaggerVersion + '/swagger-security'), | ||
// Create a wrapper to avoid having to pass the non-optional arguments back to the swaggerUi middleware | ||
swaggerUi: function (options) { | ||
var swaggerUi = require('./middleware/' + swaggerVersion + '/swagger-ui'); | ||
var suArgs = [rlOrSO]; | ||
if (swaggerVersion === '1.2') { | ||
suArgs.push(_.reduce(resources, function (map, resource) { | ||
map[resource.resourcePath] = resource; | ||
return map; | ||
}, {})); | ||
} | ||
suArgs.push(options || {}); | ||
return swaggerUi.apply(undefined, suArgs); | ||
}, | ||
swaggerValidator: require('./middleware/' + swaggerVersion + '/swagger-validator') | ||
}); | ||
}); | ||
spec = helpers.getSpec(helpers.getSwaggerVersion(rlOrSO)); | ||
spec.validate.apply(spec, args); | ||
}; | ||
module.exports = { | ||
middleware: require('./middleware'), | ||
initializeMiddleware: initializeMiddleware, | ||
specs: require('./lib/specs') | ||
}; |
@@ -28,4 +28,60 @@ /* | ||
var _ = require('lodash'); | ||
var JsonRefs = require('json-refs'); | ||
var ZSchema = require('z-schema'); | ||
var draft04Json = require('../schemas/json-schema-draft-04.json'); | ||
var draft04Url = 'http://json-schema.org/draft-04/schema'; | ||
var specCache = {}; | ||
module.exports.createJsonValidator = function createJsonValidator (schemas) { | ||
var validator = new ZSchema({ | ||
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(['byte', 'double', 'float', 'int32', 'int64', 'mime-type', 'uri-template'], 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 formatResults (results) { | ||
if (results) { | ||
// Update the results based on its content to indicate success/failure accordingly | ||
return 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; | ||
}; | ||
/** | ||
@@ -59,20 +115,10 @@ * Returns the proper specification based on the human readable version. | ||
/** | ||
* Takes a reference and creates a fully qualified JSON pointer from it. (2.0 only) | ||
* Atempts to figure out the Swagger version from the Swagger document. | ||
* | ||
* If the passed in reference is fully qualified, it is returned as-is. Otherwise, the reference will have | ||
* '#/definitions/' prepended to it to make it fully qualified since these 'relative' references are only allowed for | ||
* model definitions. | ||
* @param {object} document - The Swagger document | ||
* | ||
* @param {string} ref - The relative or fully qualified reference | ||
* | ||
* @returns the corresponding JSON pointer for the reference | ||
* @returns the Swagger version or undefined if the document is not a Swagger document | ||
*/ | ||
module.exports.refToJsonPointer = function refToJsonPointer (ref) { | ||
// TODO: Fix this to handle remote references | ||
if (ref.charAt(0) !== '#') { | ||
ref = '#/definitions/' + ref; | ||
} | ||
return ref; | ||
module.exports.getSwaggerVersion = function getSwaggerVersion (document) { | ||
return _.isPlainObject(document) ? document.swaggerVersion || document.swagger : undefined; | ||
}; | ||
@@ -87,3 +133,3 @@ | ||
*/ | ||
module.exports.toJsonPointer = function toJsonPointer (path) { | ||
var toJsonPointer = module.exports.toJsonPointer = function toJsonPointer (path) { | ||
// http://tools.ietf.org/html/rfc6901#section-4 | ||
@@ -94,1 +140,73 @@ return '#/' + path.map(function (part) { | ||
}; | ||
module.exports.printValidationResults = function printValidationResults (version, apiDOrSO, apiDeclarations, results, | ||
printSummary, endProcess) { | ||
var pluralize = function pluralize (string, count) { | ||
return count === 1 ? string : string + 's'; | ||
}; | ||
var printErrorsOrWarnings = function printErrorsOrWarnings (header, entries, indent) { | ||
console.error(header); | ||
console.error(); | ||
_.each(entries, function (entry) { | ||
console.error(new Array(indent + 1).join(' ') + toJsonPointer(entry.path) + ': ' + entry.message); | ||
if (entry.inner) { | ||
printErrorsOrWarnings (header, entry.inner, indent + 2); | ||
} | ||
}); | ||
console.error(); | ||
}; | ||
var errorCount = 0; | ||
var warningCount = 0; | ||
console.error(); | ||
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) { | ||
console.error(errorCount + ' ' + pluralize('error', errorCount) + ' and ' + warningCount + ' ' + | ||
pluralize('warning', warningCount)); | ||
} else { | ||
console.error('Validation succeeded but with ' + warningCount + ' ' + pluralize('warning', warningCount)); | ||
} | ||
} | ||
if (errorCount > 0 && endProcess) { | ||
process.exit(1); | ||
} | ||
}; |
2005
lib/specs.js
@@ -28,55 +28,53 @@ /* | ||
var _ = require('lodash'); | ||
var jjv = require('jjv'); | ||
var jjve = require('jjve'); | ||
var md5 = require('spark-md5'); | ||
var async = require('async'); | ||
var helpers = require('./helpers'); | ||
var JsonRefs = require('json-refs'); | ||
var SparkMD5 = require('spark-md5'); | ||
var traverse = require('traverse'); | ||
var helpers = require('./helpers'); | ||
var validators = require('./validators'); | ||
var draft04Json = require('../schemas/json-schema-draft-04.json'); | ||
var draft04Url = 'http://json-schema.org/draft-04/schema'; | ||
var jjvOptions = { | ||
checkRequired: true, | ||
removeAdditional: false, | ||
useDefault: false, | ||
useCoerce: false | ||
}; | ||
var jjveOptions = { | ||
formatPath: false | ||
}; | ||
var metadataCache = {}; | ||
var refToJsonPointer = helpers.refToJsonPointer; | ||
var toJsonPointer = helpers.toJsonPointer; | ||
var documentCache = {}; | ||
var createValidator = function createValidator (spec, schemaNames) { | ||
var validator = jjv(jjvOptions); | ||
var addExternalRefsToValidator = function addExternalRefsToValidator (validator, json, callback) { | ||
var remoteRefs = _.reduce(JsonRefs.findRefs(json), function (rRefs, ref, ptr) { | ||
if (JsonRefs.isRemotePointer(ptr)) { | ||
rRefs.push(ref.split('#')[0]); | ||
} | ||
// Disable the 'uri' format checker as it's got issues: https://github.com/acornejo/jjv/issues/24 | ||
validator.addFormat('uri', function() { | ||
return true; | ||
}); | ||
return rRefs; | ||
}, []); | ||
var resolveRemoteRefs = function (ref, callback) { | ||
JsonRefs.resolveRefs({$ref: ref}, function (err, json) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
validator.addSchema(draft04Url, draft04Json); | ||
// Perform the same for the newly resolved document | ||
addExternalRefsToValidator(validator, json, function (err, rJson) { | ||
callback (err, rJson); | ||
}); | ||
}); | ||
}; | ||
if (!_.isUndefined(schemaNames)) { | ||
// Compile the necessary schemas | ||
_.each(schemaNames, function (schemaName) { | ||
var clone = _.cloneDeep(spec.schemas[schemaName]); | ||
if (remoteRefs.length > 0) { | ||
async.map(remoteRefs, resolveRemoteRefs, function (err, results) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
clone.id = schemaName; | ||
_.each(results, function (json, index) { | ||
validator.setRemoteReference(remoteRefs[index], json); | ||
}); | ||
validator.addSchema(schemaName, clone); | ||
}.bind(this)); | ||
callback(); | ||
}); | ||
} else { | ||
callback(); | ||
} | ||
validator.je = jjve(validator); | ||
return validator; | ||
}; | ||
var createErrorOrWarning = function createErrorOrWarning (code, message, data, path, dest) { | ||
var createErrorOrWarning = function createErrorOrWarning (code, message, path, dest) { | ||
dest.push({ | ||
code: code, | ||
message: message, | ||
data: data, | ||
path: path | ||
@@ -86,204 +84,169 @@ }); | ||
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 addReference = function addReference (cacheEntry, defPathOrPtr, refPathOrPtr, results, omitError) { | ||
var result = true; | ||
var swaggerVersion = helpers.getSwaggerVersion(cacheEntry.resolved); | ||
var defPath = _.isArray(defPathOrPtr) ? defPathOrPtr : JsonRefs.pathFromPointer(defPathOrPtr); | ||
var defPtr = _.isArray(defPathOrPtr) ? JsonRefs.pathToPointer(defPathOrPtr) : defPathOrPtr; | ||
var refPath = _.isArray(refPathOrPtr) ? refPathOrPtr : JsonRefs.pathFromPointer(refPathOrPtr); | ||
var refPtr = _.isArray(refPathOrPtr) ? JsonRefs.pathToPointer(refPathOrPtr) : refPathOrPtr; | ||
var code; | ||
var def; | ||
var displayId; | ||
var msgPrefix; | ||
var type; | ||
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); | ||
// Only possible when defPathOrPtr is a string and is not a real pointer | ||
if (defPath.length === 0) { | ||
createErrorOrWarning('INVALID_REFERENCE', 'Not a valid JSON Reference', refPath, results.errors); | ||
return false; | ||
} | ||
}; | ||
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); | ||
def = cacheEntry.definitions[defPtr]; | ||
type = defPath[0]; | ||
code = type === 'securityDefinitions' ? | ||
'SECURITY_DEFINITION' : | ||
type.substring(0, type.length - 1).toUpperCase(); | ||
displayId = swaggerVersion === '1.2' ? defPath[defPath.length - 1] : defPtr; | ||
msgPrefix = type === 'securityDefinitions' ? | ||
'Security definition' : | ||
code.charAt(0) + code.substring(1).toLowerCase(); | ||
// This is an authorization scope reference | ||
if (['authorizations', 'securityDefinitions'].indexOf(defPath[0]) > -1 && defPath[2] === 'scopes') { | ||
code += '_SCOPE'; | ||
msgPrefix += ' scope'; | ||
} | ||
}; | ||
var validateNoDuplicates = function validateNoDuplicates (data, codeSuffix, msgPrefix, path, dest) { | ||
var name = path[path.length - 1]; | ||
if (_.isUndefined(def)) { | ||
if (!omitError) { | ||
createErrorOrWarning('UNRESOLVABLE_' + code, msgPrefix + ' could not be resolved: ' + displayId, | ||
refPath, results.errors); | ||
} | ||
if (!_.isUndefined(data) && data.length !== _.uniq(data).length) { | ||
createErrorOrWarning('DUPLICATE_' + codeSuffix, msgPrefix + ' ' + name + ' has duplicate items', data, path, dest); | ||
result = false; | ||
} else { | ||
if (_.isUndefined(def.references)) { | ||
def.references = []; | ||
} | ||
def.references.push(refPtr); | ||
} | ||
}; | ||
var validateArrayType = function validateArrayType (data, path, dest) { | ||
// We have to do this manually for now (https://github.com/swagger-api/swagger-spec/issues/174) | ||
if (data.type === 'array' && _.isUndefined(data.items)) { | ||
createErrorOrWarning('OBJECT_MISSING_REQUIRED_PROPERTY', 'Missing required property: items', data, path, dest); | ||
} | ||
return result; | ||
}; | ||
// TODO: Move this to a helper | ||
var getOrComposeSchema = function getOrComposeSchema (documentMetadata, modelId) { | ||
var title = 'Composed ' + (documentMetadata.swaggerVersion === '1.2' ? | ||
JsonRefs.pathFromPointer(modelId).pop() : | ||
modelId); | ||
var metadata = documentMetadata.definitions[modelId]; | ||
var originalT = traverse(documentMetadata.original); | ||
var resolvedT = traverse(documentMetadata.resolved); | ||
var composed; | ||
var original; | ||
var validateParameterConstraints = function validateParameterConstraints (spec, parameter, val, path, dest) { | ||
switch (spec.version) { | ||
case '1.2': | ||
// TODO: Make this work with parameters that have references | ||
if (!metadata) { | ||
return undefined; | ||
} | ||
validateArrayType(parameter, path, dest); | ||
original = _.cloneDeep(originalT.get(JsonRefs.pathFromPointer(modelId))); | ||
composed = _.cloneDeep(resolvedT.get(JsonRefs.pathFromPointer(modelId))); | ||
// Validate the value type/format (Skip for array since we manually handle it above for now) | ||
if (parameter.type === 'array' && !_.isUndefined(parameter.items)) { | ||
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; | ||
} | ||
} | ||
// Convert the Swagger 1.2 document to a valid JSON Schema file | ||
if (documentMetadata.swaggerVersion === '1.2') { | ||
// Create inheritance model | ||
if (metadata.lineage.length > 0) { | ||
composed.allOf = []; | ||
// Validate enum | ||
try { | ||
validators.validateEnum(parameter.name, val, parameter.enum); | ||
} catch (err) { | ||
createErrorOrWarning ('ENUM_MISMATCH', err.message, val, path, dest); | ||
return; | ||
_.each(metadata.lineage, function (modelId) { | ||
composed.allOf.push(getOrComposeSchema(documentMetadata, modelId)); | ||
}); | ||
} | ||
// Validate maximum | ||
try { | ||
validators.validateMaximum(parameter.name, val, parameter.maximum, parameter.type); | ||
} catch (err) { | ||
createErrorOrWarning ('MAXIMUM', err.message, val, path, dest); | ||
return; | ||
} | ||
// Remove the subTypes property | ||
delete composed.subTypes; | ||
// Validate minimum | ||
try { | ||
validators.validateMinimum(parameter.name, val, parameter.minimum, parameter.type); | ||
} catch (err) { | ||
createErrorOrWarning ('MINIMUM', err.message, val, path, dest); | ||
return; | ||
} | ||
_.each(composed.properties, function (property, name) { | ||
var oProp = original.properties[name]; | ||
// Validate uniqueItems | ||
try { | ||
validators.validateUniqueItems(parameter.name, val, parameter.uniqueItems); | ||
} catch (err) { | ||
createErrorOrWarning ('ARRAY_UNIQUE', err.message, val, path, dest); | ||
return; | ||
} | ||
// Convert the string values to numerical values | ||
_.each(['maximum', 'minimum'], function (prop) { | ||
if (_.isString(property[prop])) { | ||
property[prop] = parseFloat(property[prop]); | ||
} | ||
}); | ||
break; | ||
_.each(JsonRefs.findRefs(oProp), function (ref, ptr) { | ||
var modelId = '#/models/' + ref; | ||
var dMetadata = documentMetadata.definitions[modelId]; | ||
var path = JsonRefs.pathFromPointer(ptr); | ||
case '2.0': | ||
// TODO: Make this work with parameters that have schemas/references | ||
if (dMetadata.lineage.length > 0) { | ||
traverse(property).set(path.slice(0, path.length - 1), getOrComposeSchema(documentMetadata, modelId)); | ||
} else { | ||
traverse(property).set(path.slice(0, path.length - 1).concat('title'), 'Composed ' + ref); | ||
traverse(property).set(path.slice(0, path.length - 1).concat('type'), 'object'); | ||
} | ||
}); | ||
}); | ||
} | ||
validateArrayType(parameter, path, dest); | ||
// Validate the value type/format (Skip for array since we manually handle it above for now) | ||
if (parameter.type === 'array' && !_.isUndefined(parameter.items)) { | ||
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; | ||
} | ||
// Scrub id properties | ||
composed = traverse(composed).map(function (val) { | ||
if (this.key === 'id' && _.isString(val)) { | ||
this.remove(); | ||
} | ||
}); | ||
// Validate enum | ||
try { | ||
validators.validateEnum(parameter.name, val, parameter.enum); | ||
} catch (err) { | ||
createErrorOrWarning('ENUM_MISMATCH', err.message, val, path, dest); | ||
return; | ||
} | ||
composed.title = title; | ||
composed.type = 'object'; | ||
// 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; | ||
} | ||
return composed; | ||
}; | ||
// Validate maximum items | ||
try { | ||
validators.validateMaxItems(parameter.name, val, parameter.maxItems); | ||
} catch (err) { | ||
createErrorOrWarning('ARRAY_LENGTH_LONG', err.message, val, path, dest); | ||
return; | ||
} | ||
var createUnusedErrorOrWarning = function createUnusedErrorOrWarning (val, codeSuffix, msgPrefix, path, dest) { | ||
createErrorOrWarning('UNUSED_' + codeSuffix, msgPrefix + ' is defined but is not used: ' + val, path, dest); | ||
}; | ||
// Validate maximum length | ||
try { | ||
validators.validateMaxLength(parameter.name, val, parameter.maxLength); | ||
} catch (err) { | ||
createErrorOrWarning('MAX_LENGTH', err.message, val, path, dest); | ||
return; | ||
} | ||
var getDocumentCache = function getDocumentCache (apiDOrSO) { | ||
var key = SparkMD5.hash(JSON.stringify(apiDOrSO)); | ||
var cacheEntry = documentCache[key] || _.find(documentCache, function (cacheEntry) { | ||
return cacheEntry.resolvedId === key; | ||
}); | ||
// 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; | ||
} | ||
if (!cacheEntry) { | ||
cacheEntry = documentCache[key] = { | ||
definitions: {}, | ||
original: apiDOrSO, | ||
resolved: undefined, | ||
swaggerVersion: helpers.getSwaggerVersion(apiDOrSO) | ||
}; | ||
} | ||
// Validate minimum items | ||
try { | ||
validators.validateMinItems(parameter.name, val, parameter.minItems); | ||
} catch (err) { | ||
createErrorOrWarning('ARRAY_LENGTH_SHORT', err.message, val, path, dest); | ||
return; | ||
} | ||
return cacheEntry; | ||
}; | ||
// Validate minimum length | ||
try { | ||
validators.validateMinLength(parameter.name, val, parameter.minLength); | ||
} catch (err) { | ||
createErrorOrWarning('MIN_LENGTH', err.message, val, path, dest); | ||
return; | ||
} | ||
var handleValidationError = function handleValidationError (results, callback) { | ||
var err = new Error('The Swagger document is invalid and model composition is not possible'); | ||
// Validate pattern | ||
try { | ||
validators.validatePattern(parameter.name, val, parameter.pattern); | ||
} catch (err) { | ||
createErrorOrWarning('PATTERN', err.message, val, path, dest); | ||
return; | ||
} | ||
err.errors = results.errors; | ||
err.warnings = results.warnings; | ||
// Validate uniqueItems | ||
try { | ||
validators.validateUniqueItems(parameter.name, val, parameter.uniqueItems); | ||
} catch (err) { | ||
createErrorOrWarning('ARRAY_UNIQUE', err.message, val, path, dest); | ||
return; | ||
} | ||
break; | ||
} | ||
callback(err); | ||
}; | ||
var normalizePath = function normalizePath (path) { | ||
var matches = path.match(/\{(.*?)\}/g); | ||
var argNames = []; | ||
var segments = []; | ||
var normPath = path; | ||
_.each(path.split('/'), function (segment) { | ||
if (segment.charAt(0) === '{') { | ||
argNames.push(segment.substring(1).split('}')[0]); | ||
if (matches) { | ||
_.each(matches, function (match, index) { | ||
normPath = normPath.replace(match, '{' + index + '}'); | ||
argNames.push(match.replace(/[{}]/g, '')); | ||
}); | ||
} | ||
segment = '{' + (argNames.length - 1) + '}'; | ||
} | ||
segments.push(segment); | ||
}); | ||
return { | ||
path: segments.join('/'), | ||
path: normPath, | ||
args: argNames | ||
@@ -293,221 +256,252 @@ }; | ||
/** | ||
* Creates a new Swagger specification object. | ||
* | ||
* @param {string} version - The Swagger version | ||
* | ||
* @constructor | ||
*/ | ||
var Specification = function Specification (version) { | ||
var primitives = ['string', 'number', 'boolean', 'integer', 'array']; | ||
var docsUrl; | ||
var schemasUrl; | ||
var validateNoExist = function validateNoExist (data, val, codeSuffix, msgPrefix, path, dest) { | ||
if (!_.isUndefined(data) && data.indexOf(val) > -1) { | ||
createErrorOrWarning('DUPLICATE_' + codeSuffix, msgPrefix + ' already defined: ' + val, path, dest); | ||
} | ||
}; | ||
switch (version) { | ||
case '1.2': | ||
docsUrl = 'https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md'; | ||
primitives = _.union(primitives, ['void', 'File']); | ||
schemasUrl = 'https://github.com/wordnik/swagger-spec/tree/master/schemas/v1.2'; | ||
var validateSchemaConstraints = function validateSchemaConstraints (documentMetadata, schema, path, results, skip) { | ||
try { | ||
validators.validateSchemaConstraints(documentMetadata.swaggerVersion, schema, path, undefined); | ||
} catch (err) { | ||
if (!skip) { | ||
createErrorOrWarning(err.code, err.message, err.path, results.errors); | ||
} | ||
} | ||
}; | ||
break; | ||
case '2.0': | ||
docsUrl = 'https://github.com/wordnik/swagger-spec/blob/master/versions/2.0.md'; | ||
primitives = _.union(primitives, ['file']); | ||
schemasUrl = 'https://github.com/wordnik/swagger-spec/tree/master/schemas/v2.0'; | ||
var processDocument = function processDocument (documentMetadata, results) { | ||
var swaggerVersion = documentMetadata.swaggerVersion; | ||
var getDefinitionMetadata = function getDefinitionMetadata (defPath) { | ||
var defPtr = JsonRefs.pathToPointer(defPath); | ||
var metadata = documentMetadata.definitions[defPtr]; | ||
break; | ||
default: | ||
throw new Error(version + ' is an unsupported Swagger specification version'); | ||
} | ||
if (!metadata) { | ||
metadata = documentMetadata.definitions[defPtr] = { | ||
references: [] | ||
}; | ||
this.docsUrl = docsUrl; | ||
this.primitives = primitives; | ||
this.schemasUrl = schemasUrl; | ||
this.version = version; | ||
// For model definitions, add the inheritance properties | ||
if (['definitions', 'models'].indexOf(JsonRefs.pathFromPointer(defPtr)[0]) > -1) { | ||
metadata.cyclical = false; | ||
metadata.lineage = undefined; | ||
metadata.parents = []; | ||
} | ||
} | ||
// Load the schema files | ||
this.schemas = {}; | ||
return metadata; | ||
}; | ||
var getDisplayId = function getDisplayId (id) { | ||
return swaggerVersion === '1.2' ? JsonRefs.pathFromPointer(id).pop() : id; | ||
}; | ||
var walk = function walk (root, id, lineage) { | ||
var definition = documentMetadata.definitions[id || root]; | ||
// Create the validators | ||
this.validators = {}; | ||
if (definition) { | ||
_.each(definition.parents, function (parent) { | ||
lineage.push(parent); | ||
switch (version) { | ||
case '1.2': | ||
// Here explicitly to allow browserify to work | ||
this.schemas['apiDeclaration.json'] = require('../schemas/1.2/apiDeclaration.json'); | ||
this.schemas['authorizationObject.json'] = require('../schemas/1.2/authorizationObject.json'); | ||
this.schemas['dataType.json'] = require('../schemas/1.2/dataType.json'); | ||
this.schemas['dataTypeBase.json'] = require('../schemas/1.2/dataTypeBase.json'); | ||
this.schemas['infoObject.json'] = require('../schemas/1.2/infoObject.json'); | ||
this.schemas['modelsObject.json'] = require('../schemas/1.2/modelsObject.json'); | ||
this.schemas['oauth2GrantType.json'] = require('../schemas/1.2/oauth2GrantType.json'); | ||
this.schemas['operationObject.json'] = require('../schemas/1.2/operationObject.json'); | ||
this.schemas['parameterObject.json'] = require('../schemas/1.2/parameterObject.json'); | ||
this.schemas['resourceListing.json'] = require('../schemas/1.2/resourceListing.json'); | ||
this.schemas['resourceObject.json'] = require('../schemas/1.2/resourceObject.json'); | ||
if (root !== parent) { | ||
walk(root, parent, lineage); | ||
} | ||
}); | ||
} | ||
}; | ||
var authDefsProp = swaggerVersion === '1.2' ? 'authorizations' : 'securityDefinitions'; | ||
var modelDefsProp = swaggerVersion === '1.2' ? 'models' : 'definitions'; | ||
this.validators['apiDeclaration.json'] = createValidator(this, [ | ||
'dataTypeBase.json', | ||
'modelsObject.json', | ||
'oauth2GrantType.json', | ||
'authorizationObject.json', | ||
'parameterObject.json', | ||
'operationObject.json', | ||
'apiDeclaration.json' | ||
]); | ||
// Process authorization definitions | ||
_.each(documentMetadata.resolved[authDefsProp], function (authorization, name) { | ||
var securityDefPath = [authDefsProp, name]; | ||
this.validators['resourceListing.json'] = createValidator(this, [ | ||
'resourceObject.json', | ||
'infoObject.json', | ||
'oauth2GrantType.json', | ||
'authorizationObject.json', | ||
'resourceListing.json' | ||
]); | ||
// Swagger 1.2 only has authorization definitions in the Resource Listing | ||
if (swaggerVersion === '1.2' && !authorization.type) { | ||
return; | ||
} | ||
break; | ||
// Create the authorization definition metadata | ||
getDefinitionMetadata(securityDefPath); | ||
case '2.0': | ||
// Here explicitly to allow browserify to work | ||
this.schemas['schema.json'] = require('../schemas/2.0/schema.json'); | ||
_.reduce(authorization.scopes, function (seenScopes, scope, indexOrName) { | ||
var scopeName = swaggerVersion === '1.2' ? scope.scope : indexOrName; | ||
var scopeDefPath = securityDefPath.concat(['scopes', indexOrName.toString()]); | ||
var scopeMetadata = getDefinitionMetadata(securityDefPath.concat(['scopes', scopeName])); | ||
this.validators['schema.json'] = createValidator(this, [ | ||
'schema.json' | ||
]); | ||
scopeMetadata.scopePath = scopeDefPath; | ||
break; | ||
} | ||
}; | ||
// Identify duplicate authorization scope defined in the Resource Listing | ||
validateNoExist(seenScopes, scopeName, 'AUTHORIZATION_SCOPE_DEFINITION', 'Authorization scope definition', | ||
swaggerVersion === '1.2' ? scopeDefPath.concat('scope') : scopeDefPath, results.warnings); | ||
var getModelMetadata = function getModelMetadata (modelsMetadata, modelId) { | ||
var metadata = modelsMetadata[modelId]; | ||
seenScopes.push(scopeName); | ||
if (_.isUndefined(metadata)) { | ||
metadata = modelsMetadata[modelId] = { | ||
composed: {}, | ||
name: undefined, | ||
parents: [], | ||
refs: [], | ||
schema: undefined | ||
}; | ||
} | ||
return seenScopes; | ||
}, []); | ||
}); | ||
return metadata; | ||
}; | ||
// Proces model definitions | ||
_.each(documentMetadata.resolved[modelDefsProp], function (model, modelId) { | ||
var modelDefPath = [modelDefsProp, modelId]; | ||
var modelMetadata = getDefinitionMetadata(modelDefPath); | ||
var processModel = function processModel (spec, modelsMetadata, model, modelId, path, results) { | ||
var metadata = getModelMetadata(modelsMetadata, modelId); | ||
var isRemoteRef = function (ref) { | ||
return ref.indexOf('http://') === 0 || ref.indexOf('https://') === 0; | ||
}; | ||
// Identify model id mismatch (Id in models object is not the same as the model's id in the models object) | ||
if (swaggerVersion === '1.2' && modelId !== model.id) { | ||
createErrorOrWarning('MODEL_ID_MISMATCH', 'Model id does not match id in models object: ' + model.id, | ||
modelDefPath.concat('id'), results.errors); | ||
} | ||
// Ensure the model's name and schema are set | ||
metadata.schema = model; | ||
metadata.name = modelId; // Reasonable default | ||
metadata.path = path; | ||
// Do not reprocess parents/references if already processed | ||
if (_.isUndefined(modelMetadata.lineage)) { | ||
// Handle inheritance references | ||
switch (swaggerVersion) { | ||
case '1.2': | ||
_.each(model.subTypes, function (subType, index) { | ||
var subPath = ['models', subType]; | ||
var subPtr = JsonRefs.pathToPointer(subPath); | ||
var subMetadata = documentMetadata.definitions[subPtr]; | ||
var refPath = modelDefPath.concat(['subTypes', index.toString()]); | ||
switch (spec.version) { | ||
case '1.2': | ||
// Set the model's name to the proper value | ||
metadata.name = path[path.length - 1]; | ||
// If the metadata does not yet exist, create it | ||
if (!subMetadata && documentMetadata.resolved[modelDefsProp][subType]) { | ||
subMetadata = getDefinitionMetadata(subPath); | ||
} | ||
// Add model references from properties and validate the default values | ||
_.each(model.properties, function (property, name) { | ||
var pPath = path.concat('properties', name); | ||
// If the reference is valid, add the parent | ||
if (addReference(documentMetadata, subPath, refPath, results)) { | ||
subMetadata.parents.push(JsonRefs.pathToPointer(modelDefPath)); | ||
} | ||
}); | ||
validateArrayType(property, pPath, results.error); | ||
break; | ||
// Keep track of the model references | ||
if (property.$ref) { | ||
getModelMetadata(modelsMetadata, property.$ref).refs.push(pPath.concat(['$ref'])); | ||
} else if (property.type === 'array' && !_.isUndefined(property.items) && !_.isUndefined(property.items.$ref)) { | ||
getModelMetadata(modelsMetadata, property.items.$ref).refs.push(pPath.concat(['items', '$ref'])); | ||
default: | ||
_.each(documentMetadata.original[modelDefsProp][modelId].allOf, function (schema, index) { | ||
var childPath = modelDefPath.concat(['allOf', index.toString()]); | ||
var parentMetadata; | ||
var parentPath; | ||
if (_.isUndefined(schema.$ref) || JsonRefs.isRemotePointer(schema.$ref)) { | ||
parentPath = modelDefPath.concat(['allOf', index.toString()]); | ||
} else { | ||
parentMetadata = getDefinitionMetadata(JsonRefs.pathFromPointer(schema.$ref)); | ||
parentPath = JsonRefs.pathFromPointer(schema.$ref); | ||
} | ||
modelMetadata.parents.push(JsonRefs.pathToPointer(parentPath)); | ||
if (parentMetadata) { | ||
addReference(documentMetadata, parentPath, childPath, results); | ||
} | ||
}); | ||
break; | ||
} | ||
} | ||
}); | ||
// Validate the default value against constraints | ||
if (!_.isUndefined(property.defaultValue)) { | ||
validateParameterConstraints(spec, property, property.defaultValue, pPath.concat('defaultValue'), | ||
results.errors); | ||
} | ||
switch (swaggerVersion) { | ||
case '2.0': | ||
// Process parameter definitions | ||
_.each(documentMetadata.resolved.parameters, function (parameter, name) { | ||
var path = ['parameters', name]; | ||
getDefinitionMetadata(path); | ||
validateSchemaConstraints(documentMetadata, parameter, path, results); | ||
}); | ||
// Keep track of model references in subTypes | ||
_.each(_.uniq(model.subTypes), function (subType, index) { | ||
var subMetadata = getModelMetadata(modelsMetadata, subType); | ||
// Process response definitions | ||
_.each(documentMetadata.resolved.responses, function (response, name) { | ||
var path = ['responses', name]; | ||
subMetadata.parents.push(modelId); | ||
subMetadata.refs.push(path.concat('subTypes', index.toString())); | ||
getDefinitionMetadata(path); | ||
validateSchemaConstraints(documentMetadata, response, path, results); | ||
}); | ||
break; | ||
} | ||
case '2.0': | ||
// Keep track of model references in allOf | ||
_.each(_.uniq(model.allOf), function (schema, index) { | ||
var sPath = path.concat('allOf', index.toString()); | ||
// Validate definition/models (Inheritance, property definitions, ...) | ||
_.each(documentMetadata.definitions, function (metadata, id) { | ||
var defPath = JsonRefs.pathFromPointer(id); | ||
var definition = traverse(documentMetadata.original).get(defPath); | ||
var defProp = defPath[0]; | ||
var code = defProp.substring(0, defProp.length - 1).toUpperCase(); | ||
var msgPrefix = code.charAt(0) + code.substring(1).toLowerCase(); | ||
var dProperties; | ||
var iProperties; | ||
var lineage; | ||
if (_.isUndefined(schema.$ref)) { | ||
processModel(spec, modelsMetadata, schema, toJsonPointer(sPath), sPath, results); | ||
// The only checks we perform below are inheritance checks so skip all non-model definitions | ||
if (['definitions', 'models'].indexOf(defProp) === -1) { | ||
return; | ||
} | ||
metadata.parents.push(toJsonPointer(sPath)); | ||
} else { | ||
if (!isRemoteRef(schema.$ref)) { | ||
metadata.parents.push(refToJsonPointer(schema.$ref)); | ||
dProperties = []; | ||
iProperties = []; | ||
lineage = metadata.lineage; | ||
getModelMetadata(modelsMetadata, refToJsonPointer(schema.$ref)).refs.push(sPath.concat('$ref')); | ||
} | ||
} | ||
}); | ||
// Do not reprocess lineage if already processed | ||
if (_.isUndefined(lineage)) { | ||
lineage = []; | ||
// Validate the default value against constraints | ||
if (!_.isUndefined(model.default)) { | ||
validateParameterConstraints(spec, model, model.defaultValue, path.concat('default'), results.errors); | ||
} | ||
walk(id, undefined, lineage); | ||
// Skipping 'definitions' for now: https://github.com/reverb/swagger-spec/issues/127 | ||
// Root > next > ... | ||
lineage.reverse(); | ||
// Keep track of model references in $ref, items.$ref | ||
if (model.$ref) { | ||
if (!isRemoteRef(model.$ref)) { | ||
getModelMetadata(modelsMetadata, refToJsonPointer(model.$ref)).refs.push(path.concat(['$ref'])); | ||
} | ||
} else if (model.type === 'array') { | ||
validateArrayType(model, path, results.errors); | ||
metadata.lineage = _.cloneDeep(lineage); | ||
if (!_.isUndefined(model.items) && !_.isUndefined(model.items.$ref)) { | ||
if (!isRemoteRef(model.items.$ref)) { | ||
getModelMetadata(modelsMetadata, | ||
refToJsonPointer(model.items.$ref)).refs.push(path.concat(['items', '$ref'])); | ||
} | ||
} else if (!_.isUndefined(model.items) && !_.isUndefined(model.items.type) && | ||
spec.primitives.indexOf(model.items.type) === -1) { | ||
_.each(model.items, function (item, index) { | ||
var sPath = path.concat('items', index.toString()); | ||
metadata.cyclical = lineage.length > 1 && lineage[0] === id; | ||
} | ||
processModel(spec, modelsMetadata, item, toJsonPointer(sPath), sPath, results); | ||
}); | ||
} | ||
// Swagger 1.2 does not allow multiple inheritance while Swagger 2.0+ does | ||
if (metadata.parents.length > 1 && swaggerVersion === '1.2') { | ||
createErrorOrWarning('MULTIPLE_' + code + '_INHERITANCE', | ||
'Child ' + code.toLowerCase() + ' is sub type of multiple models: ' + | ||
_.map(metadata.parents, function (parent) { | ||
return getDisplayId(parent); | ||
}).join(' && '), defPath, results.errors); | ||
} | ||
_.each(model.properties, function (property, name) { | ||
var pPath = path.concat('properties', name); | ||
if (metadata.cyclical) { | ||
createErrorOrWarning('CYCLICAL_' + code + '_INHERITANCE', | ||
msgPrefix + ' has a circular inheritance: ' + | ||
_.map(lineage, function (dep) { | ||
return getDisplayId(dep); | ||
}).join(' -> ') + ' -> ' + getDisplayId(id), | ||
defPath.concat(swaggerVersion === '1.2' ? 'subTypes' : 'allOf'), results.errors); | ||
} | ||
// Keep track of model references in $ref, items.$ref | ||
if (property.$ref) { | ||
if (!isRemoteRef(property.$ref)) { | ||
getModelMetadata(modelsMetadata, refToJsonPointer(property.$ref)).refs.push(pPath.concat(['$ref'])); | ||
// Remove self reference from the end of the lineage (Front too if cyclical) | ||
_.each(lineage.slice(metadata.cyclical ? 1 : 0), function (id) { | ||
var pModel = traverse(documentMetadata.resolved).get(JsonRefs.pathFromPointer(id)); | ||
_.each(Object.keys(pModel.properties), function (name) { | ||
if (iProperties.indexOf(name) === -1) { | ||
iProperties.push(name); | ||
} | ||
} else if (property.type === 'array') { | ||
validateArrayType(property, pPath, results.errors); | ||
}); | ||
}); | ||
if (!_.isUndefined(property.items) && !_.isUndefined(property.items.$ref) && | ||
!isRemoteRef(property.items.$ref)) { | ||
getModelMetadata(modelsMetadata, | ||
refToJsonPointer(property.items.$ref)).refs.push(pPath.concat(['items', '$ref'])); | ||
} else if (!_.isUndefined(property.items) && !_.isUndefined(property.items.type) && | ||
spec.primitives.indexOf(property.items.type) === -1) { | ||
_.each(property.items, function (schema, index) { | ||
var sPath = pPath.concat('items', index.toString()); | ||
// Validate simple definitions | ||
validateSchemaConstraints(documentMetadata, definition, defPath, results); | ||
processModel(spec, modelsMetadata, schema, toJsonPointer(sPath), sPath, results); | ||
}); | ||
// Identify redeclared properties | ||
_.each(definition.properties, function (property, name) { | ||
var pPath = defPath.concat(['properties', name]); | ||
// Do not process unresolved properties | ||
if (!_.isUndefined(property)) { | ||
validateSchemaConstraints(documentMetadata, property, pPath, results); | ||
if (iProperties.indexOf(name) > -1) { | ||
createErrorOrWarning('CHILD_' + code + '_REDECLARES_PROPERTY', | ||
'Child ' + code.toLowerCase() + ' declares property already declared by ancestor: ' + | ||
name, | ||
pPath, results.errors); | ||
} else { | ||
dProperties.push(name); | ||
} | ||
@@ -517,656 +511,565 @@ } | ||
// Add self reference to all model definitions outside of #/definitions (They are inline models or references) | ||
if (path.length > 3 || toJsonPointer(path).indexOf('#/definitions/') === -1) { | ||
metadata.refs.push(path); | ||
// Identify missing required properties | ||
_.each(definition.required || [], function (name, index) { | ||
if (iProperties.indexOf(name) === -1 && dProperties.indexOf(name) === -1) { | ||
createErrorOrWarning('MISSING_REQUIRED_MODEL_PROPERTY', | ||
'Model requires property but it is not defined: ' + name, | ||
defPath.concat(['required', index.toString()]), results.errors); | ||
} | ||
}); | ||
}); | ||
// Process references (Only processes JSON References, all other references are handled where encountered) | ||
_.each(JsonRefs.findRefs(documentMetadata.original), function (ref, refPtr) { | ||
if (documentMetadata.swaggerVersion === '1.2') { | ||
ref = '#/models/' + ref; | ||
} | ||
break; | ||
// Only process local references | ||
if (!JsonRefs.isRemotePointer(ref)) { | ||
addReference(documentMetadata, ref, refPtr, results); | ||
} | ||
}); | ||
}; | ||
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, path, dest); | ||
} | ||
}; | ||
var getModelsMetadata = function getModelsMetadata (spec, apiDOrSO, results) { | ||
var circular = {}; | ||
var localResults = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
var resolved = {}; | ||
var unresolved = {}; | ||
var addModelProps = function addModelProps (modelId, composed) { | ||
var model = modelsMetadata[modelId].schema; | ||
var processAuthRefs = function processAuthRefs (documentMetadata, authRefs, path, results) { | ||
var code = documentMetadata.swaggerVersion === '1.2' ? 'AUTHORIZATION' : 'SECURITY_DEFINITION'; | ||
var msgPrefix = code === 'AUTHORIZATION' ? 'Authorization' : 'Security definition'; | ||
if (model) { | ||
_.each(model.properties, function (prop, propName) { | ||
var newProp = _.cloneDeep(prop); | ||
if (documentMetadata.swaggerVersion === '1.2') { | ||
_.reduce(authRefs, function (seenNames, scopes, name) { | ||
var authPtr = '#/authorizations/' + name; | ||
var aPath = path.concat([name]); | ||
if (composed.properties[propName]) { | ||
createErrorOrWarning('CHILD_MODEL_REDECLARES_PROPERTY', | ||
'Child model declares property already declared by ancestor: ' + propName, prop, | ||
spec.version === '1.2' ? | ||
['models', modelId, 'properties', propName] : | ||
modelId.substring(2).split('/').concat('properties', propName), localResults.errors); | ||
} else { | ||
if (spec.version === '1.2') { | ||
// Sanitize the maximum/minimum values to be numbers | ||
if (!_.isUndefined(newProp.maximum)) { | ||
newProp.maximum = parseFloat(newProp.maximum); | ||
} | ||
// Add reference or record unresolved authorization | ||
if (addReference(documentMetadata, authPtr, aPath, results)) { | ||
_.reduce(scopes, function (seenScopes, scope, index) { | ||
var sPath = aPath.concat(index.toString(), 'scope'); | ||
var sPtr = authPtr + '/scopes/' + scope.scope; | ||
if (!_.isUndefined(newProp.minimum)) { | ||
newProp.minimum = parseFloat(newProp.minimum); | ||
} | ||
} | ||
composed.properties[propName] = newProp; | ||
} | ||
}); | ||
validateNoExist(seenScopes, scope.scope, code + '_SCOPE_REFERENCE', msgPrefix + ' scope reference', sPath, | ||
results.warnings); | ||
if (!_.isUndefined(model.required) && _.isUndefined(composed.required)) { | ||
composed.required = []; | ||
// Add reference or record unresolved authorization scope | ||
addReference(documentMetadata, sPtr, sPath, results); | ||
return seenScopes.concat(scope.scope); | ||
}, []); | ||
} | ||
_.each(model.required, function (propName) { | ||
if (composed.required.indexOf(propName) === -1) { | ||
composed.required.push(propName); | ||
return seenNames.concat(name); | ||
}, []); | ||
} else { | ||
_.reduce(authRefs, function (seenNames, scopes, index) { | ||
_.each(scopes, function (scopes, name) { | ||
var authPtr = '#/securityDefinitions/' + name; | ||
var authRefPath = path.concat(index.toString(), name); | ||
// Ensure the security definition isn't referenced more than once (Swagger 2.0+) | ||
validateNoExist(seenNames, name, code + '_REFERENCE', msgPrefix + ' reference', authRefPath, | ||
results.warnings); | ||
seenNames.push(name); | ||
// Add reference or record unresolved authorization | ||
if (addReference(documentMetadata, authPtr, authRefPath, results)) { | ||
_.each(scopes, function (scope, index) { | ||
// Add reference or record unresolved authorization scope | ||
addReference(documentMetadata, authPtr + '/scopes/' + scope, authRefPath.concat(index.toString()), | ||
results); | ||
}); | ||
} | ||
}); | ||
return seenNames; | ||
}, []); | ||
} | ||
}; | ||
var resolveRefs = function (apiDOrSO, callback) { | ||
var cacheEntry = getDocumentCache(apiDOrSO); | ||
var swaggerVersion = helpers.getSwaggerVersion(apiDOrSO); | ||
var documentT; | ||
if (!cacheEntry.resolved) { | ||
// For Swagger 1.2, we have to create real JSON References | ||
if (swaggerVersion === '1.2') { | ||
apiDOrSO = _.cloneDeep(apiDOrSO); | ||
documentT = traverse(apiDOrSO); | ||
_.each(JsonRefs.findRefs(apiDOrSO), function (ref, ptr) { | ||
// All Swagger 1.2 references are ALWAYS to models | ||
documentT.set(JsonRefs.pathFromPointer(ptr), '#/models/' + ref); | ||
}); | ||
} | ||
}; | ||
var getPath = function getPath (parent, unresolved) { | ||
var parentVisited = false; | ||
return Object.keys(unresolved).filter(function (dep) { | ||
if (dep === parent) { | ||
parentVisited = true; | ||
// Resolve references | ||
JsonRefs.resolveRefs(apiDOrSO, function (err, json) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
return parentVisited && unresolved[dep]; | ||
cacheEntry.resolved = json; | ||
cacheEntry.resolvedId = SparkMD5.hash(JSON.stringify(json)); | ||
callback(); | ||
}); | ||
}; | ||
var resolver = function resolver (modelId, circular, resolved, unresolved, composed) { | ||
var metadata = modelsMetadata[modelId]; | ||
var model = metadata.schema; | ||
} else { | ||
callback(); | ||
} | ||
}; | ||
unresolved[modelId] = true; | ||
if (!_.isUndefined(model)) { | ||
// 1.2 does not allow multiple inheritance while 2.0+ does | ||
if (metadata.parents.length > 1 && spec.version === '1.2') { | ||
createErrorOrWarning('MULTIPLE_MODEL_INHERITANCE', | ||
'Child model is sub type of multiple models: ' + metadata.parents.join(' && '), model, | ||
['models', modelId], localResults.errors); | ||
var validateAgainstSchema = function validateAgainstSchema (spec, schemaOrName, data, callback) { | ||
var validator = _.isString(schemaOrName) ? spec.validators[schemaOrName] : helpers.createJsonValidator(); | ||
var doValidation = function doValidation () { | ||
try { | ||
validators.validateAgainstSchema(schemaOrName, data, validator); | ||
} catch (err) { | ||
if (err.failedValidation) { | ||
return callback(undefined, err.results); | ||
} else { | ||
_.each(metadata.parents, function (dep) { | ||
if (!resolved[dep]) { | ||
if (unresolved[dep]) { | ||
circular[modelId] = getPath(dep, unresolved); | ||
createErrorOrWarning('CYCLICAL_MODEL_INHERITANCE', | ||
'Model has a circular inheritance: ' + modelId + ' -> ' + | ||
circular[modelId].join(' -> '), | ||
spec.version === '1.2' ? | ||
model.subTypes : | ||
model.allOf, | ||
spec.version === '1.2' ? | ||
['models', modelId, 'subTypes'] : | ||
modelId.substring(2).split('/').concat('allOf'), localResults.errors); | ||
} | ||
// Do not resolve if circular | ||
if (!circular[modelId]) { | ||
resolver(dep, circular, resolved, unresolved, composed); | ||
} | ||
} | ||
// Do not add properties if circular | ||
if (!circular[modelId]) { | ||
addModelProps(dep, composed); | ||
} | ||
}); | ||
return callback(err); | ||
} | ||
} | ||
resolved[modelId] = true; | ||
unresolved[modelId] = false; | ||
resolveRefs(data, function (err) { | ||
return callback(err); | ||
}); | ||
}; | ||
var hash = md5.hash(JSON.stringify(apiDOrSO)); | ||
var metadataEntry = metadataCache[hash]; | ||
var modelsMetadata; | ||
if (_.isUndefined(metadataEntry)) { | ||
metadataEntry = metadataCache[hash] = { | ||
metadata: {}, | ||
results: localResults | ||
}; | ||
addExternalRefsToValidator(validator, data, function (err) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
modelsMetadata = metadataEntry.metadata; | ||
doValidation(); | ||
}); | ||
}; | ||
switch (spec.version) { | ||
case '1.2': | ||
_.reduce(apiDOrSO.models, function (seenModelIds, model, modelName) { | ||
// Validate the model is not already defined (by id) | ||
validateNoExist(seenModelIds, model.id, 'MODEL_DEFINITION', 'Model', ['models', modelName, 'id'], | ||
localResults.errors); | ||
var validateDefinitions = function validateDefinitions (documentMetadata, results) { | ||
// Validate unused definitions | ||
_.each(documentMetadata.definitions, function (metadata, id) { | ||
var defPath = JsonRefs.pathFromPointer(id); | ||
var defType = defPath[0].substring(0, defPath[0].length - 1); | ||
var displayId = documentMetadata.swaggerVersion === '1.2' ? defPath[defPath.length - 1] : id; | ||
var code = defType === 'securityDefinition' ? 'SECURITY_DEFINITION' : defType.toUpperCase(); | ||
var msgPrefix = defType === 'securityDefinition' ? | ||
'Security definition' : | ||
defType.charAt(0).toUpperCase() + defType.substring(1); | ||
processModel(spec, modelsMetadata, model, model.id, ['models', modelName], localResults); | ||
if (metadata.references.length === 0) { | ||
// Swagger 1.2 authorization scope | ||
if (metadata.scopePath) { | ||
code += '_SCOPE'; | ||
msgPrefix += ' scope'; | ||
defPath = metadata.scopePath; | ||
} | ||
return seenModelIds.concat(model.id); | ||
}, []); | ||
createUnusedErrorOrWarning(displayId, code, msgPrefix, defPath, results.warnings); | ||
} | ||
}); | ||
}; | ||
break; | ||
var validateParameters = function validateParameters (spec, documentMetadata, nPath, parameters, path, results, | ||
skipMissing) { | ||
var pathParams = []; | ||
case '2.0': | ||
// Find models defined/referenced in #/definitions | ||
_.each(apiDOrSO.definitions, function (model, modelId) { | ||
var dPath = ['definitions', modelId]; | ||
_.reduce(parameters, function (seenParameters, parameter, index) { | ||
var pPath = path.concat(['parameters', index.toString()]); | ||
processModel(spec, modelsMetadata, model, toJsonPointer(dPath), dPath, localResults); | ||
}); | ||
break; | ||
// Unresolved parameter | ||
if (_.isUndefined(parameter)) { | ||
return; | ||
} | ||
// Compose models and identify inheritance issues | ||
_.each(modelsMetadata, function (metadata, modelId) { | ||
metadata.composed = { | ||
title: 'Composed ' + modelId, | ||
type: 'object', | ||
properties: {} | ||
}; | ||
// Identify duplicate parameter names | ||
validateNoExist(seenParameters, parameter.name, 'PARAMETER', 'Parameter', pPath.concat('name'), | ||
results.errors); | ||
if (!_.isUndefined(metadata.schema)) { | ||
resolver(modelId, circular, resolved, unresolved, metadata.composed); | ||
addModelProps(modelId, metadata.composed); | ||
// Keep track of path parameters | ||
if (parameter.paramType === 'path' || parameter.in === 'path') { | ||
if (nPath.args.indexOf(parameter.name) === -1) { | ||
createErrorOrWarning('UNRESOLVABLE_API_PATH_PARAMETER', | ||
'API path parameter could not be resolved: ' + parameter.name, pPath.concat('name'), | ||
results.errors); | ||
} | ||
// Validate required properties | ||
if (!_.isUndefined(metadata.schema) && !_.isUndefined(metadata.schema.required)) { | ||
_.each(metadata.schema.required, function (propName, index) { | ||
if (_.isUndefined(metadata.composed.properties[propName])) { | ||
createErrorOrWarning('MISSING_REQUIRED_MODEL_PROPERTY', | ||
'Model requires property but it is not defined: ' + propName, propName, | ||
metadata.path.concat(['required', index.toString()]), results.errors); | ||
} | ||
}); | ||
} | ||
}); | ||
pathParams.push(parameter.name); | ||
} | ||
// Resolve references | ||
_.each(modelsMetadata, function (metadata) { | ||
var refs = traverse(metadata.composed).reduce(function (acc) { | ||
if (this.key === '$ref') { | ||
acc[toJsonPointer(this.path)] = spec.version === '1.2' ? this.node : refToJsonPointer(this.node); | ||
} | ||
// Validate parameter constraints | ||
validateSchemaConstraints(documentMetadata, parameter, pPath, results, parameter.skipErrors); | ||
return acc; | ||
}, {}); | ||
return seenParameters.concat(parameter.name); | ||
}, []); | ||
_.each(refs, function (modelId, pathPtr) { | ||
var path = pathPtr.substring(2).split('/'); | ||
var refModel = _.isUndefined(modelsMetadata[modelId]) ? | ||
undefined : | ||
_.cloneDeep(modelsMetadata[modelId].composed); | ||
if (!_.isUndefined(refModel)) { | ||
delete refModel.id; | ||
delete refModel.title; | ||
traverse(metadata.composed).set(path.slice(0, path.length - 1), refModel); | ||
} | ||
}); | ||
// Validate missing path parameters (in path but not in operation.parameters) | ||
if (_.isUndefined(skipMissing) || skipMissing === false) { | ||
_.each(_.difference(nPath.args, pathParams), function (unused) { | ||
createErrorOrWarning('MISSING_API_PATH_PARAMETER', 'API requires path parameter but it is not defined: ' + unused, | ||
documentMetadata.swaggerVersion === '1.2' ? path.slice(0, 2).concat('path') : path, | ||
results.errors); | ||
}); | ||
// Merge results | ||
if (!_.isUndefined(results)) { | ||
_.each(localResults, function (entries, destName) { | ||
results[destName] = results[destName].concat(entries); | ||
}); | ||
} | ||
} | ||
return metadataEntry; | ||
}; | ||
var validateWithSchema = function validateWithSchema (spec, schemaName, data) { | ||
var validator = spec.validators[schemaName]; | ||
var schema = validator.schema[schemaName]; | ||
var result = validator.validate(schema, data); | ||
var response = { | ||
var validateSwagger1_2 = function validateSwagger1_2 (spec, resourceListing, apiDeclarations, callback) { // jshint ignore:line | ||
var adResourcePaths = []; | ||
var rlDocumentMetadata = getDocumentCache(resourceListing); | ||
var rlResourcePaths = []; | ||
var results = { | ||
errors: [], | ||
warnings: [] | ||
warnings: [], | ||
apiDeclarations: [] | ||
}; | ||
if (result) { | ||
response = { | ||
errors: validator.je(schema, data, result, jjveOptions), | ||
warnings: [] | ||
}; | ||
} | ||
// Process Resource Listing resource definitions | ||
rlResourcePaths = _.reduce(resourceListing.apis, function (seenPaths, api, index) { | ||
// Identify duplicate resource paths defined in the Resource Listing | ||
validateNoExist(seenPaths, api.path, 'RESOURCE_PATH', 'Resource path', ['apis', index.toString(), 'path'], | ||
results.errors); | ||
return response; | ||
}; | ||
seenPaths.push(api.path); | ||
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) | ||
return seenPaths; | ||
}, []); | ||
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); | ||
// Process Resource Listing definitions (authorizations) | ||
processDocument(rlDocumentMetadata, results); | ||
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; | ||
}); | ||
}, {}); | ||
// Process each API Declaration | ||
adResourcePaths = _.reduce(apiDeclarations, function (seenResourcePaths, apiDeclaration, index) { | ||
var aResults = results.apiDeclarations[index] = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
var adDocumentMetadata = getDocumentCache(apiDeclaration); | ||
response.apiDeclarations = []; | ||
// Identify duplicate resource paths defined in the API Declarations | ||
validateNoExist(seenResourcePaths, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', | ||
['resourcePath'], aResults.errors); | ||
// Validate the API declarations | ||
_.each(apiDeclarations, function (apiDeclaration, index) { | ||
var result = response.apiDeclarations[index] = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
var apiAuthDefs = {}; | ||
var apiAuthRefs = {}; | ||
var modelsMetadata = getModelsMetadata(spec, apiDeclaration, result).metadata; | ||
var addModelRef = function addModelRef (modelId, modelRef) { | ||
var metadata = getModelMetadata(modelsMetadata, modelId); | ||
if (adResourcePaths.indexOf(apiDeclaration.resourcePath) === -1) { | ||
// Identify unused resource paths defined in the API Declarations | ||
validateExist(rlResourcePaths, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', | ||
['resourcePath'], aResults.errors); | ||
metadata.refs.push(modelRef); | ||
}; | ||
var addScopeRef = function addScopeRef (authId, scopeId) { | ||
var auth; | ||
seenResourcePaths.push(apiDeclaration.resourcePath); | ||
} | ||
if (!_.isUndefined(apiAuthDefs[authId])) { | ||
// Local auth definition | ||
auth = apiAuthRefs[authId]; | ||
// TODO: Process authorization references | ||
// Not possible due to https://github.com/swagger-api/swagger-spec/issues/159 | ||
if (_.isUndefined(auth)) { | ||
auth = apiAuthRefs[authId] = []; | ||
} | ||
} else { | ||
// Global (Or missing in which case we'll assume global) | ||
auth = authRefs[authId]; | ||
// Process models | ||
processDocument(adDocumentMetadata, aResults); | ||
if (_.isUndefined(auth)) { | ||
auth = authRefs[authId] = []; | ||
} | ||
} | ||
// Process the API definitions | ||
_.reduce(apiDeclaration.apis, function (seenPaths, api, index) { | ||
var aPath = ['apis', index.toString()]; | ||
var nPath = normalizePath(api.path); | ||
if (auth.indexOf(scopeId) === -1) { | ||
auth.push(scopeId); | ||
} | ||
}; | ||
// Validate duplicate resource path | ||
if (seenPaths.indexOf(nPath.path) > -1) { | ||
createErrorOrWarning('DUPLICATE_API_PATH', 'API path (or equivalent) already defined: ' + api.path, | ||
aPath.concat('path'), aResults.errors); | ||
} else { | ||
seenPaths.push(nPath.path); | ||
} | ||
// Build the authorization model | ||
_.each(apiDeclaration.authorizations, function (authorization, name) { | ||
apiAuthDefs[name] = _.map(authorization.scopes, function (scope) { | ||
return scope.scope; | ||
}); | ||
}, {}); | ||
// Process the API operations | ||
_.reduce(api.operations, function (seenMethods, operation, index) { | ||
var oPath = aPath.concat(['operations', index.toString()]); | ||
// Validate duplicate resource path | ||
validateNoExist(pathRefs, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', ['resourcePath'], | ||
result.errors); | ||
// Validate duplicate operation method | ||
validateNoExist(seenMethods, operation.method, 'OPERATION_METHOD', 'Operation method', oPath.concat('method'), | ||
aResults.errors); | ||
// Validate missing resource path definition | ||
validateExist(pathDefs, apiDeclaration.resourcePath, 'RESOURCE_PATH', 'Resource path', ['resourcePath'], | ||
result.errors); | ||
// Keep track of the seen methods | ||
seenMethods.push(operation.method); | ||
// Keep track of the seen paths | ||
if (pathRefs.indexOf(apiDeclaration.resourcePath) === -1) { | ||
pathRefs.push(apiDeclaration.resourcePath); | ||
// Keep track of operation types | ||
if (spec.primitives.indexOf(operation.type) === -1 && spec.version === '1.2') { | ||
addReference(adDocumentMetadata, '#/models/' + operation.type, oPath.concat('type'), aResults); | ||
} | ||
// Validate consumes/produces uniqueness | ||
_.each(['consumes', 'produces'], function (name) { | ||
validateNoDuplicates(apiDeclaration[name], 'API_' + name.toUpperCase(), 'API', [name], | ||
result.warnings); | ||
}); | ||
// Process authorization references | ||
processAuthRefs(rlDocumentMetadata, operation.authorizations, oPath.concat('authorizations'), aResults); | ||
// Valdate APIs | ||
_.reduce(apiDeclaration.apis, function (seenApiPaths, api, index) { | ||
var aPath = ['apis', index.toString()]; | ||
var nPath = normalizePath(api.path); | ||
var sParams = []; | ||
// Validate validate inline constraints | ||
validateSchemaConstraints(adDocumentMetadata, operation, oPath, aResults); | ||
// Validate duplicate resource path | ||
if (seenApiPaths.indexOf(nPath.path) > -1) { | ||
createErrorOrWarning('DUPLICATE_API_PATH', 'API path (or equivalent) already defined: ' + api.path, | ||
api.path, aPath.concat('path'), result.errors); | ||
} | ||
// Validate parameters | ||
validateParameters(spec, adDocumentMetadata, nPath, operation.parameters, oPath, aResults); | ||
// Validate operations | ||
_.reduce(api.operations, function (seenMethods, operation, index) { | ||
var oPath = aPath.concat(['operations', index.toString()]); | ||
// Validate unique response code | ||
_.reduce(operation.responseMessages, function (seenResponseCodes, responseMessage, index) { | ||
var rmPath = oPath.concat(['responseMessages', index.toString()]); | ||
// Validate consumes/produces uniqueness | ||
_.each(['consumes', 'produces'], function (name) { | ||
validateNoDuplicates(operation[name], 'OPERATION_' + name.toUpperCase(), 'Operation', | ||
oPath.concat(name), result.warnings); | ||
}); | ||
validateNoExist(seenResponseCodes, responseMessage.code, 'RESPONSE_MESSAGE_CODE', 'Response message code', | ||
rmPath.concat(['code']), aResults.errors); | ||
// Validate unique method | ||
validateNoExist(seenMethods, operation.method, 'OPERATION_METHOD', 'Operation method', | ||
oPath.concat('method'), result.errors); | ||
// Validate missing model | ||
if (responseMessage.responseModel) { | ||
addReference(adDocumentMetadata, '#/models/' + responseMessage.responseModel, | ||
rmPath.concat('responseModel'), aResults); | ||
} | ||
// 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); | ||
return seenResponseCodes.concat(responseMessage.code); | ||
}, []); | ||
// 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); | ||
} | ||
return seenMethods; | ||
}, []); | ||
addScopeRef(name, scope.scope); | ||
}); | ||
}); | ||
return seenPaths; | ||
}, []); | ||
// Validate parameters | ||
_.reduce(operation.parameters, function (seenParameters, parameter, index) { | ||
var pPath = oPath.concat('parameters', index.toString()); | ||
// Validate API Declaration definitions | ||
validateDefinitions(adDocumentMetadata, aResults); | ||
validateArrayType(parameter, pPath, result.errors); | ||
return seenResourcePaths; | ||
}, []); | ||
// 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' && !_.isUndefined(parameter.items) && | ||
!_.isUndefined(parameter.items.$ref)) { | ||
addModelRef(parameter.items.$ref, pPath.concat(['items', '$ref'])); | ||
} | ||
// Validate API Declaration definitions | ||
validateDefinitions(rlDocumentMetadata, results); | ||
// Validate duplicate parameter name | ||
validateNoExist(seenParameters, parameter.name, 'OPERATION_PARAMETER', 'Operation parameter', | ||
pPath.concat('name'), result.errors); | ||
// Identify unused resource paths defined in the Resource Listing | ||
_.each(_.difference(rlResourcePaths, adResourcePaths), function (unused) { | ||
var index = rlResourcePaths.indexOf(unused); | ||
// Keep track of path parameters | ||
if (parameter.paramType === 'path') { | ||
if (nPath.args.indexOf(parameter.name) === -1) { | ||
createErrorOrWarning('UNRESOLVABLE_API_PATH_PARAMETER', | ||
'API path parameter could not be resolved: ' + parameter.name, parameter.name, | ||
pPath.concat('name'), result.errors); | ||
} | ||
createUnusedErrorOrWarning(resourceListing.apis[index].path, 'RESOURCE_PATH', 'Resource path', | ||
['apis', index.toString(), 'path'], results.errors); | ||
}); | ||
if (sParams.indexOf(parameter.name) === -1) { | ||
sParams.push(parameter.name); | ||
} | ||
} | ||
callback(undefined, results); | ||
}; | ||
if (!_.isUndefined(parameter.defaultValue)) { | ||
// Validate default value against constraints | ||
validateParameterConstraints(spec, parameter, parameter.defaultValue, | ||
oPath.concat('parameters', index.toString(), 'defaultValue'), | ||
result.errors); | ||
} | ||
var validateSwagger2_0 = function validateSwagger2_0 (spec, swaggerObject, callback) { // jshint ignore:line | ||
var documentMetadata = getDocumentCache(swaggerObject); | ||
var results = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
return seenParameters.concat(parameter.name); | ||
}, []); | ||
// Process definitions | ||
processDocument(documentMetadata, results); | ||
// Validate missing path parameters (in path but not in operation.parameters) | ||
_.each(_.difference(nPath.args, sParams), function (unused) { | ||
createErrorOrWarning('MISSING_API_PATH_PARAMETER', | ||
'API requires path parameter but it is not defined: ' + unused, api.path, | ||
aPath.concat('path'), result.errors); | ||
}); | ||
// Process security references | ||
processAuthRefs(documentMetadata, swaggerObject.security, ['security'], results); | ||
// 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); | ||
_.reduce(documentMetadata.resolved.paths, function (seenPaths, path, name) { | ||
var pPath = ['paths', name]; | ||
var nPath = normalizePath(name); | ||
// Add model references from responseMessages responseModel | ||
if (responseMessage.responseModel) { | ||
addModelRef(responseMessage.responseModel, | ||
oPath.concat(['responseMessages', index.toString(), 'responseModel'])); | ||
} | ||
// Validate duplicate resource path | ||
if (seenPaths.indexOf(nPath.path) > -1) { | ||
createErrorOrWarning('DUPLICATE_API_PATH', 'API path (or equivalent) already defined: ' + name, pPath, | ||
results.errors); | ||
} | ||
return seenResponseCodes.concat(responseMessage.code); | ||
}, []); | ||
// Validate parameters | ||
validateParameters(spec, documentMetadata, nPath, path.parameters, pPath, results, true); | ||
validateArrayType(operation, oPath, result.errors); | ||
// Validate the Operations | ||
_.each(path, function (operation, method) { | ||
var cParams = []; | ||
var oPath = pPath.concat(method); | ||
var seenParams = []; | ||
// Add model references from type/items | ||
if (operation.type === 'array' && !_.isUndefined(operation.items) && !_.isUndefined(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'])); | ||
} | ||
if (method === 'parameters') { | ||
return; | ||
} | ||
return seenMethods.concat(operation.method); | ||
}, []); | ||
// Process security references | ||
processAuthRefs(documentMetadata, operation.security, oPath.concat('security'), results); | ||
return seenApiPaths.concat(nPath.path); | ||
}, []); | ||
// Compose parameters from path global parameters and operation parameters | ||
_.each(operation.parameters, function (parameter) { | ||
cParams.push(parameter); | ||
// Validate models | ||
_.each(modelsMetadata, function (metadata, modelId) { | ||
// Identify missing models (referenced but not declared) | ||
if (_.isUndefined(metadata.schema)) { | ||
_.each(metadata.refs, function (ref) { | ||
createErrorOrWarning('UNRESOLVABLE_MODEL', 'Model could not be resolved: ' + modelId, | ||
modelId, ref, result.errors); | ||
}); | ||
} | ||
// Identify unused models (declared but not referenced) | ||
if (metadata.refs.length === 0) { | ||
createUnusedErrorOrWarning(metadata.schema, modelId, 'MODEL', 'Model', ['models', metadata.name], | ||
result.warnings); | ||
} | ||
}); | ||
// 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) { | ||
var sIndex = scopes.indexOf(scope); | ||
createUnusedErrorOrWarning(authDef.scopes[sIndex], scope, 'AUTHORIZATION_SCOPE', | ||
'Authorization scope', path.concat(['scopes', sIndex.toString()]), | ||
result.warnings); | ||
}); | ||
}); | ||
seenParams.push(parameter.name + ':' + parameter.in); | ||
}); | ||
// Validate unused resources | ||
_.each(_.difference(pathDefs, pathRefs), function (unused) { | ||
var index = _.map(rlOrSO.apis, function (api) { return api.path; }).indexOf(unused); | ||
_.each(path.parameters, function (parameter) { | ||
var cloned = _.cloneDeep(parameter); | ||
createUnusedErrorOrWarning(rlOrSO.apis[index].path, unused, 'RESOURCE_PATH', 'Resource path', | ||
['apis', index.toString(), 'path'], response.errors); | ||
}); | ||
// The only errors that can occur here are schema constraint validation errors which are already reported above | ||
// so do not report them again. | ||
cloned.skipErrors = true; | ||
// Validate unused authorizations | ||
_.each(_.difference(Object.keys(authDefs), Object.keys(authRefs)), function (unused) { | ||
createUnusedErrorOrWarning(rlOrSO.authorizations[unused], unused, 'AUTHORIZATION', 'Authorization', | ||
['authorizations', unused], response.warnings); | ||
if (seenParams.indexOf(parameter.name + ':' + parameter.in) === -1) { | ||
cParams.push(cloned); | ||
} | ||
}); | ||
// Validate unused authorization scopes | ||
_.each(authRefs, function (scopes, name) { | ||
var path = ['authorizations', name]; | ||
// Validate parameters | ||
validateParameters(spec, documentMetadata, nPath, cParams, oPath, results); | ||
_.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); | ||
}); | ||
// Validate responses | ||
_.each(operation.responses, function (response, responseCode) { | ||
// Validate validate inline constraints | ||
validateSchemaConstraints(documentMetadata, response, oPath.concat('responses', responseCode), results); | ||
}); | ||
} | ||
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) { | ||
var modelsMetadata = getModelsMetadata(spec, rlOrSO, response).metadata; | ||
return seenPaths.concat(nPath.path); | ||
}, []); | ||
// Validate the Paths | ||
_.reduce(rlOrSO.paths, function (seenPaths, path, name) { | ||
var aPath = ['paths', name]; | ||
var nPath = normalizePath(name); | ||
var sParams = []; | ||
// Validate definitions | ||
validateDefinitions(documentMetadata, results); | ||
// Validate duplicate resource path | ||
if (seenPaths.indexOf(nPath.path) > -1) { | ||
createErrorOrWarning('DUPLICATE_API_PATH', 'API path (or equivalent) already defined: ' + name, | ||
name, aPath, response.errors); | ||
} | ||
callback(undefined, results); | ||
}; | ||
// Validate the Operations | ||
_.each(path, function (operation, method) { | ||
var oPath = aPath.concat(method); | ||
var validateSemantically = function validateSemantically (spec, rlOrSO, apiDeclarations, callback) { | ||
var cbWrapper = function cbWrapper (err, results) { | ||
callback(err, helpers.formatResults(results)); | ||
}; | ||
if (spec.version === '1.2') { | ||
validateSwagger1_2(spec, rlOrSO, apiDeclarations, cbWrapper); // jshint ignore:line | ||
} else { | ||
validateSwagger2_0(spec, rlOrSO, cbWrapper); // jshint ignore:line | ||
} | ||
}; | ||
if (method === 'parameters') { | ||
// Validate parameter constraints | ||
_.reduce(path.parameters, function (seenParameters, parameter, index) { | ||
var pPath = oPath.concat(index.toString()); | ||
var validateStructurally = function validateStructurally (spec, rlOrSO, apiDeclarations, callback) { | ||
validateAgainstSchema(spec, spec.version === '1.2' ? 'resourceListing.json' : 'schema.json', rlOrSO, | ||
function (err, results) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
// Validate duplicate parameter name | ||
validateNoExist(seenParameters, parameter.name, 'API_PARAMETER', 'API parameter', | ||
pPath.concat('name'), response.errors); | ||
// Only validate the API Declarations if the API is 1.2 and the Resource Listing was valid | ||
if (!results && spec.version === '1.2') { | ||
results = { | ||
errors: [], | ||
warnings: [], | ||
apiDeclarations: [] | ||
}; | ||
// Keep track of path parameters | ||
if (parameter.in === 'path') { | ||
if (nPath.args.indexOf(parameter.name) === -1) { | ||
createErrorOrWarning('UNRESOLVABLE_API_PATH_PARAMETER', | ||
'API path parameter could not be resolved: ' + parameter.name, parameter.name, | ||
pPath.concat('name'), response.errors); | ||
} | ||
async.map(apiDeclarations, function (apiDeclaration, callback) { | ||
validateAgainstSchema(spec, 'apiDeclaration.json', apiDeclaration, callback); | ||
}, function (err, allResults) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
if (sParams.indexOf(parameter.name) === -1) { | ||
sParams.push(parameter.name); | ||
} | ||
} | ||
_.each(allResults, function (result, index) { | ||
results.apiDeclarations[index] = result; | ||
}); | ||
// Find models defined/referenced in #/paths/{path}/parameters | ||
if (!_.isUndefined(parameter.schema)) { | ||
processModel(spec, modelsMetadata, parameter.schema, toJsonPointer(pPath.concat('schema')), | ||
pPath.concat('schema'), response); | ||
} | ||
callback(undefined, results); | ||
}); | ||
} else { | ||
callback(undefined, results); | ||
} | ||
}); | ||
}; | ||
return seenParameters.concat(parameter.name); | ||
}, []); | ||
/** | ||
* Callback used by all json-refs functions. | ||
* | ||
* @param {error} [err] - The error if there is a problem | ||
* @param {*} [result] - The result of the function | ||
* | ||
* @callback resultCallback | ||
*/ | ||
return; | ||
} | ||
/** | ||
* Creates a new Swagger specification object. | ||
* | ||
* @param {string} version - The Swagger version | ||
* | ||
* @constructor | ||
*/ | ||
var Specification = function Specification (version) { | ||
var createValidators = function createValidators (spec, validatorsMap) { | ||
return _.reduce(validatorsMap, function (result, schemas, schemaName) { | ||
result[schemaName] = helpers.createJsonValidator(schemas); | ||
// 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); | ||
}); | ||
return result; | ||
}.bind(this), {}); | ||
}; | ||
var fixSchemaId = function fixSchemaId (schemaName) { | ||
// Swagger 1.2 schema files use one id but use a different id when referencing schema files. We also use the schema | ||
// file name to reference the schema in ZSchema. To fix this so that the JSON Schema validator works properly, we | ||
// need to set the id to be the name of the schema file. | ||
var fixed = _.cloneDeep(this.schemas[schemaName]); | ||
// Validate parameter constraints | ||
_.reduce(operation.parameters, function (seenParameters, parameter, index) { | ||
var pPath = oPath.concat('parameters', index.toString()); | ||
fixed.id = schemaName; | ||
// Validate duplicate parameter name | ||
validateNoExist(seenParameters, parameter.name, 'OPERATION_PARAMETER', 'Operation parameter', | ||
pPath.concat('name'), response.errors); | ||
return fixed; | ||
}.bind(this); | ||
var primitives = ['string', 'number', 'boolean', 'integer', 'array']; | ||
// Keep track of path parameters | ||
if (parameter.in === 'path') { | ||
if (nPath.args.indexOf(parameter.name) === -1) { | ||
createErrorOrWarning('UNRESOLVABLE_API_PATH_PARAMETER', | ||
'API path parameter could not be resolved: ' + parameter.name, parameter.name, | ||
pPath.concat('name'), response.errors); | ||
} | ||
switch (version) { | ||
case '1.2': | ||
this.docsUrl = 'https://github.com/swagger-api/swagger-spec/blob/master/versions/1.2.md'; | ||
this.primitives = _.union(primitives, ['void', 'File']); | ||
this.schemasUrl = 'https://github.com/swagger-api/swagger-spec/tree/master/schemas/v1.2'; | ||
if (sParams.indexOf(parameter.name) === -1) { | ||
sParams.push(parameter.name); | ||
} | ||
} | ||
// Here explicitly to allow browserify to work | ||
this.schemas = { | ||
'apiDeclaration.json': require('../schemas/1.2/apiDeclaration.json'), | ||
'authorizationObject.json': require('../schemas/1.2/authorizationObject.json'), | ||
'dataType.json': require('../schemas/1.2/dataType.json'), | ||
'dataTypeBase.json': require('../schemas/1.2/dataTypeBase.json'), | ||
'infoObject.json': require('../schemas/1.2/infoObject.json'), | ||
'modelsObject.json': require('../schemas/1.2/modelsObject.json'), | ||
'oauth2GrantType.json': require('../schemas/1.2/oauth2GrantType.json'), | ||
'operationObject.json': require('../schemas/1.2/operationObject.json'), | ||
'parameterObject.json': require('../schemas/1.2/parameterObject.json'), | ||
'resourceListing.json': require('../schemas/1.2/resourceListing.json'), | ||
'resourceObject.json': require('../schemas/1.2/resourceObject.json') | ||
}; | ||
// Find models defined/referenced in #/paths/{path}/{method}/parameters | ||
if (!_.isUndefined(parameter.schema)) { | ||
processModel(spec, modelsMetadata, parameter.schema, toJsonPointer(pPath.concat('schema')), | ||
pPath.concat('schema'), response); | ||
} | ||
this.validators = createValidators(this, { | ||
'apiDeclaration.json': _.map([ | ||
'dataTypeBase.json', | ||
'modelsObject.json', | ||
'oauth2GrantType.json', | ||
'authorizationObject.json', | ||
'parameterObject.json', | ||
'operationObject.json', | ||
'apiDeclaration.json' | ||
], fixSchemaId), | ||
'resourceListing.json': _.map([ | ||
'resourceObject.json', | ||
'infoObject.json', | ||
'oauth2GrantType.json', | ||
'authorizationObject.json', | ||
'resourceListing.json' | ||
], fixSchemaId) | ||
}); | ||
return seenParameters.concat(parameter.name); | ||
}, []); | ||
break; | ||
// Find models defined/referenced in #/paths/{path}/{method}/responses | ||
_.each(operation.responses, function (responseObj, responseCode) { | ||
var rPath = oPath.concat('responses', responseCode); | ||
case '2.0': | ||
this.docsUrl = 'https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md'; | ||
this.primitives = _.union(primitives, ['file']); | ||
this.schemasUrl = 'https://github.com/swagger-api/swagger-spec/tree/master/schemas/v2.0'; | ||
if (!_.isUndefined(responseObj.schema)) { | ||
processModel(spec, modelsMetadata, responseObj.schema, toJsonPointer(rPath.concat('schema')), | ||
rPath.concat('schema'), response); | ||
} | ||
}); | ||
}); | ||
// Here explicitly to allow browserify to work | ||
this.schemas = { | ||
'schema.json': require('../schemas/2.0/schema.json') | ||
}; | ||
// Validate missing path parameters (in path but not in operation.parameters) | ||
_.each(_.difference(nPath.args, sParams), function (unused) { | ||
createErrorOrWarning('MISSING_API_PATH_PARAMETER', | ||
'API requires path parameter but it is not defined: ' + unused, name, | ||
aPath, response.errors); | ||
}); | ||
this.validators = createValidators(this, { | ||
'schema.json': [fixSchemaId('schema.json')] | ||
}); | ||
return seenPaths.concat(nPath.path); | ||
}, []); | ||
break; | ||
// Validate models | ||
_.each(modelsMetadata, function (metadata, modelId) { | ||
// Identify missing models (referenced but not declared) | ||
if (_.isUndefined(metadata.schema)) { | ||
_.each(metadata.refs, function (ref) { | ||
createErrorOrWarning('UNRESOLVABLE_MODEL', 'Model could not be resolved: ' + modelId, modelId, ref, | ||
response.errors); | ||
}); | ||
} | ||
// Identify unused models (declared but not referenced) | ||
if (metadata.refs.length === 0) { | ||
createUnusedErrorOrWarning(metadata.schema, modelId, 'MODEL', 'Model', modelId.substring(2).split('/'), | ||
response.warnings); | ||
} | ||
}); | ||
} | ||
break; | ||
default: | ||
throw new Error(version + ' is an unsupported Swagger specification version'); | ||
} | ||
return response; | ||
this.version = version; | ||
}; | ||
@@ -1179,12 +1082,9 @@ | ||
* @param {object[]} [apiDeclarations] - The array of Swagger API Declarations (1.2) | ||
* @param {resultCallback} callback - The result callback | ||
* | ||
* @returns undefined if validation passes or an object containing errors and/or warnings | ||
* @throws Error if the arguments provided are not valid | ||
*/ | ||
Specification.prototype.validate = function validate (rlOrSO, apiDeclarations) { | ||
var response = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
var skipRemaining = false; | ||
Specification.prototype.validate = function validate (rlOrSO, apiDeclarations, callback) { | ||
// Validate arguments | ||
switch (this.version) { | ||
@@ -1205,37 +1105,94 @@ case '1.2': | ||
// Validate structurally | ||
response = validateWithSchema(this, 'resourceListing.json', rlOrSO); | ||
break; | ||
if (response.errors.length > 0) { | ||
skipRemaining = true; | ||
case '2.0': | ||
// Validate arguments | ||
if (_.isUndefined(rlOrSO)) { | ||
throw new Error('swaggerObject is required'); | ||
} else if (!_.isPlainObject(rlOrSO)) { | ||
throw new TypeError('swaggerObject must be an object'); | ||
} | ||
if (!skipRemaining) { | ||
response.apiDeclarations = []; | ||
break; | ||
} | ||
_.each(apiDeclarations, function (apiDeclaration, index) { | ||
response.apiDeclarations[index] = validateWithSchema(this, 'apiDeclaration.json', apiDeclaration); | ||
if (this.version === '2.0') { | ||
callback = arguments[1]; | ||
} | ||
if (response.apiDeclarations[index].errors.length > 0) { | ||
skipRemaining = true; | ||
if (_.isUndefined(callback)) { | ||
throw new Error('callback is required'); | ||
} else if (!_.isFunction(callback)) { | ||
throw new TypeError('callback must be a function'); | ||
} | ||
// Skip the remaining validation | ||
return false; | ||
} | ||
}.bind(this)); | ||
// For Swagger 2.0, make sure apiDeclarations is an empty array | ||
if (this.version === '2.0') { | ||
apiDeclarations = []; | ||
} | ||
// Perform the validation | ||
validateStructurally(this, rlOrSO, apiDeclarations, function (err, result) { | ||
if (err || helpers.formatResults(result)) { | ||
callback(err, result); | ||
} else { | ||
validateSemantically(this, rlOrSO, apiDeclarations, callback); | ||
} | ||
}.bind(this)); | ||
}; | ||
// Validate semantically | ||
if (!skipRemaining) { | ||
response = validateContent(this, rlOrSO, apiDeclarations); | ||
/** | ||
* Returns a JSON Schema representation of a composed model based on its id or reference. | ||
* | ||
* @param {object} apiDOrSO - The Swagger Resource API Declaration (1.2) or the Swagger Object (2.0) | ||
* @param {string} modelIdOrRef - The model id (1.2) or the reference to the model (1.2 or 2.0) | ||
* @param {resultCallback} callback - The result callback | ||
* | ||
* @returns the object representing a composed object | ||
* | ||
* @throws Error if there are validation errors while creating | ||
*/ | ||
Specification.prototype.composeModel = function composeModel (apiDOrSO, modelIdOrRef, callback) { | ||
var swaggerVersion = helpers.getSwaggerVersion(apiDOrSO); | ||
var doComposition = function doComposition (err, results) { | ||
var documentMetadata; | ||
if (err) { | ||
return callback(err); | ||
} else if (helpers.formatResults(results)) { | ||
return handleValidationError(results, callback); | ||
} | ||
// Set the response | ||
response = response.errors.length > 0 || response.warnings.length > 0 || | ||
_.reduce(response.apiDeclarations, function (count, apiDeclaration) { | ||
return count + | ||
(_.isArray(apiDeclaration.errors) ? apiDeclaration.errors.length : 0) + | ||
(_.isArray(apiDeclaration.warnings) ? apiDeclaration.warnings.length : 0); | ||
}, 0) > 0 ? response : undefined; | ||
documentMetadata = getDocumentCache(apiDOrSO); | ||
results = { | ||
errors: [], | ||
warnings: [] | ||
}; | ||
processDocument(documentMetadata, results); | ||
if (!documentMetadata.definitions[modelIdOrRef]) { | ||
return callback(); | ||
} | ||
if (helpers.formatResults(results)) { | ||
return handleValidationError(results, callback); | ||
} | ||
callback(undefined, getOrComposeSchema(documentMetadata, modelIdOrRef)); | ||
}; | ||
switch (this.version) { | ||
case '1.2': | ||
// Validate arguments | ||
if (_.isUndefined(apiDOrSO)) { | ||
throw new Error('apiDeclaration is required'); | ||
} else if (!_.isPlainObject(apiDOrSO)) { | ||
throw new TypeError('apiDeclaration must be an object'); | ||
} | ||
if (_.isUndefined(modelIdOrRef)) { | ||
throw new Error('modelId is required'); | ||
} | ||
break; | ||
@@ -1245,45 +1202,47 @@ | ||
// Validate arguments | ||
if (_.isUndefined(rlOrSO)) { | ||
if (_.isUndefined(apiDOrSO)) { | ||
throw new Error('swaggerObject is required'); | ||
} else if (!_.isPlainObject(rlOrSO)) { | ||
} else if (!_.isPlainObject(apiDOrSO)) { | ||
throw new TypeError('swaggerObject must be an object'); | ||
} | ||
// Validate structurally | ||
response = validateWithSchema(this, 'schema.json', rlOrSO); | ||
if (response.errors.length > 0) { | ||
skipRemaining = true; | ||
if (_.isUndefined(modelIdOrRef)) { | ||
throw new Error('modelRef is required'); | ||
} | ||
// Validate semantically | ||
if (!skipRemaining) { | ||
response = validateContent(this, rlOrSO); | ||
} | ||
break; | ||
} | ||
// Set the response | ||
response = response.errors.length > 0 || response.warnings.length > 0 ? response : undefined; | ||
if (_.isUndefined(callback)) { | ||
throw new Error('callback is required'); | ||
} else if (!_.isFunction(callback)) { | ||
throw new TypeError('callback must be a function'); | ||
} | ||
break; | ||
if (modelIdOrRef.charAt(0) !== '#') { | ||
if (this.version === '1.2') { | ||
modelIdOrRef = '#/models/' + modelIdOrRef; | ||
} else { | ||
throw new Error('modelRef must be a JSON Pointer'); | ||
} | ||
} | ||
return response; | ||
// Ensure the document is valid first | ||
validateAgainstSchema(this, swaggerVersion === '1.2' ? 'apiDeclaration.json' : 'schema.json', apiDOrSO, | ||
doComposition); | ||
}; | ||
/** | ||
* Returns a JSON Schema representation of a composed model based on its id. | ||
* Validates a model based on its id. | ||
* | ||
* @param {object} apiDOrSO - The Swagger Resource API Declaration (1.2) or the Swagger Object (2.0) | ||
* @param {string} modelIdOrPath - The model id (1.2 or 2.0) or the path to the model (2.0) | ||
* @param {string} modelIdOrRef - The model id (1.2) or the reference to the model (1.2 or 2.0) | ||
* @param {object} data - The model to validate | ||
* @param {resultCallback} callback - The result callback | ||
* | ||
* @returns the object representing a composed object | ||
* @returns undefined if validation passes or an object containing errors and/or warnings | ||
* | ||
* @throws Error if there are validation errors while creating | ||
*/ | ||
Specification.prototype.composeModel = function composeModel (apiDOrSO, modelIdOrPath) { | ||
var metadataEntry; | ||
var modelMetadata; | ||
var modelsMetadata; | ||
var err; | ||
Specification.prototype.validateModel = function validateModel (apiDOrSO, modelIdOrRef, data, callback) { | ||
switch (this.version) { | ||
@@ -1298,3 +1257,3 @@ case '1.2': | ||
if (_.isUndefined(modelIdOrPath)) { | ||
if (_.isUndefined(modelIdOrRef)) { | ||
throw new Error('modelId is required'); | ||
@@ -1313,4 +1272,4 @@ } | ||
if (_.isUndefined(modelIdOrPath)) { | ||
throw new Error('modelIdOrPath is required'); | ||
if (_.isUndefined(modelIdOrRef)) { | ||
throw new Error('modelRef is required'); | ||
} | ||
@@ -1321,54 +1280,100 @@ | ||
metadataEntry = getModelsMetadata(this, apiDOrSO); | ||
modelsMetadata = metadataEntry.metadata; | ||
if (_.isUndefined(data)) { | ||
throw new Error('data is required'); | ||
} | ||
// Composing a model for an invalid model hierarchy is brittle and so we will not do it | ||
if (metadataEntry.results.errors.length > 0) { | ||
err = new Error('The models are invalid and model composition is not possible'); | ||
err.errors = metadataEntry.results.errors; | ||
err.warnings = metadataEntry.results.warnings; | ||
throw err; | ||
if (_.isUndefined(callback)) { | ||
throw new Error('callback is required'); | ||
} else if (!_.isFunction(callback)) { | ||
throw new TypeError('callback must be a function'); | ||
} | ||
modelMetadata = modelsMetadata[this.version === '1.2' ? | ||
modelIdOrPath : | ||
refToJsonPointer(modelIdOrPath)]; | ||
this.composeModel(apiDOrSO, modelIdOrRef, function (err, result) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
return _.isUndefined(modelMetadata) ? undefined : modelMetadata.composed; | ||
validateAgainstSchema(this, result, data, callback); | ||
}.bind(this)); | ||
}; | ||
/** | ||
* Validates a model based on its id. | ||
* Returns a fully resolved document or document fragment. (Does not perform validation as this is typically called | ||
* after validation occurs.)) | ||
* | ||
* @param {object} apiDOrSO - The Swagger Resource API Declaration (1.2) or the Swagger Object (2.0) | ||
* @param {string} modelIdOrPath - The model id (1.2 or 2.0) or the path to the model (2.0) | ||
* @param {object} data - The model to validate | ||
* @param {object} document - The document to resolve or the document containing the reference to resolve | ||
* @param {string} [ptr] - The JSON Pointer or undefined to return the whole document | ||
* @param {resultCallback} callback - The result callback | ||
* | ||
* @returns undefined if validation passes or an object containing errors and/or warnings | ||
* @returns the fully resolved document or fragment | ||
* | ||
* @throws Error if there are validation errors while creating | ||
* @throws Error if there are upstream errors | ||
*/ | ||
Specification.prototype.validateModel = function validateModel (apiDOrSO, modelIdOrPath, data) { | ||
var modelSchema = this.composeModel(apiDOrSO, modelIdOrPath); | ||
var result; | ||
var validator; | ||
Specification.prototype.resolve = function resolve (document, ptr, callback) { | ||
var documentMetadata; | ||
var schemaName; | ||
var respond = function respond (document) { | ||
if (_.isString(ptr)) { | ||
return callback(undefined, traverse(document).get(JsonRefs.pathFromPointer(ptr))); | ||
} else { | ||
return callback(undefined, document); | ||
} | ||
}; | ||
if (_.isUndefined(modelSchema)) { | ||
throw new Error('Unable to compose model so validation is not possible'); | ||
// Validate arguments | ||
if (_.isUndefined(document)) { | ||
throw new Error('document is required'); | ||
} else if (!_.isPlainObject(document)) { | ||
throw new TypeError('document must be an object'); | ||
} | ||
validator = createValidator(this); | ||
result = validator.validate(modelSchema, data); | ||
if (arguments.length === 2) { | ||
callback = arguments[1]; | ||
ptr = undefined; | ||
} | ||
if (result) { | ||
result = { | ||
errors: validator.je(modelSchema, data, result, jjveOptions) | ||
}; | ||
if (!_.isUndefined(ptr) && !_.isString(ptr)) { | ||
throw new TypeError('ptr must be a JSON Pointer string'); | ||
} | ||
if (_.isUndefined(callback)) { | ||
throw new Error('callback is required'); | ||
} else if (!_.isFunction(callback)) { | ||
throw new TypeError('callback must be a function'); | ||
} | ||
documentMetadata = getDocumentCache(document); | ||
// Swagger 1.2 is not supported due to invalid JSON References being used. Even if the JSON References were valid, | ||
// the JSON Schema for Swagger 1.2 do not allow JavaScript objects in all places where the resoution would occur. | ||
if (documentMetadata.swaggerVersion === '1.2') { | ||
throw new Error('Swagger 1.2 is not supported'); | ||
} | ||
if (!documentMetadata.resolved) { | ||
if (documentMetadata.swaggerVersion === '1.2') { | ||
if (_.find(['basePath', 'consumes', 'models', 'produces', 'resourcePath'], function (name) { | ||
return !_.isUndefined(document[name]); | ||
})) { | ||
schemaName = 'apiDeclaration.json'; | ||
} else { | ||
schemaName = 'resourceListing.json'; | ||
} | ||
} else { | ||
schemaName = 'schema.json'; | ||
} | ||
// Ensure the document is valid first | ||
validateAgainstSchema(this, schemaName, document, function (err, results) { | ||
if (err) { | ||
return callback(err); | ||
} else if (helpers.formatResults(results)) { | ||
return handleValidationError(results, callback); | ||
} | ||
return respond(documentMetadata.resolved); | ||
}); | ||
} else { | ||
result = undefined; | ||
return respond(documentMetadata.resolved); | ||
} | ||
return result; | ||
}; | ||
@@ -1375,0 +1380,0 @@ |
@@ -34,9 +34,2 @@ /* | ||
var dateTimeRegExp = /^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$/; | ||
var throwInvalidParameter = function throwInvalidParameter (name, message) { | ||
var err = new Error('Parameter (' + name + ') ' + message); | ||
err.failedValidation = true; | ||
throw err; | ||
}; | ||
var isValidDate = function isValidDate (date) { | ||
@@ -104,3 +97,66 @@ var day; | ||
var throwErrorWithCode = function throwErrorWithCode (code, msg) { | ||
var err = new Error(msg); | ||
err.code = code; | ||
err.failedValidation = true; | ||
throw err; | ||
}; | ||
module.exports.validateAgainstSchema = function validateAgainstSchema (schemaOrName, data, validator) { | ||
var removeParams = function (obj) { | ||
delete obj.params; | ||
if (obj.inner) { | ||
_.each(obj.inner, function (nObj) { | ||
removeParams(nObj); | ||
}); | ||
} | ||
}; | ||
var schema = _.isPlainObject(schemaOrName) ? _.cloneDeep(schemaOrName) : schemaOrName; | ||
// We don't check this due to internal usage but if validator is not provided, schemaOrName must be a schema | ||
if (_.isUndefined(validator)) { | ||
validator = helpers.createJsonValidator([schema]); | ||
} | ||
var valid = validator.validate(data, schema); | ||
if (!valid) { | ||
try { | ||
throwErrorWithCode('SCHEMA_VALIDATION_FAILED', 'Failed schema validation'); | ||
} catch (err) { | ||
err.results = { | ||
errors: _.map(validator.getLastErrors(), function (err) { | ||
removeParams(err); | ||
return err; | ||
}), | ||
warnings: [] | ||
}; | ||
throw err; | ||
} | ||
} | ||
}; | ||
/** | ||
* Validates a schema of type array is properly formed (when necessar). | ||
* | ||
* *param {object} schema - The schema object to validate | ||
* | ||
* @throws Error if the schema says it's an array but it is not formed properly | ||
* | ||
* @see {@link https://github.com/swagger-api/swagger-spec/issues/174} | ||
*/ | ||
var validateArrayType = module.exports.validateArrayType = function validateArrayType (schema) { | ||
// We have to do this manually for now | ||
if (schema.type === 'array' && _.isUndefined(schema.items)) { | ||
throwErrorWithCode('OBJECT_MISSING_REQUIRED_PROPERTY', 'Missing required property: items'); | ||
} | ||
}; | ||
/** | ||
* Validates the request's content type (when necessary). | ||
@@ -129,5 +185,4 @@ * | ||
/** | ||
* Validates the request parameter's value against the allowable values (when necessary). | ||
* Validates the value against the allowable values (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*} val - The parameter value | ||
@@ -138,5 +193,5 @@ * @param {string[]} allowed - The allowable values | ||
*/ | ||
module.exports.validateEnum = function validateEnum (name, val, allowed) { | ||
var validateEnum = module.exports.validateEnum = function validateEnum (val, allowed) { | ||
if (!_.isUndefined(allowed) && !_.isUndefined(val) && allowed.indexOf(val) === -1) { | ||
throwInvalidParameter(name, 'is not an allowable value (' + allowed.join(', ') + '): ' + val); | ||
throwErrorWithCode('ENUM_MISMATCH', 'Not an allowable value (' + allowed.join(', ') + '): ' + val); | ||
} | ||
@@ -146,5 +201,4 @@ }; | ||
/** | ||
* Validates the request parameter's value is less than the maximum (when necessary). | ||
* Validates the value is less than the maximum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*} val - The parameter value | ||
@@ -156,3 +210,4 @@ * @param {string} maximum - The maximum value | ||
*/ | ||
module.exports.validateMaximum = function validateMaximum (name, val, maximum, type, exclusive) { | ||
var validateMaximum = module.exports.validateMaximum = function validateMaximum (val, maximum, type, exclusive) { | ||
var code = exclusive === true ? 'MAXIMUM_EXCLUSIVE' : 'MAXIMUM'; | ||
var testMax; | ||
@@ -175,5 +230,5 @@ var testVal; | ||
if (exclusive && testVal >= testMax) { | ||
throwInvalidParameter(name, 'is greater than or equal to the configured maximum (' + maximum + '): ' + val); | ||
throwErrorWithCode(code, 'Greater than or equal to the configured maximum (' + maximum + '): ' + val); | ||
} else if (testVal > testMax) { | ||
throwInvalidParameter(name, 'is greater than the configured maximum (' + maximum + '): ' + val); | ||
throwErrorWithCode(code, 'Greater than the configured maximum (' + maximum + '): ' + val); | ||
} | ||
@@ -184,5 +239,4 @@ } | ||
/** | ||
* Validates the request parameter's array count is less than the maximum (when necessary). | ||
* Validates the array count is less than the maximum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*[]} val - The parameter value | ||
@@ -193,5 +247,5 @@ * @param {number} maxItems - The maximum number of items | ||
*/ | ||
module.exports.validateMaxItems = function validateMaxItems (name, val, maxItems) { | ||
var validateMaxItems = module.exports.validateMaxItems = function validateMaxItems (val, maxItems) { | ||
if (!_.isUndefined(maxItems) && val.length > maxItems) { | ||
throwInvalidParameter(name, 'contains more items than allowed: ' + maxItems); | ||
throwErrorWithCode('ARRAY_LENGTH_LONG', 'Array is too long (' + val.length + '), maximum ' + maxItems); | ||
} | ||
@@ -201,5 +255,4 @@ }; | ||
/** | ||
* Validates the request parameter's length is less than the maximum (when necessary). | ||
* Validates the value length is less than the maximum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*[]} val - The parameter value | ||
@@ -210,5 +263,5 @@ * @param {number} maxLength - The maximum length | ||
*/ | ||
module.exports.validateMaxLength = function validateMaxLength (name, val, maxLength) { | ||
var validateMaxLength = module.exports.validateMaxLength = function validateMaxLength (val, maxLength) { | ||
if (!_.isUndefined(maxLength) && val.length > maxLength) { | ||
throwInvalidParameter(name, 'is longer than allowed: ' + maxLength); | ||
throwErrorWithCode('MAX_LENGTH', 'String is too long (' + val.length + ' chars), maximum ' + maxLength); | ||
} | ||
@@ -218,5 +271,21 @@ }; | ||
/** | ||
* Validates the request parameter's array count is greater than the minimum (when necessary). | ||
* Validates the value's property count is greater than the maximum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*[]} val - The parameter value | ||
* @param {number} minProperties - The maximum number of properties | ||
* | ||
* @throws Error if the value's property count is less than the maximum | ||
*/ | ||
var validateMaxProperties = module.exports.validateMaxProperties = function validateMaxLength (val, maxProperties) { | ||
var propCount = _.isPlainObject(val) ? Object.keys(val).length : 0; | ||
if (!_.isUndefined(maxProperties) && propCount > maxProperties) { | ||
throwErrorWithCode('MAX_PROPERTIES', | ||
'Number of properties is too many (' + propCount + ' properties), maximum ' + maxProperties); | ||
} | ||
}; | ||
/** | ||
* Validates the value array count is greater than the minimum (when necessary). | ||
* | ||
* @param {*} val - The parameter value | ||
@@ -228,3 +297,4 @@ * @param {string} minimum - The minimum value | ||
*/ | ||
module.exports.validateMinimum = function validateMinimum (name, val, minimum, type, exclusive) { | ||
var validateMinimum = module.exports.validateMinimum = function validateMinimum (val, minimum, type, exclusive) { | ||
var code = exclusive === true ? 'MINIMUM_EXCLUSIVE' : 'MINIMUM'; | ||
var testMin; | ||
@@ -247,5 +317,5 @@ var testVal; | ||
if (exclusive && testVal <= testMin) { | ||
throwInvalidParameter(name, 'is less than or equal to the configured minimum (' + minimum + '): ' + val); | ||
throwErrorWithCode(code, 'Less than or equal to the configured minimum (' + minimum + '): ' + val); | ||
} else if (testVal < testMin) { | ||
throwInvalidParameter(name, 'is less than the configured minimum (' + minimum + '): ' + val); | ||
throwErrorWithCode(code, 'Less than the configured minimum (' + minimum + '): ' + val); | ||
} | ||
@@ -256,5 +326,4 @@ } | ||
/** | ||
* Validates the request parameter's value contains fewer items than allowed (when necessary). | ||
* Validates the value value contains fewer items than allowed (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*[]} val - The parameter value | ||
@@ -265,5 +334,5 @@ * @param {number} minItems - The minimum number of items | ||
*/ | ||
module.exports.validateMinItems = function validateMinItems (name, val, minItems) { | ||
var validateMinItems = module.exports.validateMinItems = function validateMinItems (val, minItems) { | ||
if (!_.isUndefined(minItems) && val.length < minItems) { | ||
throwInvalidParameter(name, 'contains fewer items than allowed: ' + minItems); | ||
throwErrorWithCode('ARRAY_LENGTH_SHORT', 'Array is too short (' + val.length + '), minimum ' + minItems); | ||
} | ||
@@ -273,5 +342,4 @@ }; | ||
/** | ||
* Validates the request parameter's length is greater than the minimum (when necessary). | ||
* Validates the value length is less than the minimum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*[]} val - The parameter value | ||
@@ -282,5 +350,5 @@ * @param {number} minLength - The minimum length | ||
*/ | ||
module.exports.validateMinLength = function validateMinLength (name, val, minLength) { | ||
var validateMinLength = module.exports.validateMinLength = function validateMinLength (val, minLength) { | ||
if (!_.isUndefined(minLength) && val.length < minLength) { | ||
throwInvalidParameter(name, 'is shorter than allowed: ' + minLength); | ||
throwErrorWithCode('MIN_LENGTH', 'String is too short (' + val.length + ' chars), minimum ' + minLength); | ||
} | ||
@@ -290,34 +358,29 @@ }; | ||
/** | ||
* Validtes the request parameter against its model schema. | ||
* Validates the value's property count is less than or equal to the minimum (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {object} val - The parameter value | ||
* @param {string} version - The Swagger version | ||
* @param {object} apiDOrSO - The Swagger API Declaration (1.2) or Swagger Object (2.0) | ||
* @param {string} modelIdOrPath - The model id or path | ||
* @param {*[]} val - The parameter value | ||
* @param {number} minProperties - The minimum number of properties | ||
* | ||
* @throws Error if the value is not a valid model | ||
* @throws Error if the value's property count is less than the minimum | ||
*/ | ||
module.exports.validateModel = function validateModel (name, val, version, apiDOrSO, modelIdOrPath) { | ||
var spec = helpers.getSpec(version); | ||
var validate = function validate (data) { | ||
var result = spec.validateModel(apiDOrSO, modelIdOrPath, data); | ||
var validateMinProperties = module.exports.validateMinProperties = function validateMinLength (val, minProperties) { | ||
var propCount = _.isPlainObject(val) ? Object.keys(val).length : 0; | ||
if (!_.isUndefined(result)) { | ||
try { | ||
throwInvalidParameter(name, 'is not a valid ' + modelIdOrPath + ' model'); | ||
} catch (err) { | ||
err.errors = result.errors; | ||
if (!_.isUndefined(minProperties) && propCount < minProperties) { | ||
throwErrorWithCode('MIN_PROPERTIES', | ||
'Number of properties is too few (' + propCount + ' properties), minimum ' + minProperties); | ||
} | ||
}; | ||
throw err; | ||
} | ||
} | ||
}; | ||
if (_.isArray(val)) { | ||
_.each(val, function (item) { | ||
validate(item); | ||
}); | ||
} else { | ||
validate(val); | ||
/** | ||
* Validates the value is a multiple of the provided number (when necessary). | ||
* | ||
* @param {*[]} val - The parameter value | ||
* @param {number} multipleOf - The number that should divide evenly into the value | ||
* | ||
* @throws Error if the value contains fewer items than allowable | ||
*/ | ||
var validateMultipleOf = module.exports.validateMultipleOf = function validateMultipleOf (val, multipleOf) { | ||
if (!_.isUndefined(multipleOf) && val % multipleOf !== 0) { | ||
throwErrorWithCode('MULTIPLE_OF', 'Not a multiple of ' + multipleOf); | ||
} | ||
@@ -327,3 +390,3 @@ }; | ||
/** | ||
* Validates the request parameter's matches a pattern (when necessary). | ||
* Validates the value matches a pattern (when necessary). | ||
* | ||
@@ -336,5 +399,5 @@ * @param {string} name - The parameter name | ||
*/ | ||
module.exports.validatePattern = function validatePattern (name, val, pattern) { | ||
var validatePattern = module.exports.validatePattern = function validatePattern (val, pattern) { | ||
if (!_.isUndefined(pattern) && _.isNull(val.match(new RegExp(pattern)))) { | ||
throwInvalidParameter(name, 'does not match required pattern: ' + pattern); | ||
throwErrorWithCode('PATTERN', 'Does not match required pattern: ' + pattern); | ||
} | ||
@@ -344,5 +407,4 @@ }; | ||
/** | ||
* Validates the request parameter's requiredness (when necessary). | ||
* Validates the value requiredness (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*} val - The parameter value | ||
@@ -353,5 +415,5 @@ * @param {boolean} required - Whether or not the parameter is required | ||
*/ | ||
module.exports.validateRequiredness = function validateRequiredness (name, val, required) { | ||
module.exports.validateRequiredness = function validateRequiredness (val, required) { | ||
if (!_.isUndefined(required) && required === true && _.isUndefined(val)) { | ||
throwInvalidParameter(name, 'is required'); | ||
throwErrorWithCode('REQUIRED', 'Is required'); | ||
} | ||
@@ -361,5 +423,4 @@ }; | ||
/** | ||
* Validates the request parameter's type and format (when necessary). | ||
* Validates the value type and format (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {*} val - The parameter value | ||
@@ -372,48 +433,49 @@ * @param {string} type - The parameter type | ||
*/ | ||
module.exports.validateTypeAndFormat = function validateTypeAndFormat (name, val, type, format, skipError) { | ||
var result = true; | ||
var validateTypeAndFormat = module.exports.validateTypeAndFormat = | ||
function validateTypeAndFormat (val, type, format, skipError) { | ||
var result = true; | ||
if (_.isArray(val)) { | ||
_.each(val, function (aVal, index) { | ||
if (!validateTypeAndFormat(name, aVal, type, format, true)) { | ||
throwInvalidParameter(name, 'at index ' + index + ' is not a valid ' + type + ': ' + aVal); | ||
} | ||
}); | ||
} else { | ||
switch (type) { | ||
case 'boolean': | ||
result = _.isBoolean(val) || ['false', 'true'].indexOf(val) !== -1; | ||
break; | ||
case 'integer': | ||
result = !_.isNaN(parseInt(val, 10)); | ||
break; | ||
case 'number': | ||
result = !_.isNaN(parseFloat(val)); | ||
break; | ||
case 'string': | ||
if (!_.isUndefined(format)) { | ||
switch (format) { | ||
case 'date': | ||
result = isValidDate(val); | ||
break; | ||
case 'date-time': | ||
result = isValidDateTime(val); | ||
break; | ||
if (_.isArray(val)) { | ||
_.each(val, function (aVal, index) { | ||
if (!validateTypeAndFormat(aVal, type, format, true)) { | ||
throwErrorWithCode('INVALID_TYPE', 'Value at index ' + index + ' is not a valid ' + type + ': ' + aVal); | ||
} | ||
}); | ||
} else { | ||
switch (type) { | ||
case 'boolean': | ||
result = _.isBoolean(val) || ['false', 'true'].indexOf(val) !== -1; | ||
break; | ||
case 'integer': | ||
result = !_.isNaN(parseInt(val, 10)); | ||
break; | ||
case 'number': | ||
result = !_.isNaN(parseFloat(val)); | ||
break; | ||
case 'string': | ||
if (!_.isUndefined(format)) { | ||
switch (format) { | ||
case 'date': | ||
result = isValidDate(val); | ||
break; | ||
case 'date-time': | ||
result = isValidDateTime(val); | ||
break; | ||
} | ||
} | ||
break; | ||
} | ||
break; | ||
} | ||
} | ||
if (skipError) { | ||
return result; | ||
} else if (!result) { | ||
throwInvalidParameter(name, 'is not a valid ' + (_.isUndefined(format) ? '' : format + ' ') + type + ': ' + val); | ||
} | ||
}; | ||
if (skipError) { | ||
return result; | ||
} else if (!result) { | ||
throwErrorWithCode('INVALID_TYPE', | ||
'Not a valid ' + (_.isUndefined(format) ? '' : format + ' ') + type + ': ' + val); | ||
} | ||
}; | ||
/** | ||
* Validates the request parameter's values are unique (when necessary). | ||
* Validates the value values are unique (when necessary). | ||
* | ||
* @param {string} name - The parameter name | ||
* @param {string[]} val - The parameter value | ||
@@ -424,6 +486,106 @@ * @param {boolean} isUnique - Whether or not the parameter values are unique | ||
*/ | ||
module.exports.validateUniqueItems = function validateUniqueItems (name, val, isUnique) { | ||
var validateUniqueItems = module.exports.validateUniqueItems = function validateUniqueItems (val, isUnique) { | ||
if (!_.isUndefined(isUnique) && _.uniq(val).length !== val.length) { | ||
throwInvalidParameter(name, 'does not allow duplicate values: ' + val.join(', ')); | ||
throwErrorWithCode('ARRAY_UNIQUE', 'Does not allow duplicate values: ' + val.join(', ')); | ||
} | ||
}; | ||
/** | ||
* Validates the value against the schema. | ||
* | ||
* @param {string} swaggerVersion - The Swagger version | ||
* @param {object} schema - The schema to use to validate things | ||
* @param {string[]} path - The path to the schema | ||
* @param {*} [val] - The value to validate or undefined to use the default value provided by the schema | ||
* | ||
* @throws Error if any validation failes | ||
*/ | ||
module.exports.validateSchemaConstraints = function validateSchemaConstraints (swaggerVersion, schema, path, val) { | ||
var resolveSchema = function resolveSchema (schema) { | ||
var resolved = schema; | ||
if (resolved.schema) { | ||
path = path.concat(['schema']); | ||
resolved = resolveSchema(resolved.schema); | ||
} | ||
return resolved; | ||
}; | ||
// Resolve the actual schema object | ||
schema = resolveSchema(schema); | ||
try { | ||
// Always perform this check even if there is no value | ||
if (schema.type === 'array') { | ||
validateArrayType(schema); | ||
} | ||
// Default to default value if necessary | ||
if (_.isUndefined(val)) { | ||
val = swaggerVersion === '1.2' ? schema.defaultValue : schema.default; | ||
path = path.concat([swaggerVersion === '1.2' ? 'defaultValue' : 'default']); | ||
} | ||
// If there is no explicit default value, return as all validations will fail | ||
if (_.isUndefined(val)) { | ||
return; | ||
} | ||
if (schema.type === 'array') { | ||
if (!_.isUndefined(schema.items)) { | ||
validateTypeAndFormat(val, schema.type === 'array' ? schema.items.type : schema.type, | ||
schema.type === 'array' && schema.items.format ? | ||
schema.items.format : | ||
schema.format); | ||
} else { | ||
validateTypeAndFormat(val, schema.type, schema.format); | ||
} | ||
} else { | ||
validateTypeAndFormat(val, schema.type, schema.format); | ||
} | ||
// Validate enum | ||
validateEnum(val, schema.enum); | ||
// Validate maximum | ||
validateMaximum(val, schema.maximum, schema.type, schema.exclusiveMaximum); | ||
// Validate maxItems (Swagger 2.0+) | ||
validateMaxItems(val, schema.maxItems); | ||
// Validate maxLength (Swagger 2.0+) | ||
validateMaxLength(val, schema.maxLength); | ||
// Validate maxProperties (Swagger 2.0+) | ||
validateMaxProperties(val, schema.maxProperties); | ||
// Validate minimum | ||
validateMinimum(val, schema.minimum, schema.type, schema.exclusiveMinimum); | ||
// Validate minItems | ||
validateMinItems(val, schema.minItems); | ||
// Validate minLength (Swagger 2.0+) | ||
validateMinLength(val, schema.minLength); | ||
// Validate minProperties (Swagger 2.0+) | ||
validateMinProperties(val, schema.minProperties); | ||
// Validate multipleOf (Swagger 2.0+) | ||
validateMultipleOf(val, schema.multipleOf); | ||
// Validate pattern (Swagger 2.0+) | ||
validatePattern(val, schema.pattern); | ||
// Validate uniqueItems | ||
validateUniqueItems(val, schema.uniqueItems); | ||
} catch (err) { | ||
err.path = path; | ||
throw err; | ||
} | ||
}; |
@@ -29,3 +29,2 @@ /* | ||
var helpers = require('../helpers'); | ||
var expressStylePath = helpers.expressStylePath; | ||
var parseurl = require('parseurl'); | ||
@@ -68,31 +67,37 @@ var pathToRegexp = require('path-to-regexp'); | ||
var apis = {}; | ||
var apiCache = {}; | ||
// Gather the apis, their path regex patterns and the corresponding operations | ||
_.each(resources, function (resource, index) { | ||
_.each(resource.apis, function (api) { | ||
_.each(resources, function (resource, resourceIndex) { | ||
_.each(resource.apis, function (api, apiIndex) { | ||
var expressPath = helpers.expressStylePath(resource.basePath, api.path); | ||
var keys = []; | ||
var re = pathToRegexp(expressStylePath(resource.basePath, api.path), keys); | ||
var reStr = re.toString(); | ||
var re = pathToRegexp(expressPath, keys); | ||
var cacheKey = re.toString(); | ||
if (Object.keys(apis).indexOf(reStr) !== -1) { | ||
throw new Error('Duplicate API path/pattern: ' + api.path); | ||
// This is an absolute path, use it as the cache key | ||
if (expressPath.indexOf('{') === -1) { | ||
cacheKey = expressPath; | ||
} | ||
apis[reStr] = { | ||
// For absolute paths, store it instead of its regex | ||
apiCache[cacheKey] = { | ||
api: api, | ||
apiDeclaration: resource, | ||
apiIndex: apiIndex, | ||
keys: keys, | ||
params: {}, | ||
re: re, | ||
resourceIndex: index, | ||
operations: {} | ||
operations: {}, | ||
resourceIndex: resourceIndex, | ||
resourceListing: resourceList | ||
}; | ||
_.each(api.operations, function (operation) { | ||
_.each(api.operations, function (operation, operationIndex) { | ||
var method = operation.method; | ||
if (!_.isUndefined(apis[reStr][method])) { | ||
throw new Error('Duplicate API operation (' + api.path + ') method: ' + method); | ||
} | ||
apis[reStr].operations[method] = operation; | ||
apiCache[cacheKey].operations[method] = { | ||
operation: operation, | ||
operationPath: ['apis', apiIndex.toString(), 'operations', operationIndex.toString()] | ||
}; | ||
}); | ||
@@ -104,78 +109,45 @@ }); | ||
var path = parseurl(req).pathname; | ||
var apiMetadata; | ||
var match; | ||
var api = _.find(apis, function (api) { | ||
match = api.re.exec(path); | ||
return _.isArray(match); | ||
}); | ||
var metadata = { | ||
api: api ? api.api : undefined, | ||
apiDeclaration: api ? resources[api.resourceIndex] : undefined, | ||
authorizations: resourceList.authorizations || {}, | ||
models: api ? resources[api.resourceIndex].models || {} : {}, | ||
operation: api ? api.operations[req.method] : undefined, | ||
params: {}, | ||
resourceListing: resourceList | ||
}; | ||
var metadata; | ||
// Attach Swagger metadata to the request | ||
if (!_.isUndefined(api)) { | ||
req.swagger = metadata; | ||
} | ||
try { | ||
apiMetadata = apiCache[path] || _.find(apiCache, function (metadata) { | ||
match = metadata.re.exec(path); | ||
return _.isArray(match); | ||
}); | ||
// Collect the parameter values | ||
if (!_.isUndefined(metadata.operation)) { | ||
try { | ||
_.each(metadata.operation.parameters, function (param) { | ||
var val; | ||
if (apiMetadata) { | ||
metadata = { | ||
api: apiMetadata.api, | ||
apiDeclaration: apiMetadata.apiDeclaration, | ||
apiIndex: apiMetadata.apiIndex, | ||
params: {}, | ||
resourceIndex: apiMetadata.resourceIndex, | ||
resourceListing: apiMetadata.resourceListing | ||
}; | ||
// Get the value to validate based on the operation parameter type | ||
switch (param.paramType) { | ||
case 'body': | ||
case 'form': | ||
if (!req.body) { | ||
throw new Error('Server configuration error: req.body is not defined but is required'); | ||
} | ||
if (_.isPlainObject(apiMetadata.operations[req.method])) { | ||
metadata.operation = apiMetadata.operations[req.method].operation; | ||
metadata.operationPath = apiMetadata.operations[req.method].operationPath; | ||
metadata.authorizations = metadata.operation.authorizations || apiMetadata.apiDeclaration.authorizations; | ||
} | ||
if (helpers.isModelParameter('1.2', param)) { | ||
val = req.body; | ||
} else { | ||
val = req.body[param.name]; | ||
} | ||
req.swagger = metadata; | ||
} | ||
break; | ||
case 'header': | ||
val = req.headers[param.name]; | ||
// Collect the parameter values | ||
if (metadata && metadata.operation) { | ||
_.each(metadata.operation.parameters, function (parameter, index) { | ||
var val = helpers.getParameterValue('1.2', parameter, apiMetadata.keys, match, req); | ||
break; | ||
case 'path': | ||
_.each(api.keys, function (key, index) { | ||
if (key.name === param.name) { | ||
val = match[index + 1]; | ||
} | ||
}); | ||
break; | ||
case 'query': | ||
if (!req.query) { | ||
throw new Error('Server configuration error: req.query is not defined but is required'); | ||
} | ||
val = req.query[param.name]; | ||
break; | ||
} | ||
// Use the default value when necessary | ||
if (_.isUndefined(val) && !_.isUndefined(param.defaultValue)) { | ||
val = param.defaultValue; | ||
} | ||
metadata.params[param.name] = { | ||
schema: param, | ||
metadata.params[parameter.name] = { | ||
path: metadata.operationPath.concat(['parameters', index.toString()]), | ||
schema: parameter, | ||
value: val | ||
}; | ||
}); | ||
} catch (err) { | ||
return next(err); | ||
} | ||
} catch (err) { | ||
return next(err); | ||
} | ||
@@ -182,0 +154,0 @@ |
@@ -29,7 +29,2 @@ /* | ||
var helpers = require('../helpers'); | ||
var createStubHandler = helpers.createStubHandler; | ||
var getHandlerName = helpers.getHandlerName; | ||
var handlerCacheFromDir = helpers.handlerCacheFromDir; | ||
var send405 = helpers.send405; | ||
var specVer = '1.2'; | ||
@@ -79,3 +74,3 @@ var defaultOptions = { | ||
// Create the handler cache from the modules in the controllers directory | ||
handlerCache = handlerCacheFromDir(options.controllers); | ||
handlerCache = helpers.handlerCacheFromDir(options.controllers); | ||
} | ||
@@ -93,9 +88,9 @@ | ||
if (_.isUndefined(operation)) { | ||
return send405(specVer, req, res, next); | ||
return helpers.send405('1.2', req, res, next); | ||
} else { | ||
handlerName = getHandlerName(specVer, req); | ||
handlerName = helpers.getHandlerName('1.2', req); | ||
handler = handlerCache[handlerName]; | ||
if (_.isUndefined(handler) && options.useStubs === true) { | ||
handler = handlerCache[handlerName] = createStubHandler(req, res, specVer); | ||
handler = handlerCache[handlerName] = helpers.createStubHandler('1.2', req, res, next, handlerName); | ||
} | ||
@@ -102,0 +97,0 @@ |
@@ -53,3 +53,2 @@ /* | ||
var apiDocsPaths = []; | ||
var rlApiPaths = []; | ||
var staticMiddleware = serveStatic(path.join(__dirname, '..', 'swagger-ui'), staticOptions); | ||
@@ -86,11 +85,2 @@ var apiDocsHandler = function apiDocsHandler (res, path) { | ||
// Create the apiPaths list | ||
_.each(resourceList.apis, function (api) { | ||
if (rlApiPaths.indexOf(api.path) > -1) { | ||
throw new Error('API path declared multiple times: ' + api.path); | ||
} | ||
rlApiPaths.push(api.path); | ||
}); | ||
// Add the Resource Listing to the response cache | ||
@@ -101,6 +91,2 @@ apiDocsCache[options.apiDocs] = JSON.stringify(resourceList, null, 2); | ||
_.each(resources, function (resource, resourcePath) { | ||
if (rlApiPaths.indexOf(resourcePath) === -1) { | ||
throw new Error('resource path is not defined in the resource listing: ' + resourcePath); | ||
} | ||
// Respond with pretty JSON (Configurable?) | ||
@@ -107,0 +93,0 @@ apiDocsCache[options.apiDocs + resourcePath] = JSON.stringify(resource, null, 2); |
@@ -28,5 +28,6 @@ /* | ||
var _ = require('lodash'); | ||
var async = require('async'); | ||
var helpers = require('../helpers'); | ||
var isModelParameter = helpers.isModelParameter; | ||
var send400 = helpers.send400; | ||
var spec = require('../../lib/helpers').getSpec('1.2'); | ||
var validators = require('../../lib/validators'); | ||
@@ -47,2 +48,6 @@ | ||
if (!_.isUndefined(operation)) { | ||
var paramIndex = 0; | ||
var paramName; // Here since we use it in the catch block | ||
var paramPath; // Here since we use it in the catch block | ||
// Validate the request | ||
@@ -53,48 +58,71 @@ try { | ||
_.each(operation.parameters || [], function (param) { | ||
var paramName = param.name; | ||
var val = req.swagger.params[paramName].value; | ||
async.map(operation.parameters, function (parameter, oCallback) { | ||
var isModel = helpers.isModelParameter('1.2', parameter); | ||
var val; | ||
paramName = parameter.name; | ||
paramPath = req.swagger.operationPath.concat(['params', paramIndex.toString()]); | ||
val = req.swagger.params[paramName].value; | ||
// Validate requiredness | ||
validators.validateRequiredness(paramName, val, param.required); | ||
validators.validateRequiredness(val, parameter.required); | ||
// Quick return if the value is not present | ||
if (_.isUndefined(val)) { | ||
return; | ||
return oCallback(); | ||
} | ||
if (isModelParameter('1.2', param)) { | ||
// Validate the model | ||
validators.validateModel(paramName, val, '1.2', req.swagger.apiDeclaration, | ||
param.type === 'array' && !_.isUndefined(param.items.$ref) ? | ||
param.items.$ref : | ||
param.type); | ||
} else { | ||
// Validate the value type/format | ||
validators.validateTypeAndFormat(paramName, val, | ||
param.type === 'array' ? param.items.type : param.type, | ||
param.type === 'array' && param.items.format ? | ||
param.items.format : | ||
param.format); | ||
validators.validateSchemaConstraints('1.2', parameter, paramPath, val); | ||
// Validate enum | ||
validators.validateEnum(paramName, val, param.enum); | ||
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'); | ||
// Validate maximum | ||
validators.validateMaximum(paramName, val, param.maximum, param.type); | ||
err.code = 'SCHEMA_VALIDATION_FAILED'; | ||
err.errors = results.errors; | ||
err.failedValidation = true; | ||
// Validate minimum | ||
validators.validateMinimum(paramName, val, param.minimum, param.type); | ||
return false; | ||
} | ||
}); | ||
} | ||
// Validate uniqueItems | ||
validators.validateUniqueItems(paramName, val, param.uniqueItems); | ||
oCallback(err); | ||
}); | ||
} else { | ||
oCallback(); | ||
} | ||
paramIndex++; | ||
}, function (err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
return next(); | ||
} | ||
}); | ||
} catch (err) { | ||
if (err.failedValidation === true) { | ||
if (!err.path) { | ||
err.path = paramPath; | ||
} | ||
err.paramName = paramName; | ||
} | ||
return send400(req, res, next, err); | ||
} | ||
} else { | ||
return next(); | ||
} | ||
return next(); | ||
}; | ||
}; |
@@ -32,3 +32,29 @@ /* | ||
var pathToRegexp = require('path-to-regexp'); | ||
var spec = require('../../lib/helpers').getSpec('2.0'); | ||
var composeParameters = function composeParameters (apiPath, method, path, operation) { | ||
var cParams = []; | ||
var seenParams = []; | ||
_.each(operation.parameters, function (parameter, index) { | ||
cParams.push({ | ||
path: apiPath.concat([method, 'parameters', index.toString()]), | ||
schema: parameter | ||
}); | ||
seenParams.push(parameter.name + ':' + parameter.in); | ||
}); | ||
_.each(path.parameters, function (parameter, index) { | ||
if (seenParams.indexOf(parameter.name + ':' + parameter.in) === -1) { | ||
cParams.push({ | ||
path: apiPath.concat(['parameters', index.toString()]), | ||
schema: parameter | ||
}); | ||
} | ||
}); | ||
return cParams; | ||
}; | ||
/** | ||
@@ -60,24 +86,42 @@ * Middleware for providing Swagger information to downstream middleware and request handlers. 'req.swagger' will be | ||
var paths = {}; | ||
var apiCache = {}; | ||
// Gather the paths, their path regex patterns and the corresponding operations | ||
_.each(swaggerObject.paths, function (path, pathName) { | ||
var keys = []; | ||
var re = pathToRegexp(expressStylePath(swaggerObject.basePath, pathName), keys); | ||
var reStr = re.toString(); | ||
// To avoid running into issues with references throughout the Swagger object we will use the resolved version. | ||
// Getting the resolved version is an asynchronous process but since initializeMiddleware caches the resolved document | ||
// this is a synchronous action at this point. | ||
spec.resolve(swaggerObject, function (err, resolved) { | ||
// Gather the paths, their path regex patterns and the corresponding operations | ||
_.each(resolved.paths, function (path, pathName) { | ||
var expressPath = expressStylePath(resolved.basePath, pathName); | ||
var keys = []; | ||
var re = pathToRegexp(expressPath, keys); | ||
var cacheKey = re.toString(); | ||
paths[reStr] = { | ||
apiPath: pathName, | ||
path: path, | ||
keys: keys, | ||
re: re, | ||
operations: {} | ||
}; | ||
// This is an absolute path, use it as the cache key | ||
if (expressPath.indexOf('{') === -1) { | ||
cacheKey = expressPath; | ||
} | ||
_.each(['get', 'put', 'post', 'delete', 'options', 'head', 'patch'], function (method) { | ||
var operation = path[method]; | ||
apiCache[cacheKey] = { | ||
apiPath: pathName, | ||
path: path, | ||
keys: keys, | ||
re: re, | ||
operations: {}, | ||
swaggerObject: { | ||
original: swaggerObject, | ||
resolved: resolved | ||
} | ||
}; | ||
if (!_.isUndefined(operation)) { | ||
paths[reStr].operations[method] = operation; | ||
} | ||
_.each(['get', 'put', 'post', 'delete', 'options', 'head', 'patch'], function (method) { | ||
var operation = path[method]; | ||
if (!_.isUndefined(operation)) { | ||
apiCache[cacheKey].operations[method] = { | ||
operation: operation, | ||
parameters: composeParameters(['paths', pathName], method, path, operation) | ||
}; | ||
} | ||
}); | ||
}); | ||
@@ -87,105 +131,45 @@ }); | ||
return function swaggerMetadata (req, res, next) { | ||
var rPath = parseurl(req).pathname; | ||
var path = parseurl(req).pathname; | ||
var match; | ||
var path = _.find(paths, function (path) { | ||
match = path.re.exec(rPath); | ||
return _.isArray(match); | ||
}); | ||
var metadata = { | ||
apiPath : path ? path.apiPath : undefined, | ||
path: path ? path.path : undefined, | ||
operation: path ? path.operations[req.method.toLowerCase()] : undefined, | ||
params: {}, | ||
swaggerObject: swaggerObject | ||
}; | ||
var metadata; | ||
var pathMetadata; | ||
// Attach Swagger metadata to the request | ||
if (!_.isUndefined(path)) { | ||
req.swagger = metadata; | ||
} | ||
try { | ||
pathMetadata = apiCache[path] || _.find(apiCache, function (metadata) { | ||
match = metadata.re.exec(path); | ||
return _.isArray(match); | ||
}); | ||
// Collect the parameter values | ||
if (!_.isUndefined(metadata.operation)) { | ||
try { | ||
// Until Swagger 2.0 documentation comes out, I'm going to assume that you cannot override "path" parameters | ||
// with operation parameters. That's why we start with the path parameters first and then the operation | ||
// parameters. (Note: "path" in this context is a path entry at #/paths in the Swagger Object) | ||
_.each(_.union(metadata.path.parameters, metadata.operation.parameters), function (param) { | ||
var paramPath = ['paths', path.apiPath]; | ||
var paramType = param.in; | ||
var findIndex = function (params, name) { | ||
var foundIndex; | ||
if (pathMetadata) { | ||
metadata = { | ||
apiPath : pathMetadata.apiPath, | ||
path: pathMetadata.path, | ||
params: {}, | ||
swaggerObject: pathMetadata.swaggerObject.resolved | ||
}; | ||
_.each(params, function (param, index) { | ||
if (param.in === paramType && param.name === name) { | ||
foundIndex = index; | ||
return false; | ||
} | ||
}); | ||
if (_.isPlainObject(pathMetadata.operations[req.method.toLowerCase()])) { | ||
metadata.operation = pathMetadata.operations[req.method.toLowerCase()].operation; | ||
metadata.operationParameters = pathMetadata.operations[req.method.toLowerCase()].parameters || []; | ||
metadata.security = metadata.operation.security || metadata.swaggerObject.security || []; | ||
} | ||
return foundIndex; | ||
}; | ||
var paramIndex = findIndex(metadata.path.parameters, param.name); | ||
var val; | ||
req.swagger = metadata; | ||
} | ||
// Get the value to validate based on the operation parameter type | ||
switch (paramType) { | ||
case 'body': | ||
case 'formData': | ||
if (!req.body) { | ||
throw new Error('Server configuration error: req.body is not defined but is required'); | ||
} | ||
// Collect the parameter values | ||
if (metadata && metadata.operation) { | ||
_.each(metadata.operationParameters, function (paramMetadata) { | ||
var parameter = paramMetadata.schema; | ||
var val = helpers.getParameterValue('2.0', parameter, pathMetadata.keys, match, req); | ||
if (helpers.isModelParameter('2.0', param)) { | ||
val = req.body; | ||
} else { | ||
val = req.body[param.name]; | ||
} | ||
break; | ||
case 'header': | ||
val = req.headers[param.name]; | ||
break; | ||
case 'path': | ||
_.each(path.keys, function (key, index) { | ||
if (key.name === param.name) { | ||
val = match[index + 1]; | ||
} | ||
}); | ||
break; | ||
case 'query': | ||
if (!req.query) { | ||
throw new Error('Server configuration error: req.query is not defined but is required'); | ||
} | ||
val = req.query[param.name]; | ||
break; | ||
} | ||
// Use the default value when necessary | ||
if (_.isUndefined(val) && !_.isUndefined(param.schema) && !_.isUndefined(param.schema.default)) { | ||
val = param.schema.default; | ||
} | ||
// Figure out the parameter path | ||
if (_.isUndefined(paramIndex)) { | ||
paramPath.push(req.method.toLowerCase()); | ||
paramIndex = findIndex(metadata.operation.parameters, param.name); | ||
} | ||
paramPath.push('parameters', paramIndex); | ||
metadata.params[param.name] = { | ||
path: paramPath, | ||
schema: param, | ||
metadata.params[parameter.name] = { | ||
path: paramMetadata.path, | ||
schema: parameter, | ||
value: val | ||
}; | ||
}); | ||
} catch (err) { | ||
return next(err); | ||
} | ||
} catch (err) { | ||
return next(err); | ||
} | ||
@@ -192,0 +176,0 @@ |
@@ -29,7 +29,2 @@ /* | ||
var helpers = require('../helpers'); | ||
var createStubHandler = helpers.createStubHandler; | ||
var getHandlerName = helpers.getHandlerName; | ||
var handlerCacheFromDir = helpers.handlerCacheFromDir; | ||
var send405 = helpers.send405; | ||
var specVer = '2.0'; | ||
@@ -83,3 +78,3 @@ var defaultOptions = { | ||
// Create the handler cache from the modules in the controllers directory | ||
handlerCache = handlerCacheFromDir(options.controllers); | ||
handlerCache = helpers.handlerCacheFromDir(options.controllers); | ||
} | ||
@@ -90,3 +85,2 @@ | ||
var handlerName; | ||
var responseModel; | ||
var operation; | ||
@@ -99,19 +93,9 @@ | ||
if (_.isUndefined(operation)) { | ||
return send405(specVer, req, res, next); | ||
return helpers.send405('2.0', req, res, next); | ||
} else { | ||
handlerName = getHandlerName(specVer, req); | ||
handlerName = helpers.getHandlerName('2.0', req); | ||
handler = handlerCache[handlerName]; | ||
if (_.isUndefined(handler) && options.useStubs === true) { | ||
responseModel = _.find(operation.responses, function (responseModel, responseCode) { | ||
if (responseCode === '200') { | ||
return responseModel.responseModel; | ||
} | ||
}); | ||
if (_.isUndefined(responseModel)) { | ||
responseModel = operation.responses.default; | ||
} | ||
handler = handlerCache[handlerName] = createStubHandler(req, res, specVer, handlerName, responseModel); | ||
handler = handlerCache[handlerName] = helpers.createStubHandler('2.0', req, res, next, handlerName); | ||
} | ||
@@ -118,0 +102,0 @@ |
@@ -29,3 +29,3 @@ /* | ||
function handleSecurityError(err, res) { | ||
function handleSecurityError (err, res) { | ||
var body = { | ||
@@ -36,2 +36,3 @@ 'error_description': err.message, | ||
}; | ||
if (err.headers) { | ||
@@ -42,2 +43,3 @@ _.each(_.keys(err.headers), function(name) { | ||
} | ||
res.statusCode = err.statusCode || 403; | ||
@@ -72,38 +74,33 @@ res.end(JSON.stringify(body)); | ||
*/ | ||
exports = module.exports = function swaggerSecurityMiddleware(options) { | ||
exports = module.exports = function swaggerSecurityMiddleware (options) { | ||
var handlers = options || {}; | ||
return function swaggerSecurity(req, res, next) { | ||
return function swaggerSecurity (req, res, next) { | ||
if (!req.swagger || !req.swagger.operation) { return next(); } | ||
if (!req.swagger) { return next(); } | ||
var securityReqs = req.swagger.operation.security || req.swagger.swaggerObject.security; | ||
var securityReqs = req.swagger.operation.security || req.swagger.swaggerObject.security; | ||
if (!securityReqs) { return next(); } | ||
async.map(securityReqs, function(secReq, cb) { // logical OR - any one can allow | ||
async.map(Object.keys(secReq), function(name, cb) { // logical AND - all must allow | ||
var secDef = req.swagger.swaggerObject.securityDefinitions[name]; | ||
if (!secDef) { return cb(new Error('unknown security definition: ' + name)); } | ||
var handler = handlers[name]; | ||
var handler = handlers[name]; | ||
if (!handler) { return cb(new Error('unknown security handler: ' + name)); } | ||
handler(req, secDef, secReq[name], cb); | ||
}, | ||
function(err) { | ||
// swap normal err and result to short-circuit the logical OR | ||
if (err) { return cb(undefined, err); } | ||
cb(new Error('OK')); | ||
} | ||
); | ||
}, | ||
function(ok, errors) { // note swapped results | ||
if (ok && ok.message === 'OK') { return next(); } | ||
handleSecurityError(errors[0], res); | ||
} | ||
); | ||
}, function (err) { | ||
// swap normal err and result to short-circuit the logical OR | ||
if (err) { return cb(undefined, err); } | ||
cb(new Error('OK')); | ||
}); | ||
}, function (ok, errors) { // note swapped results | ||
if (ok && ok.message === 'OK') { return next(); } | ||
handleSecurityError(errors[0], res); | ||
}); | ||
}; | ||
}; |
@@ -28,5 +28,4 @@ /* | ||
var _ = require('lodash'); | ||
var async = require('async'); | ||
var helpers = require('../helpers'); | ||
var isModelParameter = helpers.isModelParameter; | ||
var toJsonPointer = require('../../lib/helpers').toJsonPointer; | ||
var send400 = helpers.send400; | ||
@@ -48,2 +47,5 @@ var validators = require('../../lib/validators'); | ||
if (!_.isUndefined(operation)) { | ||
var paramName; // Here since we use it in the catch block | ||
var paramPath; // Here since we use it in the catch block | ||
// Validate the request | ||
@@ -54,73 +56,58 @@ try { | ||
_.each(_.union(req.swagger.path.parameters, operation.parameters), function (param) { | ||
var paramName = param.name; | ||
var paramPath = req.swagger.params[paramName].path; | ||
var val = req.swagger.params[paramName].value; | ||
async.map(req.swagger.operationParameters, function (paramMetadata, oCallback) { | ||
var parameter = paramMetadata.schema; | ||
var isModel = helpers.isModelParameter('2.0', parameter); | ||
var val; | ||
paramName = parameter.name; | ||
paramPath = paramMetadata.path; | ||
val = req.swagger.params[paramName].value; | ||
// Validate requiredness | ||
validators.validateRequiredness(paramName, val, param.required); | ||
validators.validateRequiredness(val, parameter.required); | ||
// Quick return if the value is not present | ||
if (_.isUndefined(val)) { | ||
return; | ||
return oCallback(); | ||
} | ||
if (isModelParameter('2.0', param)) { | ||
if (param.schema) { | ||
paramPath.push('schema'); | ||
} | ||
validators.validateSchemaConstraints('2.0', parameter, paramPath, val); | ||
// Validate the model | ||
validators.validateModel(paramName, val, '2.0', req.swagger.swaggerObject, | ||
_.isUndefined(param.schema.$ref) ? | ||
toJsonPointer(paramPath) : | ||
param.schema.$ref); | ||
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 { | ||
// Constraints can appear in the parameter itself (type/format) and in the parameter's schema (if available) | ||
if (param.schema) { | ||
param = param.schema; | ||
} | ||
// Validate the value type/format | ||
validators.validateTypeAndFormat(paramName, val, | ||
param.type === 'array' ? param.items.type : param.type, | ||
param.type === 'array' && param.items.format ? | ||
param.items.format : | ||
param.format); | ||
// Validate enum | ||
validators.validateEnum(paramName, val, param.enum); | ||
// Validate maximum | ||
validators.validateMaximum(paramName, val, param.maximum, param.type, param.exclusiveMaximum); | ||
// Validate maximum items | ||
validators.validateMaxItems(paramName, val, param.maxItems); | ||
// Validate maximum length | ||
validators.validateMaxLength(paramName, val, param.maxLength); | ||
// Validate minimum | ||
validators.validateMinimum(paramName, val, param.minimum, param.type, param.exclusiveMinimum); | ||
// Validate minimum items | ||
validators.validateMinItems(paramName, val, param.minItems); | ||
// Validate minimum length | ||
validators.validateMinLength(paramName, val, param.minLength); | ||
// Validate pattern | ||
validators.validatePattern(paramName, val, param.pattern); | ||
// Validate uniqueItems | ||
validators.validateUniqueItems(paramName, val, param.uniqueItems); | ||
oCallback(); | ||
} | ||
}, function (err) { | ||
if (err) { | ||
throw err; | ||
} else { | ||
return next(); | ||
} | ||
}); | ||
} catch (err) { | ||
if (err.failedValidation === true) { | ||
if (!err.path) { | ||
err.path = paramPath; | ||
} | ||
err.paramName = paramName; | ||
} | ||
return send400(req, res, next, err); | ||
} | ||
} else { | ||
return next(); | ||
} | ||
return next(); | ||
}; | ||
}; |
@@ -43,2 +43,6 @@ /* | ||
var isModelType = function isModelType (spec, type) { | ||
return spec.primitives.indexOf(type) === -1; | ||
}; | ||
/** | ||
@@ -74,3 +78,3 @@ * Returns an Express style path for the Swagger path. | ||
var getHandlerName = module.exports.getHandlerName = function getHandlerName (version, req) { | ||
module.exports.getHandlerName = function getHandlerName (version, req) { | ||
var handlerName; | ||
@@ -98,2 +102,6 @@ | ||
if (!schema.type) { | ||
schema.type = 'object'; | ||
} | ||
switch (schema.type) { | ||
@@ -150,2 +158,8 @@ case 'array': | ||
_.each(schema.allOf, function (parentSchema) { | ||
_.each(parentSchema.properties, function (property, propName) { | ||
value[propName] = getMockValue(version, property); | ||
}); | ||
}); | ||
_.each(schema.properties, function (property, propName) { | ||
@@ -196,12 +210,16 @@ value[propName] = getMockValue(version, property); | ||
var mockResponse = function mockResponse (version, req) { | ||
var mockResponse = function mockResponse (version, req, res, next, handlerName) { | ||
var method = req.method.toLowerCase(); | ||
var operation = req.swagger.operation; | ||
var stubResponse = 'Stubbed response for ' + getHandlerName(version, req); | ||
var sendResponse = function sendResponse (err, response) { | ||
if (err) { | ||
return next(err); | ||
} else { | ||
return res.end(response); | ||
} | ||
}; | ||
var spec = helpers.getSpec(version); | ||
var stubResponse = 'Stubbed response for ' + handlerName; | ||
var apiDOrSO; | ||
var composedModel; | ||
var response; | ||
var responseCode; // (2.0) | ||
var responseType; | ||
var spec = helpers.getSpec(version); | ||
@@ -213,6 +231,2 @@ switch (version) { | ||
if (spec.primitives.indexOf(operation.type) === -1) { | ||
responseType = operation.type; | ||
} | ||
break; | ||
@@ -223,51 +237,35 @@ | ||
if (method === 'post' && _.isPlainObject(operation.responses['201'])) { | ||
responseCode = '201'; | ||
} else if (_.isPlainObject(operation.responses['200'])) { | ||
responseCode = '200'; | ||
} else if (_.isPlainObject(operation.responses.default)) { | ||
responseCode = 'default'; | ||
if (method === 'post' && operation.responses['201']) { | ||
responseType = operation.responses['201'].schema; | ||
} else if (operation.responses['200']) { | ||
responseType = operation.responses['200']; | ||
} else if (operation.responses['default']) { | ||
responseType = operation.responses['default']; | ||
} else if (operation.schema) { | ||
responseType = operation.schema.type || 'object'; | ||
} else { | ||
responseType = operation.type; | ||
} | ||
if (!_.isUndefined(responseCode)) { | ||
responseType = operation.responses[responseCode]; | ||
} | ||
if (_.isPlainObject(responseType)) { | ||
if (_.isUndefined(responseType.schema.$ref)) { | ||
responseType = helpers.toJsonPointer(['paths', req.swagger.apiPath, method, 'responses', responseCode, | ||
'schema']); | ||
} else { | ||
responseType = helpers.refToJsonPointer(responseType.schema.$ref); | ||
} | ||
} | ||
break; | ||
} | ||
if (_.isUndefined(responseType)) { | ||
// Should never happen but handle it safely | ||
response = stubResponse; | ||
} else if (spec.primitives.indexOf(responseType) === -1) { | ||
// This is a model | ||
try { | ||
composedModel = spec.composeModel(apiDOrSO, responseType); | ||
} catch (err) { | ||
response = JSON.stringify({ | ||
message: err.message, | ||
stack: err.stack | ||
if (_.isPlainObject(responseType) || isModelType(spec, responseType)) { | ||
if (version === '1.2') { | ||
spec.composeModel(apiDOrSO, responseType, function (err, result) { | ||
if (err) { | ||
return sendResponse(undefined, err); | ||
} else { | ||
// Should we handle this differently as undefined typically means the model doesn't exist | ||
return sendResponse(undefined, _.isUndefined(result) ? | ||
stubResponse : | ||
JSON.stringify(getMockValue(version, result))); | ||
} | ||
}); | ||
} | ||
if (_.isUndefined(composedModel)) { | ||
response = stubResponse; | ||
} else { | ||
response = JSON.stringify(getMockValue(version, composedModel)); | ||
return sendResponse(undefined, JSON.stringify(getMockValue(version, responseType.schema))); | ||
} | ||
} else { | ||
// This is a primitive (Only possible in 1.2) | ||
response = getMockValue(version, operation); | ||
return sendResponse(undefined, getMockValue(version, responseType)); | ||
} | ||
return response; | ||
}; | ||
@@ -312,3 +310,3 @@ | ||
module.exports.createStubHandler = function createStubHandler (req, res, version) { | ||
module.exports.createStubHandler = function createStubHandler (version, req, res, next, handlerName) { | ||
// TODO: Handle headers for 2.0 | ||
@@ -318,9 +316,8 @@ // TODO: Handle examples (per mime-type) for 2.0 | ||
return function stubHandler (req, res) { | ||
res.end(mockResponse(version, req)); | ||
// res.end('Stubbed response for ' + getHandlerName(version, req)); | ||
return function stubHandler () { | ||
mockResponse(version, req, res, next, handlerName); | ||
}; | ||
}; | ||
module.exports.isModelParameter = function isModelParameter (version, param) { | ||
var isModelParameter = module.exports.isModelParameter = function isModelParameter (version, param) { | ||
var spec = helpers.getSpec(version); | ||
@@ -331,11 +328,14 @@ var isModel = false; | ||
case '1.2': | ||
if (!_.isUndefined(param.type) && spec.primitives.indexOf(param.type) === -1) { | ||
if (!_.isUndefined(spec, param.type) && isModelType(spec, param.type)) { | ||
isModel = true; | ||
} else if (param.type === 'array' && !_.isUndefined(param.items.$ref)) { | ||
} 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') { | ||
if (param.type === 'object' || !param.type) { | ||
isModel = true; | ||
@@ -346,3 +346,3 @@ } else if (!_.isUndefined(param.schema) && (param.schema.type === 'object' || !_.isUndefined(param.schema.$ref))) { | ||
// 2.0 does not allow arrays of models | ||
// 2.0 does not allow arrays of models in the same way Swagger 1.2 does | ||
@@ -355,5 +355,98 @@ break; | ||
module.exports.getParameterValue = function getParameterValue (version, parameter, pathKeys, match, req) { | ||
var defaultVal = version === '1.2' ? parameter.defaultValue : parameter.default; | ||
var paramType = version === '1.2' ? parameter.paramType : parameter.in; | ||
var val; | ||
// Get the value to validate based on the operation parameter type | ||
switch (paramType) { | ||
case 'body': | ||
case 'form': | ||
if (!req.body) { | ||
throw new Error('Server configuration error: req.body is not defined but is required'); | ||
} | ||
if (isModelParameter(version, parameter)) { | ||
val = req.body; | ||
} else { | ||
val = req.body[parameter.name]; | ||
} | ||
break; | ||
case 'header': | ||
val = req.headers[parameter.name.toLowerCase()]; | ||
break; | ||
case 'path': | ||
_.each(pathKeys, function (key, index) { | ||
if (key.name === parameter.name) { | ||
val = match[index + 1]; | ||
} | ||
}); | ||
break; | ||
case 'query': | ||
if (!req.query) { | ||
throw new Error('Server configuration error: req.query is not defined but is required'); | ||
} | ||
val = req.query[parameter.name]; | ||
break; | ||
} | ||
// Use the default value when necessary | ||
if (_.isUndefined(val) && !_.isUndefined(defaultVal)) { | ||
val = defaultVal; | ||
} | ||
return val; | ||
}; | ||
module.exports.send400 = function send400 (req, res, next, err) { | ||
var validationMessage; | ||
res.statusCode = 400; | ||
// Format the errors to include the parameter information | ||
if (err.failedValidation === true) { | ||
validationMessage = 'Parameter (' + err.paramName + ') '; | ||
switch (err.code) { | ||
case 'ENUM_MISMATCH': | ||
case 'MAXIMUM': | ||
case 'MAXIMUM_EXCLUSIVE': | ||
case 'MINIMUM': | ||
case 'MINIMUM_EXCLUSIVE': | ||
case 'MULTIPLE_OF': | ||
case 'INVALID_TYPE': | ||
if (err.code === 'INVALID_TYPE' && err.message.split(' ')[0] === 'Value') { | ||
validationMessage += err.message.split(' ').slice(1).join(' '); | ||
} else { | ||
validationMessage += 'is ' + err.message.charAt(0).toLowerCase() + err.message.substring(1); | ||
} | ||
break; | ||
case 'ARRAY_LENGTH_LONG': | ||
case 'ARRAY_LENGTH_SHORT': | ||
case 'MAX_LENGTH': | ||
case 'MIN_LENGTH': | ||
validationMessage += err.message.split(' ').slice(1).join(' '); | ||
break; | ||
case 'MAX_PROPERTIES': | ||
case 'MIN_PROPERTIES': | ||
validationMessage += 'properties are ' + err.message.split(' ').slice(4).join(' '); | ||
break; | ||
default: | ||
validationMessage += err.message.charAt(0).toLowerCase() + err.message.substring(1); | ||
} | ||
err.message = validationMessage; | ||
} | ||
return next(err); | ||
@@ -360,0 +453,0 @@ }; |
// swagger-client.js | ||
// version 2.1.0-alpha.2 | ||
// version 2.1.0-alpha.4 | ||
/** | ||
@@ -90,11 +90,16 @@ * Array Model | ||
else { | ||
for(name in authorizations) { | ||
for (key in this.authz) { | ||
if(key == name) { | ||
value = this.authz[key]; | ||
result = value.apply(obj, authorizations); | ||
if (result === true) | ||
status = true; | ||
if(Array.isArray(authorizations)) { | ||
var i; | ||
for(i = 0; i < authorizations.length; i++) { | ||
var auth = authorizations[i]; | ||
log(auth); | ||
for (key in this.authz) { | ||
var value = this.authz[key]; | ||
if(typeof value !== 'undefined') { | ||
result = value.apply(obj, authorizations); | ||
if (result === true) | ||
status = true; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -386,4 +391,7 @@ } | ||
this.produces = response.produces; | ||
this.authSchemes = response.authorizations; | ||
this.securityDefinitions = response.securityDefinitions; | ||
// legacy support | ||
this.authSchemes = response.securityDefinitions; | ||
var location = this.parseUri(this.url); | ||
@@ -420,2 +428,5 @@ if(typeof this.schemes === 'undefined' || this.schemes.length === 0) { | ||
for(httpMethod in response.paths[path]) { | ||
if(['delete', 'get', 'head', 'options', 'patch', 'post', 'put'].indexOf(httpMethod) === -1) { | ||
continue; | ||
} | ||
var operation = response.paths[path][httpMethod]; | ||
@@ -508,3 +519,7 @@ var tags = operation.tags; | ||
else { | ||
return path.substring(1).replace(/\//g, "_").replace(/\{/g, "").replace(/\}/g, "") + "_" + httpMethod; | ||
return path.substring(1) | ||
.replace(/\//g, "_") | ||
.replace(/\{/g, "") | ||
.replace(/\}/g, "") | ||
.replace(/\./g, "_") + "_" + httpMethod; | ||
} | ||
@@ -547,2 +562,3 @@ } | ||
this.security = args.security; | ||
this.authorizations = args.security; | ||
this.description = args.description; | ||
@@ -558,3 +574,3 @@ | ||
var innerType = this.getType(param); | ||
if(innerType.toString().toLowerCase() === 'boolean') { | ||
if(innerType && innerType.toString().toLowerCase() === 'boolean') { | ||
param.allowableValues = {}; | ||
@@ -655,4 +671,4 @@ param.isList = true; | ||
str = 'long'; | ||
else if(type === 'integer' && typeof format === 'undefined') | ||
str = 'long'; | ||
else if(type === 'integer') | ||
str = 'integer' | ||
else if(type === 'string' && format === 'date-time') | ||
@@ -666,3 +682,3 @@ str = 'date-time'; | ||
str = 'double'; | ||
else if(type === 'number' && typeof format === 'undefined') | ||
else if(type === 'number') | ||
str = 'double'; | ||
@@ -839,3 +855,3 @@ else if(type === 'boolean') | ||
} | ||
else if (param.in === 'query') { | ||
else if (param.in === 'query' && typeof args[param.name] !== 'undefined') { | ||
if(querystring === '') | ||
@@ -878,4 +894,9 @@ querystring += '?'; | ||
} | ||
var url = this.scheme + '://' + this.host + this.basePath + requestUrl + querystring; | ||
var url = this.scheme + '://' + this.host; | ||
if(this.basePath !== '/') | ||
url += this.basePath; | ||
url += requestUrl + querystring; | ||
var obj = { | ||
@@ -928,3 +949,3 @@ url: url, | ||
// if there's a body, need to set the accepts header via requestContentType | ||
if (body && (this.type === 'post' || this.type === 'put' || this.type === 'patch' || this.type === 'delete')) { | ||
if (body && (this.method === 'post' || this.method === 'put' || this.method === 'patch' || this.method === 'delete')) { | ||
if (opts.requestContentType) | ||
@@ -1105,10 +1126,7 @@ consumes = opts.requestContentType; | ||
this.required = required; | ||
if(obj['$ref']) { | ||
var refType = obj['$ref']; | ||
refType = refType.indexOf('#/definitions') === -1 ? refType : refType.substring('#/definitions').length; | ||
this['$ref'] = refType; | ||
} | ||
if(obj['$ref']) | ||
this['$ref'] = simpleRef(obj['$ref']); | ||
else if (obj.type === 'array') { | ||
if(obj.items['$ref']) | ||
this['$ref'] = obj.items['$ref']; | ||
this['$ref'] = simpleRef(obj.items['$ref']); | ||
else | ||
@@ -1144,3 +1162,4 @@ obj = obj.items; | ||
if(this['$ref']) { | ||
var refModel = models[this['$ref']]; | ||
var refModelName = simpleRef(this['$ref']); | ||
var refModel = models[refModelName]; | ||
if(refModel && typeof ignoredModels[type] === 'undefined') { | ||
@@ -1204,4 +1223,6 @@ ignoredModels[type] = this; | ||
str += 'boolean'; | ||
else if(obj['$ref']) | ||
str += simpleRef(obj['$ref']); | ||
else | ||
str += obj.type || obj['$ref']; | ||
str += obj.type; | ||
if(obj.type === 'array') | ||
@@ -1213,2 +1234,4 @@ str += ']'; | ||
simpleRef = function(name) { | ||
if(typeof name === 'undefined') | ||
return null; | ||
if(name.indexOf("#/definitions/") === 0) | ||
@@ -1345,3 +1368,3 @@ return name.substring('#/definitions/'.length) | ||
var headers = {}, | ||
headerArray = response.getAllResponseHeaders().split("\n"); | ||
headerArray = response.getAllResponseHeaders().split("\n"); | ||
@@ -1359,3 +1382,3 @@ for(var i = 0; i < headerArray.length; i++) { | ||
var name = toSplit.substring(0, separator).trim(), | ||
value = toSplit.substring(separator + 1).trim(); | ||
value = toSplit.substring(separator + 1).trim(); | ||
headers[name] = value; | ||
@@ -1376,4 +1399,11 @@ } | ||
if(contentType.indexOf("application/json") == 0 || contentType.indexOf("+json") > 0) { | ||
if(response.responseText && response.responseText !== "") | ||
out.obj = JSON.parse(response.responseText); | ||
if(response.responseText && response.responseText !== "") { | ||
try { | ||
out.obj = JSON.parse(response.content.data); | ||
} | ||
catch (ex) { | ||
// do not set out.obj | ||
log ("unable to parse JSON content"); | ||
} | ||
} | ||
else | ||
@@ -1380,0 +1410,0 @@ out.obj = {} |
@@ -10,6 +10,25 @@ var appName; | ||
if(window.swaggerUi.api.authSchemes | ||
&& window.swaggerUi.api.authSchemes.oauth2 | ||
&& window.swaggerUi.api.authSchemes.oauth2.scopes) { | ||
scopes = window.swaggerUi.api.authSchemes.oauth2.scopes; | ||
var auths = window.swaggerUi.api.authSchemes || window.swaggerUi.api.securityDefinitions; | ||
if(auths) { | ||
var key; | ||
var defs = auths; | ||
for(key in defs) { | ||
var auth = defs[key]; | ||
if(auth.type === 'oauth2' && auth.scopes) { | ||
var scope; | ||
if(Array.isArray(auth.scopes)) { | ||
// 1.2 support | ||
var i; | ||
for(i = 0; i < auth.scopes.length; i++) { | ||
scopes.push(auth.scopes[i]); | ||
} | ||
} | ||
else { | ||
// 2.0 support | ||
for(scope in auth.scopes) { | ||
scopes.push({scope: scope, description: auth.scopes[scope]}); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -22,32 +41,28 @@ | ||
if(popupDialog.length > 0) | ||
popupDialog = popupDialog.last(); | ||
else { | ||
popupDialog = $( | ||
[ | ||
'<div class="api-popup-dialog">', | ||
'<div class="api-popup-title">Select OAuth2.0 Scopes</div>', | ||
'<div class="api-popup-content">', | ||
'<p>Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.', | ||
'<a href="#">Learn how to use</a>', | ||
'</p>', | ||
'<p><strong>' + appName + '</strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>', | ||
'<ul class="api-popup-scopes">', | ||
'</ul>', | ||
'<p class="error-msg"></p>', | ||
'<div class="api-popup-actions"><button class="api-popup-authbtn api-button green" type="button">Authorize</button><button class="api-popup-cancel api-button gray" type="button">Cancel</button></div>', | ||
'</div>', | ||
'</div>'].join('')); | ||
$(document.body).append(popupDialog); | ||
popupDialog = $( | ||
[ | ||
'<div class="api-popup-dialog">', | ||
'<div class="api-popup-title">Select OAuth2.0 Scopes</div>', | ||
'<div class="api-popup-content">', | ||
'<p>Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.', | ||
'<a href="#">Learn how to use</a>', | ||
'</p>', | ||
'<p><strong>' + appName + '</strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>', | ||
'<ul class="api-popup-scopes">', | ||
'</ul>', | ||
'<p class="error-msg"></p>', | ||
'<div class="api-popup-actions"><button class="api-popup-authbtn api-button green" type="button">Authorize</button><button class="api-popup-cancel api-button gray" type="button">Cancel</button></div>', | ||
'</div>', | ||
'</div>'].join('')); | ||
$(document.body).append(popupDialog); | ||
popup = popupDialog.find('ul.api-popup-scopes').empty(); | ||
for (i = 0; i < scopes.length; i ++) { | ||
scope = scopes[i]; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope; | ||
if (scope.description) { | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
} | ||
str += '</label></li>'; | ||
popup.append(str); | ||
popup = popupDialog.find('ul.api-popup-scopes').empty(); | ||
for (i = 0; i < scopes.length; i ++) { | ||
scope = scopes[i]; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope; | ||
if (scope.description) { | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
} | ||
str += '</label></li>'; | ||
popup.append(str); | ||
} | ||
@@ -72,3 +87,6 @@ | ||
popupDialog.hide(); | ||
popupDialog.empty(); | ||
popupDialog = []; | ||
}); | ||
popupDialog.find('button.api-popup-authbtn').click(function() { | ||
@@ -81,3 +99,3 @@ popupMask.hide(); | ||
var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); | ||
var redirectUrl = host.protocol + '//' + host.host + pathname + "/o2c.html"; | ||
var redirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; | ||
var url = null; | ||
@@ -87,8 +105,17 @@ | ||
if (authSchemes.hasOwnProperty(key)) { | ||
var o = authSchemes[key].grantTypes; | ||
for(var t in o) { | ||
if(o.hasOwnProperty(t) && t === 'implicit') { | ||
var dets = o[t]; | ||
url = dets.loginEndpoint.url + "?response_type=token"; | ||
window.swaggerUi.tokenName = dets.tokenName; | ||
if(authSchemes[key].type === 'oauth2' && authSchemes[key].flow === 'implicit') { | ||
var dets = authSchemes[key]; | ||
url = dets.authorizationUrl + '?response_type=token'; | ||
window.swaggerUi.tokenName = dets.tokenUrl || 'access_token'; | ||
} | ||
else if(authSchemes[key].grantTypes) { | ||
// 1.2 support | ||
var o = authSchemes[key].grantTypes; | ||
for(var t in o) { | ||
if(o.hasOwnProperty(t) && t === 'implicit') { | ||
var dets = o[t]; | ||
var ep = dets.loginEndpoint.url; | ||
url = dets.loginEndpoint.url + '?response_type=token'; | ||
window.swaggerUi.tokenName = dets.tokenName; | ||
} | ||
} | ||
@@ -102,3 +129,3 @@ } | ||
for(k =0; k < o.length; k++) { | ||
scopes.push($(o[k]).attr("scope")); | ||
scopes.push($(o[k]).attr('scope')); | ||
} | ||
@@ -139,10 +166,10 @@ | ||
appName = (o.appName||errors.push("missing appName")); | ||
appName = (o.appName||errors.push('missing appName')); | ||
popupMask = (o.popupMask||$('#api-common-mask')); | ||
popupDialog = (o.popupDialog||$('.api-popup-dialog')); | ||
clientId = (o.clientId||errors.push("missing client id")); | ||
realm = (o.realm||errors.push("missing realm")); | ||
clientId = (o.clientId||errors.push('missing client id')); | ||
realm = (o.realm||errors.push('missing realm')); | ||
if(errors.length > 0){ | ||
log("auth unable initialize oauth: " + errors); | ||
log('auth unable initialize oauth: ' + errors); | ||
return; | ||
@@ -213,4 +240,3 @@ } | ||
}); | ||
window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header")); | ||
window.authorizations.add('oauth2', new ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); | ||
} | ||
@@ -217,0 +243,0 @@ } |
// swagger.js | ||
// version 2.0.41 | ||
// version 2.0.47 | ||
@@ -142,3 +142,3 @@ (function () { | ||
headers: { | ||
accept: "application/json,application/json;charset=\"utf-8\",*/*" | ||
accept: "application/json,application/json;charset=utf-8,*/*" | ||
}, | ||
@@ -377,3 +377,3 @@ on: { | ||
headers: { | ||
accept: "application/json,application/json;charset=\"utf-8\",*/*" | ||
accept: "application/json,application/json;charset=utf-8,*/*" | ||
}, | ||
@@ -503,3 +503,3 @@ on: { | ||
o.nickname = this.sanitize(o.nickname); | ||
var op = new SwaggerOperation(o.nickname, resource_path, method, o.parameters, o.summary, o.notes, type, responseMessages, this, consumes, produces, o.authorizations); | ||
var op = new SwaggerOperation(o.nickname, resource_path, method, o.parameters, o.summary, o.notes, type, responseMessages, this, consumes, produces, o.authorizations, o.deprecated); | ||
this.operations[op.nickname] = op; | ||
@@ -697,3 +697,3 @@ output.push(this.operationsArray.push(op)); | ||
var SwaggerOperation = function (nickname, path, method, parameters, summary, notes, type, responseMessages, resource, consumes, produces, authorizations) { | ||
var SwaggerOperation = function (nickname, path, method, parameters, summary, notes, type, responseMessages, resource, consumes, produces, authorizations, deprecated) { | ||
var _this = this; | ||
@@ -714,2 +714,3 @@ | ||
this.authorizations = authorizations; | ||
this.deprecated = deprecated; | ||
this["do"] = __bind(this["do"], this); | ||
@@ -746,3 +747,3 @@ | ||
if (type.toLowerCase() === 'boolean') { | ||
if (type && type.toLowerCase() === 'boolean') { | ||
param.allowableValues = {}; | ||
@@ -913,2 +914,8 @@ param.allowableValues.values = ["true", "false"]; | ||
possibleParams.push(param); | ||
else if (param.paramType === 'body' && param.name !== 'body') { | ||
if (args.body) { | ||
throw new Error("Saw two body params in an API listing; expecting a max of one."); | ||
} | ||
args.body = args[param.name]; | ||
} | ||
} | ||
@@ -971,3 +978,3 @@ | ||
// apply path params and remove from args | ||
var reg = new RegExp('\\{\\s*?' + param.name + '.*?\\}(?=\\s*?(\\/|$))', 'gi'); | ||
var reg = new RegExp('\\{\\s*?' + param.name + '.*?\\}(?=\\s*?(\\/?|$))', 'gi'); | ||
url = url.replace(reg, this.encodePathParam(args[param.name])); | ||
@@ -984,20 +991,22 @@ delete args[param.name]; | ||
var param = params[i]; | ||
if (param.paramType === 'query') { | ||
if (args[param.name] !== undefined) { | ||
var value = args[param.name]; | ||
if (queryParams !== '') | ||
queryParams += '&'; | ||
if (Array.isArray(value)) { | ||
var j; | ||
var output = ''; | ||
for(j = 0; j < value.length; j++) { | ||
if(j > 0) | ||
output += ','; | ||
output += encodeURIComponent(value[j]); | ||
} | ||
queryParams += encodeURIComponent(param.name) + '=' + output; | ||
if(param.paramType === 'query') { | ||
if (queryParams !== '') | ||
queryParams += '&'; | ||
if (Array.isArray(param)) { | ||
var j; | ||
var output = ''; | ||
for(j = 0; j < param.length; j++) { | ||
if(j > 0) | ||
output += ','; | ||
output += encodeURIComponent(param[j]); | ||
} | ||
queryParams += encodeURIComponent(param.name) + '=' + output; | ||
} | ||
else { | ||
if (args[param.name]) { | ||
queryParams += encodeURIComponent(param.name) + '=' + encodeURIComponent(args[param.name]); | ||
} else { | ||
if (param.required) | ||
throw "" + param.name + " is a required query param."; | ||
} | ||
else { | ||
queryParams += encodeURIComponent(param.name) + '=' + encodeURIComponent(args[param.name]); | ||
} | ||
} | ||
@@ -1283,3 +1292,3 @@ } | ||
else if (this.type != "DELETE") | ||
accepts = null; | ||
consumes = null; | ||
} | ||
@@ -1502,8 +1511,14 @@ | ||
var contentType = (response._headers["content-type"] || response._headers["Content-Type"] || null) | ||
var headers = response._headers.normalized || response._headers; | ||
var contentType = (headers["content-type"] || headers["Content-Type"] || null) | ||
if (contentType != null) { | ||
if (contentType.indexOf("application/json") == 0 || contentType.indexOf("+json") > 0) { | ||
if (response.content.data && response.content.data !== "") | ||
out.obj = JSON.parse(response.content.data); | ||
try { | ||
out.obj = JSON.parse(response.content.data); | ||
} | ||
catch (ex) { | ||
// do not set out.obj | ||
log ("unable to parse JSON content"); | ||
} | ||
else | ||
@@ -1673,2 +1688,4 @@ out.obj = {} | ||
e.parameterMacro = parameterMacro; | ||
e.modelPropertyMacro = modelPropertyMacro; | ||
e.SampleModels = sampleModels; | ||
@@ -1675,0 +1692,0 @@ e.SwaggerHttp = SwaggerHttp; |
@@ -1,1 +0,1 @@ | ||
$(function(){$.fn.vAlign=function(){return this.each(function(c){var a=$(this).height();var d=$(this).parent().height();var b=(d-a)/2;$(this).css("margin-top",b)})};$.fn.stretchFormtasticInputWidthToParent=function(){return this.each(function(b){var d=$(this).closest("form").innerWidth();var c=parseInt($(this).closest("form").css("padding-left"),10)+parseInt($(this).closest("form").css("padding-right"),10);var a=parseInt($(this).css("padding-left"),10)+parseInt($(this).css("padding-right"),10);$(this).css("width",d-c-a)})};$("form.formtastic li.string input, form.formtastic textarea").stretchFormtasticInputWidthToParent();$("ul.downplayed li div.content p").vAlign();$("form.sandbox").submit(function(){var a=true;$(this).find("input.required").each(function(){$(this).removeClass("error");if($(this).val()==""){$(this).addClass("error");$(this).wiggle();a=false}});return a})});function clippyCopiedCallback(b){$("#api_key_copied").fadeIn().delay(1000).fadeOut()}log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){console.log(Array.prototype.slice.call(arguments)[0])}};if(Function.prototype.bind&&console&&typeof console.log=="object"){["log","info","warn","error","assert","dir","clear","profile","profileEnd"].forEach(function(a){console[a]=this.bind(console[a],console)},Function.prototype.call)}var Docs={shebang:function(){var b=$.param.fragment().split("/");b.shift();switch(b.length){case 1:var d="resource_"+b[0];Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});break;case 2:Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});var c=b.join("_");var a=c+"_content";Docs.expandOperation($("#"+a));$("#"+c).slideto({highlight:false});break}},toggleEndpointListForResource:function(b){var a=$("li#resource_"+Docs.escapeResourceName(b)+" ul.endpoints");if(a.is(":visible")){Docs.collapseEndpointListForResource(b)}else{Docs.expandEndpointListForResource(b)}},expandEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);if(b==""){$(".resource ul.endpoints").slideDown();return}$("li#resource_"+b).addClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideDown()},collapseEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);$("li#resource_"+b).removeClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideUp()},expandOperationsForResource:function(a){Docs.expandEndpointListForResource(a);if(a==""){$(".resource ul.endpoints li.operation div.content").slideDown();return}$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.expandOperation($(this))})},collapseOperationsForResource:function(a){Docs.expandEndpointListForResource(a);$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.collapseOperation($(this))})},escapeResourceName:function(a){return a.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},expandOperation:function(a){a.slideDown()},collapseOperation:function(a){a.slideUp()}};(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.produces,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="contentType"></label>\n<select name="contentType">\n';c=f["if"].call(l,l.produces,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.main=b(function(h,n,g,m,l){this.compilerInfo=[4,">= 1.0.0"];g=this.merge(g,h.helpers);l=l||{};var j="",c,s,i="function",k=this.escapeExpression,q=this;function f(x,w){var t="",v,u;t+='\n <div class="info_title">'+k(((v=((v=x.info),v==null||v===false?v:v.title)),typeof v===i?v.apply(x):v))+'</div>\n <div class="info_description">';u=((v=((v=x.info),v==null||v===false?v:v.description)),typeof v===i?v.apply(x):v);if(u||u===0){t+=u}t+="</div>\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.termsOfServiceUrl),{hash:{},inverse:q.noop,fn:q.program(2,d,w),data:w});if(u||u===0){t+=u}t+="\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.contact),{hash:{},inverse:q.noop,fn:q.program(4,r,w),data:w});if(u||u===0){t+=u}t+="\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.license),{hash:{},inverse:q.noop,fn:q.program(6,p,w),data:w});if(u||u===0){t+=u}t+="\n ";return t}function d(w,v){var t="",u;t+='<div class="info_tos"><a href="'+k(((u=((u=w.info),u==null||u===false?u:u.termsOfServiceUrl)),typeof u===i?u.apply(w):u))+'">Terms of service</a></div>';return t}function r(w,v){var t="",u;t+="<div class='info_contact'><a href=\"mailto:"+k(((u=((u=((u=w.info),u==null||u===false?u:u.contact)),u==null||u===false?u:u.name)),typeof u===i?u.apply(w):u))+'">Contact the developer</a></div>';return t}function p(w,v){var t="",u;t+="<div class='info_license'><a href='"+k(((u=((u=((u=w.info),u==null||u===false?u:u.license)),u==null||u===false?u:u.url)),typeof u===i?u.apply(w):u))+"'>"+k(((u=((u=((u=w.info),u==null||u===false?u:u.license)),u==null||u===false?u:u.name)),typeof u===i?u.apply(w):u))+"</a></div>";return t}function o(w,v){var t="",u;t+='\n , <span style="font-variant: small-caps">api version</span>: '+k(((u=((u=w.info),u==null||u===false?u:u.version)),typeof u===i?u.apply(w):u))+"\n ";return t}function e(w,v){var t="",u;t+='\n <span style="float:right"><a href="';if(u=g.validatorUrl){u=u.call(w,{hash:{},data:v})}else{u=w.validatorUrl;u=typeof u===i?u.apply(w):u}t+=k(u)+"/debug?url=";if(u=g.url){u=u.call(w,{hash:{},data:v})}else{u=w.url;u=typeof u===i?u.apply(w):u}t+=k(u)+'"><img id="validator" src="';if(u=g.validatorUrl){u=u.call(w,{hash:{},data:v})}else{u=w.validatorUrl;u=typeof u===i?u.apply(w):u}t+=k(u)+"?url=";if(u=g.url){u=u.call(w,{hash:{},data:v})}else{u=w.url;u=typeof u===i?u.apply(w):u}t+=k(u)+'"></a>\n </span>\n ';return t}j+="<div class='info' id='api_info'>\n ";c=g["if"].call(n,n.info,{hash:{},inverse:q.noop,fn:q.program(1,f,l),data:l});if(c||c===0){j+=c}j+="\n</div>\n<div class='container' id='resources_container'>\n <ul id='resources'>\n </ul>\n\n <div class=\"footer\">\n <br>\n <br>\n <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: ";if(c=g.basePath){c=c.call(n,{hash:{},data:l})}else{c=n.basePath;c=typeof c===i?c.apply(n):c}j+=k(c)+"\n ";s=g["if"].call(n,((c=n.info),c==null||c===false?c:c.version),{hash:{},inverse:q.noop,fn:q.program(8,o,l),data:l});if(s||s===0){j+=s}j+="]\n ";s=g["if"].call(n,n.validatorUrl,{hash:{},inverse:q.noop,fn:q.program(10,e,l),data:l});if(s||s===0){j+=s}j+="\n </h4>\n </div>\n</div>\n";return j})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.operation=b(function(j,u,s,o,A){this.compilerInfo=[4,">= 1.0.0"];s=this.merge(s,j.helpers);A=A||{};var t="",k,f,e="function",d=this.escapeExpression,r=this,c=s.blockHelperMissing;function q(C,B){return"deprecated"}function p(C,B){return"\n <h4>Warning: Deprecated</h4>\n "}function n(E,D){var B="",C;B+="\n <h4>Implementation Notes</h4>\n <p>";if(C=s.description){C=C.call(E,{hash:{},data:D})}else{C=E.description;C=typeof C===e?C.apply(E):C}if(C||C===0){B+=C}B+="</p>\n ";return B}function m(C,B){return'\n <div class="auth">\n <span class="api-ic ic-error"></span>'}function i(E,D){var B="",C;B+='\n <div id="api_information_panel" style="top: 526px; left: 776px; display: none;">\n ';C=s.each.call(E,E,{hash:{},inverse:r.noop,fn:r.program(10,z,D),data:D});if(C||C===0){B+=C}B+="\n </div>\n ";return B}function z(F,E){var B="",D,C;B+="\n <div title='";C=((D=F.description),typeof D===e?D.apply(F):D);if(C||C===0){B+=C}B+="'>"+d(((D=F.scope),typeof D===e?D.apply(F):D))+"</div>\n ";return B}function y(C,B){return"</div>"}function x(C,B){return'\n <div class=\'access\'>\n <span class="api-ic ic-off" title="click to authenticate"></span>\n </div>\n '}function w(C,B){return'\n <h4>Response Class</h4>\n <p><span class="model-signature" /></p>\n <br/>\n <div class="response-content-type" />\n '}function v(C,B){return'\n <h4>Parameters</h4>\n <table class=\'fullwidth\'>\n <thead>\n <tr>\n <th style="width: 100px; max-width: 100px">Parameter</th>\n <th style="width: 310px; max-width: 310px">Value</th>\n <th style="width: 200px; max-width: 200px">Description</th>\n <th style="width: 100px; max-width: 100px">Parameter Type</th>\n <th style="width: 220px; max-width: 230px">Data Type</th>\n </tr>\n </thead>\n <tbody class="operation-params">\n\n </tbody>\n </table>\n '}function l(C,B){return"\n <div style='margin:0;padding:0;display:inline'></div>\n <h4>Response Messages</h4>\n <table class='fullwidth'>\n <thead>\n <tr>\n <th>HTTP Status Code</th>\n <th>Reason</th>\n <th>Response Model</th>\n </tr>\n </thead>\n <tbody class=\"operation-status\">\n \n </tbody>\n </table>\n "}function h(C,B){return"\n "}function g(C,B){return"\n <div class='sandbox_header'>\n <input class='submit' name='commit' type='button' value='Try it out!' />\n <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n <span class='response_throbber' style='display:none'></span>\n </div>\n "}t+="\n <ul class='operations' >\n <li class='";if(k=s.method){k=k.call(u,{hash:{},data:A})}else{k=u.method;k=typeof k===e?k.apply(u):k}t+=d(k)+" operation' id='";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"_";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"'>\n <div class='heading'>\n <h3>\n <span class='http_method'>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+'\' class="toggleOperation">';if(k=s.method){k=k.call(u,{hash:{},data:A})}else{k=u.method;k=typeof k===e?k.apply(u):k}t+=d(k)+"</a>\n </span>\n <span class='path'>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"' class=\"toggleOperation ";k=s["if"].call(u,u.deprecated,{hash:{},inverse:r.noop,fn:r.program(1,q,A),data:A});if(k||k===0){t+=k}t+='">';if(k=s.path){k=k.call(u,{hash:{},data:A})}else{k=u.path;k=typeof k===e?k.apply(u):k}t+=d(k)+"</a>\n </span>\n </h3>\n <ul class='options'>\n <li>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+'\' class="toggleOperation">';if(k=s.summary){k=k.call(u,{hash:{},data:A})}else{k=u.summary;k=typeof k===e?k.apply(u):k}if(k||k===0){t+=k}t+="</a>\n </li>\n </ul>\n </div>\n <div class='content' id='";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"_";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"_content' style='display:none'>\n ";k=s["if"].call(u,u.deprecated,{hash:{},inverse:r.noop,fn:r.program(3,p,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.description,{hash:{},inverse:r.noop,fn:r.program(5,n,A),data:A});if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(7,m,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";k=s.each.call(u,u.oauth,{hash:{},inverse:r.noop,fn:r.program(9,i,A),data:A});if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(12,y,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(14,x,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.type,{hash:{},inverse:r.noop,fn:r.program(16,w,A),data:A});if(k||k===0){t+=k}t+="\n <form accept-charset='UTF-8' class='sandbox'>\n <div style='margin:0;padding:0;display:inline'></div>\n ";k=s["if"].call(u,u.parameters,{hash:{},inverse:r.noop,fn:r.program(18,v,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.responseMessages,{hash:{},inverse:r.noop,fn:r.program(20,l,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.isReadOnly,{hash:{},inverse:r.program(24,g,A),fn:r.program(22,h,A),data:A});if(k||k===0){t+=k}t+="\n </form>\n <div class='response' style='display:none'>\n <h4>Request URL</h4>\n <div class='block request_url'></div>\n <h4>Response Body</h4>\n <div class='block response_body'></div>\n <h4>Response Code</h4>\n <div class='block response_code'></div>\n <h4>Response Headers</h4>\n <div class='block response_headers'></div>\n </div>\n </div>\n </li>\n </ul>\n";return t})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param=b(function(f,q,o,j,t){this.compilerInfo=[4,">= 1.0.0"];o=this.merge(o,f.helpers);t=t||{};var p="",g,d="function",c=this.escapeExpression,n=this;function m(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y.isFile,{hash:{},inverse:n.program(4,k,x),fn:n.program(2,l,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function l(y,x){var v="",w;v+='\n <input type="file" name=\'';if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+'\'/>\n <div class="parameter-content-type" />\n ';return v}function k(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y["default"],{hash:{},inverse:n.program(7,h,x),fn:n.program(5,i,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function i(y,x){var v="",w;v+="\n <textarea class='body-textarea' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"'>";if(w=o["default"]){w=w.call(y,{hash:{},data:x})}else{w=y["default"];w=typeof w===d?w.apply(y):w}v+=c(w)+"</textarea>\n ";return v}function h(y,x){var v="",w;v+="\n <textarea class='body-textarea' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+'\'></textarea>\n <br />\n <div class="parameter-content-type" />\n ';return v}function e(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y.isFile,{hash:{},inverse:n.program(10,u,x),fn:n.program(2,l,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function u(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y["default"],{hash:{},inverse:n.program(13,r,x),fn:n.program(11,s,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function s(y,x){var v="",w;v+="\n <input class='parameter' minlength='0' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"' placeholder='' type='text' value='";if(w=o["default"]){w=w.call(y,{hash:{},data:x})}else{w=y["default"];w=typeof w===d?w.apply(y):w}v+=c(w)+"'/>\n ";return v}function r(y,x){var v="",w;v+="\n <input class='parameter' minlength='0' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"' placeholder='' type='text' value=''/>\n ";return v}p+="<td class='code'>";if(g=o.name){g=g.call(q,{hash:{},data:t})}else{g=q.name;g=typeof g===d?g.apply(q):g}p+=c(g)+"</td>\n<td>\n\n ";g=o["if"].call(q,q.isBody,{hash:{},inverse:n.program(9,e,t),fn:n.program(1,m,t),data:t});if(g||g===0){p+=g}p+="\n\n</td>\n<td>";if(g=o.description){g=g.call(q,{hash:{},data:t})}else{g=q.description;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+="</td>\n<td>";if(g=o.paramType){g=g.call(q,{hash:{},data:t})}else{g=q.paramType;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+='</td>\n<td>\n <span class="model-signature"></span>\n</td>\n';return p})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_list=b(function(h,t,r,m,y){this.compilerInfo=[4,">= 1.0.0"];r=this.merge(r,h.helpers);y=y||{};var s="",j,g,e,p=this,q=r.helperMissing,d="function",c=this.escapeExpression;function o(A,z){return" multiple='multiple'"}function n(A,z){return"\n "}function l(C,B){var z="",A;z+="\n ";A=r["if"].call(C,C.defaultValue,{hash:{},inverse:p.program(8,i,B),fn:p.program(6,k,B),data:B});if(A||A===0){z+=A}z+="\n ";return z}function k(A,z){return"\n "}function i(E,D){var z="",C,B,A;z+="\n ";A={hash:{},inverse:p.program(11,x,D),fn:p.program(9,f,D),data:D};B=((C=r.isArray||E.isArray),C?C.call(E,E,A):q.call(E,"isArray",E,A));if(B||B===0){z+=B}z+="\n ";return z}function f(A,z){return"\n "}function x(A,z){return"\n <option selected=\"\" value=''></option>\n "}function w(C,B){var z="",A;z+="\n ";A=r["if"].call(C,C.isDefault,{hash:{},inverse:p.program(16,u,B),fn:p.program(14,v,B),data:B});if(A||A===0){z+=A}z+="\n ";return z}function v(C,B){var z="",A;z+='\n <option selected="" value=\'';if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"'>";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+" (default)</option>\n ";return z}function u(C,B){var z="",A;z+="\n <option value='";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"'>";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"</option>\n ";return z}s+="<td class='code'>";if(j=r.name){j=j.call(t,{hash:{},data:y})}else{j=t.name;j=typeof j===d?j.apply(t):j}s+=c(j)+"</td>\n<td>\n <select ";e={hash:{},inverse:p.noop,fn:p.program(1,o,y),data:y};g=((j=r.isArray||t.isArray),j?j.call(t,t,e):q.call(t,"isArray",t,e));if(g||g===0){s+=g}s+=" class='parameter' name='";if(g=r.name){g=g.call(t,{hash:{},data:y})}else{g=t.name;g=typeof g===d?g.apply(t):g}s+=c(g)+"'>\n ";g=r["if"].call(t,t.required,{hash:{},inverse:p.program(5,l,y),fn:p.program(3,n,y),data:y});if(g||g===0){s+=g}s+="\n ";g=r.each.call(t,((j=t.allowableValues),j==null||j===false?j:j.descriptiveValues),{hash:{},inverse:p.noop,fn:p.program(13,w,y),data:y});if(g||g===0){s+=g}s+="\n </select>\n</td>\n<td>";if(g=r.description){g=g.call(t,{hash:{},data:y})}else{g=t.description;g=typeof g===d?g.apply(t):g}if(g||g===0){s+=g}s+="</td>\n<td>";if(g=r.paramType){g=g.call(t,{hash:{},data:y})}else{g=t.paramType;g=typeof g===d?g.apply(t):g}if(g||g===0){s+=g}s+='</td>\n<td><span class="model-signature"></span></td>';return s})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,h="function",j=this.escapeExpression,o=this;function e(t,s){var q="",r;q+="\n <textarea class='body-textarea' readonly='readonly' name='";if(r=f.name){r=r.call(t,{hash:{},data:s})}else{r=t.name;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>";if(r=f.defaultValue){r=r.call(t,{hash:{},data:s})}else{r=t.defaultValue;r=typeof r===h?r.apply(t):r}q+=j(r)+"</textarea>\n ";return q}function c(t,s){var q="",r;q+="\n ";r=f["if"].call(t,t.defaultValue,{hash:{},inverse:o.program(6,n,s),fn:o.program(4,p,s),data:s});if(r||r===0){q+=r}q+="\n ";return q}function p(t,s){var q="",r;q+="\n ";if(r=f.defaultValue){r=r.call(t,{hash:{},data:s})}else{r=t.defaultValue;r=typeof r===h?r.apply(t):r}q+=j(r)+"\n ";return q}function n(r,q){return"\n (empty)\n "}i+="<td class='code'>";if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</td>\n<td>\n ";d=f["if"].call(m,m.isBody,{hash:{},inverse:o.program(3,c,k),fn:o.program(1,e,k),data:k});if(d||d===0){i+=d}i+="\n</td>\n<td>";if(d=f.description){d=d.call(m,{hash:{},data:k})}else{d=m.description;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="</td>\n<td>";if(d=f.paramType){d=d.call(m,{hash:{},data:k})}else{d=m.paramType;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+='</td>\n<td><span class="model-signature"></span></td>\n';return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly_required=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,h="function",j=this.escapeExpression,o=this;function e(t,s){var q="",r;q+="\n <textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='";if(r=f.name){r=r.call(t,{hash:{},data:s})}else{r=t.name;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>";if(r=f.defaultValue){r=r.call(t,{hash:{},data:s})}else{r=t.defaultValue;r=typeof r===h?r.apply(t):r}q+=j(r)+"</textarea>\n ";return q}function c(t,s){var q="",r;q+="\n ";r=f["if"].call(t,t.defaultValue,{hash:{},inverse:o.program(6,n,s),fn:o.program(4,p,s),data:s});if(r||r===0){q+=r}q+="\n ";return q}function p(t,s){var q="",r;q+="\n ";if(r=f.defaultValue){r=r.call(t,{hash:{},data:s})}else{r=t.defaultValue;r=typeof r===h?r.apply(t):r}q+=j(r)+"\n ";return q}function n(r,q){return"\n (empty)\n "}i+="<td class='code required'>";if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</td>\n<td>\n ";d=f["if"].call(m,m.isBody,{hash:{},inverse:o.program(3,c,k),fn:o.program(1,e,k),data:k});if(d||d===0){i+=d}i+="\n</td>\n<td>";if(d=f.description){d=d.call(m,{hash:{},data:k})}else{d=m.description;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="</td>\n<td>";if(d=f.paramType){d=d.call(m,{hash:{},data:k})}else{d=m.paramType;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+='</td>\n<td><span class="model-signature"></span></td>\n';return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_required=b(function(f,q,o,j,u){this.compilerInfo=[4,">= 1.0.0"];o=this.merge(o,f.helpers);u=u||{};var p="",g,d="function",c=this.escapeExpression,n=this;function m(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.isFile,{hash:{},inverse:n.program(4,k,y),fn:n.program(2,l,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function l(z,y){var w="",x;w+='\n <input type="file" name=\'';if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function k(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.defaultValue,{hash:{},inverse:n.program(7,h,y),fn:n.program(5,i,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function i(z,y){var w="",x;w+="\n <textarea class='body-textarea' placeholder='(required)' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'>";if(x=o.defaultValue){x=x.call(z,{hash:{},data:y})}else{x=z.defaultValue;x=typeof x===d?x.apply(z):x}w+=c(x)+"</textarea>\n ";return w}function h(z,y){var w="",x;w+="\n <textarea class='body-textarea' placeholder='(required)' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+'\'></textarea>\n <br />\n <div class="parameter-content-type" />\n ';return w}function e(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.isFile,{hash:{},inverse:n.program(12,t,y),fn:n.program(10,v,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function v(z,y){var w="",x;w+="\n <input class='parameter' class='required' type='file' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function t(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.defaultValue,{hash:{},inverse:n.program(15,r,y),fn:n.program(13,s,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function s(z,y){var w="",x;w+="\n <input class='parameter required' minlength='1' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"' placeholder='(required)' type='text' value='";if(x=o.defaultValue){x=x.call(z,{hash:{},data:y})}else{x=z.defaultValue;x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function r(z,y){var w="",x;w+="\n <input class='parameter required' minlength='1' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"' placeholder='(required)' type='text' value=''/>\n ";return w}p+="<td class='code required'>";if(g=o.name){g=g.call(q,{hash:{},data:u})}else{g=q.name;g=typeof g===d?g.apply(q):g}p+=c(g)+"</td>\n<td>\n ";g=o["if"].call(q,q.isBody,{hash:{},inverse:n.program(9,e,u),fn:n.program(1,m,u),data:u});if(g||g===0){p+=g}p+="\n</td>\n<td>\n <strong>";if(g=o.description){g=g.call(q,{hash:{},data:u})}else{g=q.description;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+="</strong>\n</td>\n<td>";if(g=o.paramType){g=g.call(q,{hash:{},data:u})}else{g=q.paramType;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+='</td>\n<td><span class="model-signature"></span></td>\n';return p})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.parameter_content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.consumes,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="parameterContentType"></label>\n<select name="parameterContentType">\n';c=f["if"].call(l,l.consumes,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.resource=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,p,h="function",j=this.escapeExpression,o=this,n=f.blockHelperMissing;function e(r,q){return" : "}function c(t,s){var q="",r;q+="<li>\n <a href='";if(r=f.url){r=r.call(t,{hash:{},data:s})}else{r=t.url;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>Raw</a>\n </li>";return q}i+="<div class='heading'>\n <h2>\n <a href='#!/";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'\' class="toggleEndpointList" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">';if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</a> ";p={hash:{},inverse:o.noop,fn:o.program(1,e,k),data:k};if(d=f.summary){d=d.call(m,p)}else{d=m.summary;d=typeof d===h?d.apply(m):d}if(!f.summary){d=n.call(m,d,p)}if(d||d===0){i+=d}if(d=f.summary){d=d.call(m,{hash:{},data:k})}else{d=m.summary;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="\n </h2>\n <ul class='options'>\n <li>\n <a href='#!/";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+"' id='endpointListTogger_";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'\' class="toggleEndpointList" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">Show/Hide</a>\n </li>\n <li>\n <a href=\'#\' class="collapseResource" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">\n List Operations\n </a>\n </li>\n <li>\n <a href=\'#\' class="expandResource" data-id=';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+">\n Expand Operations\n </a>\n </li>\n ";p={hash:{},inverse:o.noop,fn:o.program(3,c,k),data:k};if(d=f.url){d=d.call(m,p)}else{d=m.url;d=typeof d===h?d.apply(m):d}if(!f.url){d=n.call(m,d,p)}if(d||d===0){i+=d}i+="\n </ul>\n</div>\n<ul class='endpoints' id='";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+"_endpoint_list' style='display:none'>\n\n</ul>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.response_content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.produces,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="responseContentType"></label>\n<select name="responseContentType">\n';c=f["if"].call(l,l.produces,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.signature=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<div>\n<ul class="signature-nav">\n <li><a class="description-link" href="#">Model</a></li>\n <li><a class="snippet-link" href="#">Model Schema</a></li>\n</ul>\n<div>\n\n<div class="signature-container">\n <div class="description">\n ';if(c=d.signature){c=c.call(k,{hash:{},data:i})}else{c=k.signature;c=typeof c===f?c.apply(k):c}if(c||c===0){g+=c}g+='\n </div>\n\n <div class="snippet">\n <pre><code>';if(c=d.sampleJSON){c=c.call(k,{hash:{},data:i})}else{c=k.sampleJSON;c=typeof c===f?c.apply(k):c}g+=h(c)+'</code></pre>\n <small class="notice"></small>\n </div>\n</div>\n\n';return g})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.status_code=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+="<td width='15%' class='code'>";if(c=d.code){c=c.call(k,{hash:{},data:i})}else{c=k.code;c=typeof c===f?c.apply(k):c}g+=h(c)+"</td>\n<td>";if(c=d.message){c=c.call(k,{hash:{},data:i})}else{c=k.message;c=typeof c===f?c.apply(k):c}if(c||c===0){g+=c}g+="</td>\n<td width='50%'><span class=\"model-signature\" /></td>";return g})})();(function(){var j,r,u,o,l,k,n,m,i,p,s,q,h,c,g,f,e,d,b,a,x,w,t={}.hasOwnProperty,v=function(B,z){for(var y in z){if(t.call(z,y)){B[y]=z[y]}}function A(){this.constructor=B}A.prototype=z.prototype;B.prototype=new A();B.__super__=z.prototype;return B};s=(function(z){v(y,z);function y(){q=y.__super__.constructor.apply(this,arguments);return q}y.prototype.dom_id="swagger_ui";y.prototype.options=null;y.prototype.api=null;y.prototype.headerView=null;y.prototype.mainView=null;y.prototype.initialize=function(A){var B=this;if(A==null){A={}}if(A.dom_id!=null){this.dom_id=A.dom_id;delete A.dom_id}if($("#"+this.dom_id)==null){$("body").append('<div id="'+this.dom_id+'"></div>')}this.options=A;this.options.success=function(){return B.render()};this.options.progress=function(C){return B.showMessage(C)};this.options.failure=function(C){if(B.api&&B.api.isValid===false){log("not a valid 2.0 spec, loading legacy client");B.api=new SwaggerApi(B.options);return B.api.build()}else{return B.onLoadFailure(C)}};this.headerView=new r({el:$("#header")});return this.headerView.on("update-swagger-ui",function(C){return B.updateSwaggerUi(C)})};y.prototype.setOption=function(A,B){return this.options[A]=B};y.prototype.getOption=function(A){return this.options[A]};y.prototype.updateSwaggerUi=function(A){this.options.url=A.url;return this.load()};y.prototype.load=function(){var B,A;if((A=this.mainView)!=null){A.clear()}B=this.options.url;if(B.indexOf("http")!==0){B=this.buildUrl(window.location.href.toString(),B)}this.options.url=B;this.headerView.update(B);this.api=new SwaggerClient(this.options);return this.api.build()};y.prototype.render=function(){var A=this;this.showMessage("Finished Loading Resource Information. Rendering Swagger UI...");this.mainView=new u({model:this.api,el:$("#"+this.dom_id),swaggerOptions:this.options}).render();this.showMessage();switch(this.options.docExpansion){case"full":Docs.expandOperationsForResource("");break;case"list":Docs.collapseOperationsForResource("")}if(this.options.onComplete){this.options.onComplete(this.api,this)}return setTimeout(function(){return Docs.shebang()},400)};y.prototype.buildUrl=function(C,A){var B,D;log("base is "+C);if(A.indexOf("/")===0){D=C.split("/");C=D[0]+"//"+D[2];return C+A}else{B=C.length;if(C.indexOf("?")>-1){B=Math.min(B,C.indexOf("?"))}if(C.indexOf("#")>-1){B=Math.min(B,C.indexOf("#"))}C=C.substring(0,B);if(C.indexOf("/",C.length-1)!==-1){return C+A}return C+"/"+A}};y.prototype.showMessage=function(A){if(A==null){A=""}$("#message-bar").removeClass("message-fail");$("#message-bar").addClass("message-success");return $("#message-bar").html(A)};y.prototype.onLoadFailure=function(A){var B;if(A==null){A=""}$("#message-bar").removeClass("message-success");$("#message-bar").addClass("message-fail");B=$("#message-bar").html(A);if(this.options.onFailure!=null){this.options.onFailure(A)}return B};return y})(Backbone.Router);window.SwaggerUi=s;r=(function(z){v(y,z);function y(){h=y.__super__.constructor.apply(this,arguments);return h}y.prototype.events={"click #show-pet-store-icon":"showPetStore","click #show-wordnik-dev-icon":"showWordnikDev","click #explore":"showCustom","keyup #input_baseUrl":"showCustomOnKeyup","keyup #input_apiKey":"showCustomOnKeyup"};y.prototype.initialize=function(){};y.prototype.showPetStore=function(A){return this.trigger("update-swagger-ui",{url:"http://petstore.swagger.wordnik.com/api/api-docs"})};y.prototype.showWordnikDev=function(A){return this.trigger("update-swagger-ui",{url:"http://api.wordnik.com/v4/resources.json"})};y.prototype.showCustomOnKeyup=function(A){if(A.keyCode===13){return this.showCustom()}};y.prototype.showCustom=function(A){if(A!=null){A.preventDefault()}return this.trigger("update-swagger-ui",{url:$("#input_baseUrl").val(),apiKey:$("#input_apiKey").val()})};y.prototype.update=function(B,C,A){if(A==null){A=false}$("#input_baseUrl").val(B);if(A){return this.trigger("update-swagger-ui",{url:B})}};return y})(Backbone.View);u=(function(y){var z;v(A,y);function A(){g=A.__super__.constructor.apply(this,arguments);return g}z={alpha:function(C,B){return C.path.localeCompare(B.path)},method:function(C,B){return C.method.localeCompare(B.method)}};A.prototype.initialize=function(B){var C,I,J,E,D,G,H,F;if(B==null){B={}}if(B.swaggerOptions.sorter){E=B.swaggerOptions.sorter;J=z[E];if(this.model.apisArray){F=this.model.apisArray;for(G=0,H=F.length;G<H;G++){I=F[G];I.operationsArray.sort(J)}if(E==="alpha"){this.model.apisArray.sort(J)}}}if(this.model.info&&this.model.info.license&&typeof this.model.info.license==="string"){C=this.model.info.license;D=this.model.info.licenseUrl;this.model.info.license={};this.model.info.license.name=C;this.model.info.license.url=D}if(!this.model.info){this.model.info={}}if(!this.model.info.version){this.model.info.version=this.model.apiVersion}if(this.model.swaggerVersion==="2.0"){if("validatorUrl" in B.swaggerOptions){return this.model.validatorUrl=B.swaggerOptions.validatorUrl}else{if(this.model.url.match(/https?:\/\/localhost/)){return this.model.validatorUrl=this.model.url}else{return this.model.validatorUrl="http://online.swagger.io/validator"}}}};A.prototype.render=function(){var C,H,E,F,D,B,G;$(this.el).html(Handlebars.templates.main(this.model));F={};C=0;G=this.model.apisArray;for(D=0,B=G.length;D<B;D++){E=G[D];H=E.name;while(typeof F[H]!=="undefined"){H=H+"_"+C;C+=1}E.id=H;F[H]=E;this.addResource(E)}return this};A.prototype.addResource=function(C){var B;C.id=C.id.replace(/\s/g,"_");B=new n({model:C,tagName:"li",id:"resource_"+C.id,className:"resource",swaggerOptions:this.options.swaggerOptions});return $("#resources").append(B.render().el)};A.prototype.clear=function(){return $(this.el).html("")};return A})(Backbone.View);n=(function(z){v(y,z);function y(){f=y.__super__.constructor.apply(this,arguments);return f}y.prototype.initialize=function(){if(""===this.model.description){return this.model.description=null}};y.prototype.render=function(){var B,G,D,C,E,A,F;$(this.el).html(Handlebars.templates.resource(this.model));D={};if(this.model.description){this.model.summary=this.model.description}F=this.model.operationsArray;for(E=0,A=F.length;E<A;E++){C=F[E];B=0;G=C.nickname;while(typeof D[G]!=="undefined"){G=G+"_"+B;B+=1}D[G]=C;C.nickname=G;C.parentId=this.model.id;this.addOperation(C)}$(".toggleEndpointList",this.el).click(this.callDocs.bind(this,"toggleEndpointListForResource"));$(".collapseResource",this.el).click(this.callDocs.bind(this,"collapseOperationsForResource"));$(".expandResource",this.el).click(this.callDocs.bind(this,"expandOperationsForResource"));return this};y.prototype.addOperation=function(A){var B;A.number=this.number;B=new o({model:A,tagName:"li",className:"endpoint",swaggerOptions:this.options.swaggerOptions});$(".endpoints",$(this.el)).append(B.render().el);return this.number++};y.prototype.callDocs=function(B,A){A.preventDefault();return Docs[B](A.currentTarget.getAttribute("data-id"))};return y})(Backbone.View);o=(function(z){v(y,z);function y(){e=y.__super__.constructor.apply(this,arguments);return e}y.prototype.invocationUrl=null;y.prototype.events={"submit .sandbox":"submitOperation","click .submit":"submitOperation","click .response_hider":"hideResponse","click .toggleOperation":"toggleOperationContent","mouseenter .api-ic":"mouseEnter","mouseout .api-ic":"mouseExit"};y.prototype.initialize=function(){};y.prototype.mouseEnter=function(F){var D,E,I,B,A,J,G,C,K,H;D=$(F.currentTarget.parentNode).find("#api_information_panel");K=F.pageX;H=F.pageY;J=$(window).scrollLeft();G=$(window).scrollTop();B=J+$(window).width();A=G+$(window).height();C=D.width();E=D.height();if(K+C>B){K=B-C}if(K<J){K=J}if(H+E>A){H=A-E}if(H<G){H=G}I={};I.top=H;I.left=K;D.css(I);return $(F.currentTarget.parentNode).find("#api_information_panel").show()};y.prototype.mouseExit=function(A){return $(A.currentTarget.parentNode).find("#api_information_panel").hide()};y.prototype.render=function(){var D,U,V,T,R,K,J,Q,L,P,W,O,M,I,N,S,H,G,F,C,Y,ab,Z,X,E,B,A,ac,aa;V=true;if(!V){this.model.isReadOnly=true}this.model.description=this.model.description||this.model.notes;if(this.model.description){this.model.description=this.model.description.replace(/(?:\r\n|\r|\n)/g,"<br />")}this.model.oauth=null;if(this.model.authorizations){E=this.model.authorizations;for(T in E){N=E[T];if(T==="oauth2"){if(this.model.oauth===null){this.model.oauth={}}if(this.model.oauth.scopes===void 0){this.model.oauth.scopes=[]}for(H=0,Y=N.length;H<Y;H++){R=N[H];this.model.oauth.scopes.push(R)}}}}if(typeof this.model.responses!=="undefined"){this.model.responseMessages=[];B=this.model.responses;for(D in B){S=B[D];P=null;W=this.model.responses[D].schema;if(W&&W["$ref"]){P=W["$ref"];if(P.indexOf("#/definitions/")===0){P=P.substring("#/definitions/".length)}}this.model.responseMessages.push({code:D,message:S.description,responseModel:P})}}if(typeof this.model.responseMessages==="undefined"){this.model.responseMessages=[]}$(this.el).html(Handlebars.templates.operation(this.model));if(this.model.responseClassSignature&&this.model.responseClassSignature!=="string"){O={sampleJSON:this.model.responseSampleJSON,isParam:false,signature:this.model.responseClassSignature};L=new i({model:O,tagName:"div"});$(".model-signature",$(this.el)).append(L.render().el)}else{this.model.responseClassSignature="string";$(".model-signature",$(this.el)).html(this.model.type)}U={isParam:false};U.consumes=this.model.consumes;U.produces=this.model.produces;A=this.model.parameters;for(G=0,ab=A.length;G<ab;G++){K=A[G];I=K.type||K.dataType;if(typeof I==="undefined"){P=K.schema;if(P&&P["$ref"]){J=P["$ref"];if(J.indexOf("#/definitions/")===0){I=J.substring("#/definitions/".length)}else{I=J}}}if(I&&I.toLowerCase()==="file"){if(!U.consumes){U.consumes="multipart/form-data"}}K.type=I}Q=new m({model:U});$(".response-content-type",$(this.el)).append(Q.render().el);ac=this.model.parameters;for(F=0,Z=ac.length;F<Z;F++){K=ac[F];this.addParameter(K,U.consumes)}aa=this.model.responseMessages;for(C=0,X=aa.length;C<X;C++){M=aa[C];this.addStatusCode(M)}return this};y.prototype.addParameter=function(C,A){var B;C.consumes=A;B=new k({model:C,tagName:"tr",readOnly:this.model.isReadOnly});return $(".operation-params",$(this.el)).append(B.render().el)};y.prototype.addStatusCode=function(B){var A;A=new p({model:B,tagName:"tr"});return $(".operation-status",$(this.el)).append(A.render().el)};y.prototype.submitOperation=function(O){var Q,G,N,D,I,A,J,M,L,K,P,F,C,H,E,B;if(O!=null){O.preventDefault()}G=$(".sandbox",$(this.el));Q=true;G.find("input.required").each(function(){var R=this;$(this).removeClass("error");if(jQuery.trim($(this).val())===""){$(this).addClass("error");$(this).wiggle({callback:function(){return $(R).focus()}});return Q=false}});if(Q){D={};A={parent:this};N=false;H=G.find("input");for(M=0,P=H.length;M<P;M++){I=H[M];if((I.value!=null)&&jQuery.trim(I.value).length>0){D[I.name]=I.value}if(I.type==="file"){N=true}}E=G.find("textarea");for(L=0,F=E.length;L<F;L++){I=E[L];if((I.value!=null)&&jQuery.trim(I.value).length>0){D[I.name]=I.value}}B=G.find("select");for(K=0,C=B.length;K<C;K++){I=B[K];J=this.getSelectedValue(I);if((J!=null)&&jQuery.trim(J).length>0){D[I.name]=J}}A.responseContentType=$("div select[name=responseContentType]",$(this.el)).val();A.requestContentType=$("div select[name=parameterContentType]",$(this.el)).val();$(".response_throbber",$(this.el)).show();if(N){return this.handleFileUpload(D,G)}else{return this.model["do"](D,A,this.showCompleteStatus,this.showErrorStatus,this)}}};y.prototype.success=function(A,B){return B.showCompleteStatus(A)};y.prototype.handleFileUpload=function(R,I){var M,H,C,N,L,K,P,J,G,F,D,Q,U,T,S,E,B,A,V,O=this;E=I.serializeArray();for(J=0,Q=E.length;J<Q;J++){N=E[J];if((N.value!=null)&&jQuery.trim(N.value).length>0){R[N.name]=N.value}}M=new FormData();P=0;B=this.model.parameters;for(G=0,U=B.length;G<U;G++){K=B[G];if(K.paramType==="form"){if(K.type.toLowerCase()!=="file"&&R[K.name]!==void 0){M.append(K.name,R[K.name])}}}C={};A=this.model.parameters;for(F=0,T=A.length;F<T;F++){K=A[F];if(K.paramType==="header"){C[K.name]=R[K.name]}}V=I.find('input[type~="file"]');for(D=0,S=V.length;D<S;D++){H=V[D];if(typeof H.files[0]!=="undefined"){M.append($(H).attr("name"),H.files[0]);P+=1}}this.invocationUrl=this.model.supportHeaderParams()?(C=this.model.getHeaderParams(R),this.model.urlify(R,false)):this.model.urlify(R,true);$(".request_url",$(this.el)).html("<pre></pre>");$(".request_url pre",$(this.el)).text(this.invocationUrl);L={type:this.model.method,url:this.invocationUrl,headers:C,data:M,dataType:"json",contentType:false,processData:false,error:function(X,Y,W){return O.showErrorStatus(O.wrap(X),O)},success:function(W){return O.showResponse(W,O)},complete:function(W){return O.showCompleteStatus(O.wrap(W),O)}};if(window.authorizations){window.authorizations.apply(L)}if(P===0){L.data.append("fake","true")}jQuery.ajax(L);return false};y.prototype.wrap=function(E){var C,F,H,B,G,D,A;H={};F=E.getAllResponseHeaders().split("\r");for(D=0,A=F.length;D<A;D++){B=F[D];C=B.split(":");if(C[0]!==void 0&&C[1]!==void 0){H[C[0].trim()]=C[1].trim()}}G={};G.content={};G.content.data=E.responseText;G.headers=H;G.request={};G.request.url=this.invocationUrl;G.status=E.status;return G};y.prototype.getSelectedValue=function(A){var D,C,F,B,E;if(!A.multiple){return A.value}else{C=[];E=A.options;for(F=0,B=E.length;F<B;F++){D=E[F];if(D.selected){C.push(D.value)}}if(C.length>0){return C}else{return null}}};y.prototype.hideResponse=function(A){if(A!=null){A.preventDefault()}$(".response",$(this.el)).slideUp();return $(".response_hider",$(this.el)).fadeOut()};y.prototype.showResponse=function(A){var B;B=JSON.stringify(A,null,"\t").replace(/\n/g,"<br>");return $(".response_body",$(this.el)).html(escape(B))};y.prototype.showErrorStatus=function(B,A){return A.showStatus(B)};y.prototype.showCompleteStatus=function(B,A){return A.showStatus(B)};y.prototype.formatXml=function(H){var D,G,B,I,N,J,C,A,L,M,F,E,K;A=/(>)(<)(\/*)/g;M=/[ ]*(.*)[ ]+\n/g;D=/(<.+>)(.+\n)/g;H=H.replace(A,"$1\n$2$3").replace(M,"$1\n").replace(D,"$1\n$2");C=0;G="";N=H.split("\n");B=0;I="other";L={"single->single":0,"single->closing":-1,"single->opening":0,"single->other":0,"closing->single":0,"closing->closing":-1,"closing->opening":0,"closing->other":0,"opening->single":1,"opening->closing":0,"opening->opening":1,"opening->other":1,"other->single":0,"other->closing":-1,"other->opening":0,"other->other":0};F=function(T){var P,O,R,V,S,Q,U;Q={single:Boolean(T.match(/<.+\/>/)),closing:Boolean(T.match(/<\/.+>/)),opening:Boolean(T.match(/<[^!?].*>/))};S=((function(){var W;W=[];for(R in Q){U=Q[R];if(U){W.push(R)}}return W})())[0];S=S===void 0?"other":S;P=I+"->"+S;I=S;V="";B+=L[P];V=((function(){var X,Y,W;W=[];for(O=X=0,Y=B;0<=Y?X<Y:X>Y;O=0<=Y?++X:--X){W.push(" ")}return W})()).join("");if(P==="opening->closing"){return G=G.substr(0,G.length-1)+T+"\n"}else{return G+=V+T+"\n"}};for(E=0,K=N.length;E<K;E++){J=N[E];F(J)}return G};y.prototype.showStatus=function(F){var C,J,L,I,D,M,A,E,H,G,B;if(F.content===void 0){J=F.data;B=F.url}else{J=F.content.data;B=F.request.url}D=F.headers;L=D&&D["Content-Type"]?D["Content-Type"].split(";")[0].trim():null;if(!J){C=$("<code />").text("no content");E=$('<pre class="json" />').append(C)}else{if(L==="application/json"||/\+json$/.test(L)){M=null;try{M=JSON.stringify(JSON.parse(J),null," ")}catch(K){I=K;M="can't parse JSON. Raw result:\n\n"+J}C=$("<code />").text(M);E=$('<pre class="json" />').append(C)}else{if(L==="application/xml"||/\+xml$/.test(L)){C=$("<code />").text(this.formatXml(J));E=$('<pre class="xml" />').append(C)}else{if(L==="text/html"){C=$("<code />").html(_.escape(J));E=$('<pre class="xml" />').append(C)}else{if(/^image\//.test(L)){E=$("<img>").attr("src",B)}else{C=$("<code />").text(J);E=$('<pre class="json" />').append(C)}}}}}H=E;$(".request_url",$(this.el)).html("<pre></pre>");$(".request_url pre",$(this.el)).text(B);$(".response_code",$(this.el)).html("<pre>"+F.status+"</pre>");$(".response_body",$(this.el)).html(H);$(".response_headers",$(this.el)).html("<pre>"+_.escape(JSON.stringify(F.headers,null," ")).replace(/\n/g,"<br>")+"</pre>");$(".response",$(this.el)).slideDown();$(".response_hider",$(this.el)).show();$(".response_throbber",$(this.el)).hide();G=$(".response_body",$(this.el))[0];A=this.options.swaggerOptions;if(A.highlightSizeThreshold&&F.data.length>A.highlightSizeThreshold){return G}else{return hljs.highlightBlock(G)}};y.prototype.toggleOperationContent=function(){var A;A=$("#"+Docs.escapeResourceName(this.model.parentId)+"_"+this.model.nickname+"_content");if(A.is(":visible")){return Docs.collapseOperation(A)}else{return Docs.expandOperation(A)}};return y})(Backbone.View);p=(function(z){v(y,z);function y(){d=y.__super__.constructor.apply(this,arguments);return d}y.prototype.initialize=function(){};y.prototype.render=function(){var B,A,C;C=this.template();$(this.el).html(C(this.model));if(swaggerUi.api.models.hasOwnProperty(this.model.responseModel)){B={sampleJSON:JSON.stringify(swaggerUi.api.models[this.model.responseModel].createJSONSample(),null,2),isParam:false,signature:swaggerUi.api.models[this.model.responseModel].getMockSignature()};A=new i({model:B,tagName:"div"});$(".model-signature",this.$el).append(A.render().el)}else{$(".model-signature",this.$el).html("")}return this};y.prototype.template=function(){return Handlebars.templates.status_code};return y})(Backbone.View);k=(function(z){v(y,z);function y(){b=y.__super__.constructor.apply(this,arguments);return b}y.prototype.initialize=function(){return Handlebars.registerHelper("isArray",function(B,A){if(B.type.toLowerCase()==="array"||B.allowMultiple){return A.fn(this)}else{return A.inverse(this)}})};y.prototype.render=function(){var A,B,E,C,F,D,I,J,H,G;G=this.model.type||this.model.dataType;if(typeof G==="undefined"){D=this.model.schema;if(D&&D["$ref"]){C=D["$ref"];if(C.indexOf("#/definitions/")===0){G=C.substring("#/definitions/".length)}else{G=C}}}this.model.type=G;this.model.paramType=this.model["in"]||this.model.paramType;if(this.model.paramType==="body"){this.model.isBody=true}if(G&&G.toLowerCase()==="file"){this.model.isFile=true}this.model["default"]=this.model["default"]||this.model.defaultValue;H=this.template();$(this.el).html(H(this.model));I={sampleJSON:this.model.sampleJSON,isParam:true,signature:this.model.signature};if(this.model.sampleJSON){J=new i({model:I,tagName:"div"});$(".model-signature",$(this.el)).append(J.render().el)}else{$(".model-signature",$(this.el)).html(this.model.signature)}B=false;if(this.model.isBody){B=true}A={isParam:B};A.consumes=this.model.consumes;if(B){E=new l({model:A});$(".parameter-content-type",$(this.el)).append(E.render().el)}else{F=new m({model:A});$(".response-content-type",$(this.el)).append(F.render().el)}return this};y.prototype.template=function(){if(this.model.isList){return Handlebars.templates.param_list}else{if(this.options.readOnly){if(this.model.required){return Handlebars.templates.param_readonly_required}else{return Handlebars.templates.param_readonly}}else{if(this.model.required){return Handlebars.templates.param_required}else{return Handlebars.templates.param}}}};return y})(Backbone.View);i=(function(z){v(y,z);function y(){a=y.__super__.constructor.apply(this,arguments);return a}y.prototype.events={"click a.description-link":"switchToDescription","click a.snippet-link":"switchToSnippet","mousedown .snippet":"snippetToTextArea"};y.prototype.initialize=function(){};y.prototype.render=function(){var A;A=this.template();$(this.el).html(A(this.model));this.switchToSnippet();this.isParam=this.model.isParam;if(this.isParam){$(".notice",$(this.el)).text("Click to set as parameter value")}return this};y.prototype.template=function(){return Handlebars.templates.signature};y.prototype.switchToDescription=function(A){if(A!=null){A.preventDefault()}$(".snippet",$(this.el)).hide();$(".description",$(this.el)).show();$(".description-link",$(this.el)).addClass("selected");return $(".snippet-link",$(this.el)).removeClass("selected")};y.prototype.switchToSnippet=function(A){if(A!=null){A.preventDefault()}$(".description",$(this.el)).hide();$(".snippet",$(this.el)).show();$(".snippet-link",$(this.el)).addClass("selected");return $(".description-link",$(this.el)).removeClass("selected")};y.prototype.snippetToTextArea=function(A){var B;if(this.isParam){if(A!=null){A.preventDefault()}B=$("textarea",$(this.el.parentNode.parentNode.parentNode));if($.trim(B.val())===""){return B.val(this.model.sampleJSON)}}};return y})(Backbone.View);j=(function(y){v(z,y);function z(){x=z.__super__.constructor.apply(this,arguments);return x}z.prototype.initialize=function(){};z.prototype.render=function(){var A;A=this.template();$(this.el).html(A(this.model));$("label[for=contentType]",$(this.el)).text("Response Content Type");return this};z.prototype.template=function(){return Handlebars.templates.content_type};return z})(Backbone.View);m=(function(y){v(z,y);function z(){w=z.__super__.constructor.apply(this,arguments);return w}z.prototype.initialize=function(){};z.prototype.render=function(){var A;A=this.template();$(this.el).html(A(this.model));$("label[for=responseContentType]",$(this.el)).text("Response Content Type");return this};z.prototype.template=function(){return Handlebars.templates.response_content_type};return z})(Backbone.View);l=(function(z){v(y,z);function y(){c=y.__super__.constructor.apply(this,arguments);return c}y.prototype.initialize=function(){};y.prototype.render=function(){var A;A=this.template();$(this.el).html(A(this.model));$("label[for=parameterContentType]",$(this.el)).text("Parameter content type:");return this};y.prototype.template=function(){return Handlebars.templates.parameter_content_type};return y})(Backbone.View)}).call(this); | ||
$(function(){$.fn.vAlign=function(){return this.each(function(c){var a=$(this).height();var d=$(this).parent().height();var b=(d-a)/2;$(this).css("margin-top",b)})};$.fn.stretchFormtasticInputWidthToParent=function(){return this.each(function(b){var d=$(this).closest("form").innerWidth();var c=parseInt($(this).closest("form").css("padding-left"),10)+parseInt($(this).closest("form").css("padding-right"),10);var a=parseInt($(this).css("padding-left"),10)+parseInt($(this).css("padding-right"),10);$(this).css("width",d-c-a)})};$("form.formtastic li.string input, form.formtastic textarea").stretchFormtasticInputWidthToParent();$("ul.downplayed li div.content p").vAlign();$("form.sandbox").submit(function(){var a=true;$(this).find("input.required").each(function(){$(this).removeClass("error");if($(this).val()==""){$(this).addClass("error");$(this).wiggle();a=false}});return a})});function clippyCopiedCallback(b){$("#api_key_copied").fadeIn().delay(1000).fadeOut()}log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){console.log(Array.prototype.slice.call(arguments)[0])}};if(Function.prototype.bind&&console&&typeof console.log=="object"){["log","info","warn","error","assert","dir","clear","profile","profileEnd"].forEach(function(a){console[a]=this.bind(console[a],console)},Function.prototype.call)}var Docs={shebang:function(){var b=$.param.fragment().split("/");b.shift();switch(b.length){case 1:var d="resource_"+b[0];Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});break;case 2:Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});var c=b.join("_");var a=c+"_content";Docs.expandOperation($("#"+a));$("#"+c).slideto({highlight:false});break}},toggleEndpointListForResource:function(b){var a=$("li#resource_"+Docs.escapeResourceName(b)+" ul.endpoints");if(a.is(":visible")){Docs.collapseEndpointListForResource(b)}else{Docs.expandEndpointListForResource(b)}},expandEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);if(b==""){$(".resource ul.endpoints").slideDown();return}$("li#resource_"+b).addClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideDown()},collapseEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);$("li#resource_"+b).removeClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideUp()},expandOperationsForResource:function(a){Docs.expandEndpointListForResource(a);if(a==""){$(".resource ul.endpoints li.operation div.content").slideDown();return}$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.expandOperation($(this))})},collapseOperationsForResource:function(a){Docs.expandEndpointListForResource(a);$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.collapseOperation($(this))})},escapeResourceName:function(a){return a.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},expandOperation:function(a){a.slideDown()},collapseOperation:function(a){a.slideUp()}};(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.apikey_button_view=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+="<div class='auth_button' id='apikey_button'><img class='auth_icon' alt='apply api key' src='images/apikey.jpeg'></div>\n<div class='auth_container' id='apikey_container'>\n <div class='key_input_container'>\n <div class='auth_label'>";if(c=d.keyName){c=c.call(k,{hash:{},data:i})}else{c=k.keyName;c=typeof c===f?c.apply(k):c}g+=h(c)+'</div>\n <input placeholder="api_key" class="auth_input" id="input_apiKey_entry" name="apiKey" type="text"/>\n <div class=\'auth_submit\'><a class=\'auth_submit_button\' id="apply_api_key" href="#">apply</a></div>\n </div>\n</div>\n\n';return g})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.basic_auth_button_view=b(function(f,g,d,c,e){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,f.helpers);e=e||{};return'<div class=\'auth_button\' id=\'basic_auth_button\'><img class=\'auth_icon\' src=\'images/password.jpeg\'></div>\n<div class=\'auth_container\' id=\'basic_auth_container\'>\n <div class=\'key_input_container\'>\n <div class="auth_label">Username</div>\n <input placeholder="username" class="auth_input" id="input_username" name="username" type="text"/>\n <div class="auth_label">Password</div>\n <input placeholder="password" class="auth_input" id="input_password" name="password" type="password"/>\n <div class=\'auth_submit\'><a class=\'auth_submit_button\' id="apply_basic_auth" href="#">apply</a></div>\n </div>\n</div>\n\n'})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.produces,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="contentType"></label>\n<select name="contentType">\n';c=f["if"].call(l,l.produces,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.main=b(function(h,n,g,m,l){this.compilerInfo=[4,">= 1.0.0"];g=this.merge(g,h.helpers);l=l||{};var j="",c,s,i="function",k=this.escapeExpression,q=this;function f(x,w){var t="",v,u;t+='\n <div class="info_title">'+k(((v=((v=x.info),v==null||v===false?v:v.title)),typeof v===i?v.apply(x):v))+'</div>\n <div class="info_description">';u=((v=((v=x.info),v==null||v===false?v:v.description)),typeof v===i?v.apply(x):v);if(u||u===0){t+=u}t+="</div>\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.termsOfServiceUrl),{hash:{},inverse:q.noop,fn:q.program(2,d,w),data:w});if(u||u===0){t+=u}t+="\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.contact),{hash:{},inverse:q.noop,fn:q.program(4,r,w),data:w});if(u||u===0){t+=u}t+="\n ";u=g["if"].call(x,((v=x.info),v==null||v===false?v:v.license),{hash:{},inverse:q.noop,fn:q.program(6,p,w),data:w});if(u||u===0){t+=u}t+="\n ";return t}function d(w,v){var t="",u;t+='<div class="info_tos"><a href="'+k(((u=((u=w.info),u==null||u===false?u:u.termsOfServiceUrl)),typeof u===i?u.apply(w):u))+'">Terms of service</a></div>';return t}function r(w,v){var t="",u;t+="<div class='info_contact'><a href=\"mailto:"+k(((u=((u=((u=w.info),u==null||u===false?u:u.contact)),u==null||u===false?u:u.name)),typeof u===i?u.apply(w):u))+'">Contact the developer</a></div>';return t}function p(w,v){var t="",u;t+="<div class='info_license'><a href='"+k(((u=((u=((u=w.info),u==null||u===false?u:u.license)),u==null||u===false?u:u.url)),typeof u===i?u.apply(w):u))+"'>"+k(((u=((u=((u=w.info),u==null||u===false?u:u.license)),u==null||u===false?u:u.name)),typeof u===i?u.apply(w):u))+"</a></div>";return t}function o(w,v){var t="",u;t+='\n , <span style="font-variant: small-caps">api version</span>: '+k(((u=((u=w.info),u==null||u===false?u:u.version)),typeof u===i?u.apply(w):u))+"\n ";return t}function e(w,v){var t="",u;t+='\n <span style="float:right"><a href="';if(u=g.validatorUrl){u=u.call(w,{hash:{},data:v})}else{u=w.validatorUrl;u=typeof u===i?u.apply(w):u}t+=k(u)+"/debug?url=";if(u=g.url){u=u.call(w,{hash:{},data:v})}else{u=w.url;u=typeof u===i?u.apply(w):u}t+=k(u)+'"><img id="validator" src="';if(u=g.validatorUrl){u=u.call(w,{hash:{},data:v})}else{u=w.validatorUrl;u=typeof u===i?u.apply(w):u}t+=k(u)+"?url=";if(u=g.url){u=u.call(w,{hash:{},data:v})}else{u=w.url;u=typeof u===i?u.apply(w):u}t+=k(u)+'"></a>\n </span>\n ';return t}j+="<div class='info' id='api_info'>\n ";c=g["if"].call(n,n.info,{hash:{},inverse:q.noop,fn:q.program(1,f,l),data:l});if(c||c===0){j+=c}j+="\n</div>\n<div class='container' id='resources_container'>\n <ul id='resources'></ul>\n\n <div class=\"footer\">\n <br>\n <br>\n <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: ";if(c=g.basePath){c=c.call(n,{hash:{},data:l})}else{c=n.basePath;c=typeof c===i?c.apply(n):c}j+=k(c)+"\n ";s=g["if"].call(n,((c=n.info),c==null||c===false?c:c.version),{hash:{},inverse:q.noop,fn:q.program(8,o,l),data:l});if(s||s===0){j+=s}j+="]\n ";s=g["if"].call(n,n.validatorUrl,{hash:{},inverse:q.noop,fn:q.program(10,e,l),data:l});if(s||s===0){j+=s}j+="\n </h4>\n </div>\n</div>\n";return j})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.operation=b(function(j,u,s,o,A){this.compilerInfo=[4,">= 1.0.0"];s=this.merge(s,j.helpers);A=A||{};var t="",k,f,e="function",d=this.escapeExpression,r=this,c=s.blockHelperMissing;function q(C,B){return"deprecated"}function p(C,B){return"\n <h4>Warning: Deprecated</h4>\n "}function n(E,D){var B="",C;B+="\n <h4>Implementation Notes</h4>\n <p>";if(C=s.description){C=C.call(E,{hash:{},data:D})}else{C=E.description;C=typeof C===e?C.apply(E):C}if(C||C===0){B+=C}B+="</p>\n ";return B}function m(C,B){return'\n <div class="auth">\n <span class="api-ic ic-error"></span>'}function i(E,D){var B="",C;B+='\n <div id="api_information_panel" style="top: 526px; left: 776px; display: none;">\n ';C=s.each.call(E,E,{hash:{},inverse:r.noop,fn:r.program(10,z,D),data:D});if(C||C===0){B+=C}B+="\n </div>\n ";return B}function z(F,E){var B="",D,C;B+="\n <div title='";C=((D=F.description),typeof D===e?D.apply(F):D);if(C||C===0){B+=C}B+="'>"+d(((D=F.scope),typeof D===e?D.apply(F):D))+"</div>\n ";return B}function y(C,B){return"</div>"}function x(C,B){return'\n <div class=\'access\'>\n <span class="api-ic ic-off" title="click to authenticate"></span>\n </div>\n '}function w(C,B){return'\n <h4>Response Class</h4>\n <p><span class="model-signature" /></p>\n <br/>\n <div class="response-content-type" />\n '}function v(C,B){return'\n <h4>Parameters</h4>\n <table class=\'fullwidth\'>\n <thead>\n <tr>\n <th style="width: 100px; max-width: 100px">Parameter</th>\n <th style="width: 310px; max-width: 310px">Value</th>\n <th style="width: 200px; max-width: 200px">Description</th>\n <th style="width: 100px; max-width: 100px">Parameter Type</th>\n <th style="width: 220px; max-width: 230px">Data Type</th>\n </tr>\n </thead>\n <tbody class="operation-params">\n\n </tbody>\n </table>\n '}function l(C,B){return"\n <div style='margin:0;padding:0;display:inline'></div>\n <h4>Response Messages</h4>\n <table class='fullwidth'>\n <thead>\n <tr>\n <th>HTTP Status Code</th>\n <th>Reason</th>\n <th>Response Model</th>\n </tr>\n </thead>\n <tbody class=\"operation-status\">\n \n </tbody>\n </table>\n "}function h(C,B){return"\n "}function g(C,B){return"\n <div class='sandbox_header'>\n <input class='submit' name='commit' type='button' value='Try it out!' />\n <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n <span class='response_throbber' style='display:none'></span>\n </div>\n "}t+="\n <ul class='operations' >\n <li class='";if(k=s.method){k=k.call(u,{hash:{},data:A})}else{k=u.method;k=typeof k===e?k.apply(u):k}t+=d(k)+" operation' id='";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"_";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"'>\n <div class='heading'>\n <h3>\n <span class='http_method'>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+'\' class="toggleOperation">';if(k=s.method){k=k.call(u,{hash:{},data:A})}else{k=u.method;k=typeof k===e?k.apply(u):k}t+=d(k)+"</a>\n </span>\n <span class='path'>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"' class=\"toggleOperation ";k=s["if"].call(u,u.deprecated,{hash:{},inverse:r.noop,fn:r.program(1,q,A),data:A});if(k||k===0){t+=k}t+='">';if(k=s.path){k=k.call(u,{hash:{},data:A})}else{k=u.path;k=typeof k===e?k.apply(u):k}t+=d(k)+"</a>\n </span>\n </h3>\n <ul class='options'>\n <li>\n <a href='#!/";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"/";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+'\' class="toggleOperation">';if(k=s.summary){k=k.call(u,{hash:{},data:A})}else{k=u.summary;k=typeof k===e?k.apply(u):k}if(k||k===0){t+=k}t+="</a>\n </li>\n </ul>\n </div>\n <div class='content' id='";if(k=s.parentId){k=k.call(u,{hash:{},data:A})}else{k=u.parentId;k=typeof k===e?k.apply(u):k}t+=d(k)+"_";if(k=s.nickname){k=k.call(u,{hash:{},data:A})}else{k=u.nickname;k=typeof k===e?k.apply(u):k}t+=d(k)+"_content' style='display:none'>\n ";k=s["if"].call(u,u.deprecated,{hash:{},inverse:r.noop,fn:r.program(3,p,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.description,{hash:{},inverse:r.noop,fn:r.program(5,n,A),data:A});if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(7,m,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";k=s.each.call(u,u.oauth,{hash:{},inverse:r.noop,fn:r.program(9,i,A),data:A});if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(12,y,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";f={hash:{},inverse:r.noop,fn:r.program(14,x,A),data:A};if(k=s.oauth){k=k.call(u,f)}else{k=u.oauth;k=typeof k===e?k.apply(u):k}if(!s.oauth){k=c.call(u,k,f)}if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.type,{hash:{},inverse:r.noop,fn:r.program(16,w,A),data:A});if(k||k===0){t+=k}t+="\n <form accept-charset='UTF-8' class='sandbox'>\n <div style='margin:0;padding:0;display:inline'></div>\n ";k=s["if"].call(u,u.parameters,{hash:{},inverse:r.noop,fn:r.program(18,v,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.responseMessages,{hash:{},inverse:r.noop,fn:r.program(20,l,A),data:A});if(k||k===0){t+=k}t+="\n ";k=s["if"].call(u,u.isReadOnly,{hash:{},inverse:r.program(24,g,A),fn:r.program(22,h,A),data:A});if(k||k===0){t+=k}t+="\n </form>\n <div class='response' style='display:none'>\n <h4>Request URL</h4>\n <div class='block request_url'></div>\n <h4>Response Body</h4>\n <div class='block response_body'></div>\n <h4>Response Code</h4>\n <div class='block response_code'></div>\n <h4>Response Headers</h4>\n <div class='block response_headers'></div>\n </div>\n </div>\n </li>\n </ul>\n";return t})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param=b(function(f,q,o,j,t){this.compilerInfo=[4,">= 1.0.0"];o=this.merge(o,f.helpers);t=t||{};var p="",g,d="function",c=this.escapeExpression,n=this;function m(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y.isFile,{hash:{},inverse:n.program(4,k,x),fn:n.program(2,l,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function l(y,x){var v="",w;v+='\n <input type="file" name=\'';if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+'\'/>\n <div class="parameter-content-type" />\n ';return v}function k(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y["default"],{hash:{},inverse:n.program(7,h,x),fn:n.program(5,i,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function i(y,x){var v="",w;v+="\n <textarea class='body-textarea' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"'>";if(w=o["default"]){w=w.call(y,{hash:{},data:x})}else{w=y["default"];w=typeof w===d?w.apply(y):w}v+=c(w)+"</textarea>\n ";return v}function h(y,x){var v="",w;v+="\n <textarea class='body-textarea' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+'\'></textarea>\n <br />\n <div class="parameter-content-type" />\n ';return v}function e(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y.isFile,{hash:{},inverse:n.program(10,u,x),fn:n.program(2,l,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function u(y,x){var v="",w;v+="\n ";w=o["if"].call(y,y["default"],{hash:{},inverse:n.program(13,r,x),fn:n.program(11,s,x),data:x});if(w||w===0){v+=w}v+="\n ";return v}function s(y,x){var v="",w;v+="\n <input class='parameter' minlength='0' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"' placeholder='' type='text' value='";if(w=o["default"]){w=w.call(y,{hash:{},data:x})}else{w=y["default"];w=typeof w===d?w.apply(y):w}v+=c(w)+"'/>\n ";return v}function r(y,x){var v="",w;v+="\n <input class='parameter' minlength='0' name='";if(w=o.name){w=w.call(y,{hash:{},data:x})}else{w=y.name;w=typeof w===d?w.apply(y):w}v+=c(w)+"' placeholder='' type='text' value=''/>\n ";return v}p+="<td class='code'>";if(g=o.name){g=g.call(q,{hash:{},data:t})}else{g=q.name;g=typeof g===d?g.apply(q):g}p+=c(g)+"</td>\n<td>\n\n ";g=o["if"].call(q,q.isBody,{hash:{},inverse:n.program(9,e,t),fn:n.program(1,m,t),data:t});if(g||g===0){p+=g}p+="\n\n</td>\n<td>";if(g=o.description){g=g.call(q,{hash:{},data:t})}else{g=q.description;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+="</td>\n<td>";if(g=o.paramType){g=g.call(q,{hash:{},data:t})}else{g=q.paramType;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+='</td>\n<td>\n <span class="model-signature"></span>\n</td>\n';return p})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_list=b(function(h,t,r,m,y){this.compilerInfo=[4,">= 1.0.0"];r=this.merge(r,h.helpers);y=y||{};var s="",j,g,e,p=this,q=r.helperMissing,d="function",c=this.escapeExpression;function o(A,z){return" multiple='multiple'"}function n(A,z){return"\n "}function l(C,B){var z="",A;z+="\n ";A=r["if"].call(C,C["default"],{hash:{},inverse:p.program(8,i,B),fn:p.program(6,k,B),data:B});if(A||A===0){z+=A}z+="\n ";return z}function k(A,z){return"\n "}function i(E,D){var z="",C,B,A;z+="\n ";A={hash:{},inverse:p.program(11,x,D),fn:p.program(9,f,D),data:D};B=((C=r.isArray||E.isArray),C?C.call(E,E,A):q.call(E,"isArray",E,A));if(B||B===0){z+=B}z+="\n ";return z}function f(A,z){return"\n "}function x(A,z){return"\n <option selected=\"\" value=''></option>\n "}function w(C,B){var z="",A;z+="\n ";A=r["if"].call(C,C.isDefault,{hash:{},inverse:p.program(16,u,B),fn:p.program(14,v,B),data:B});if(A||A===0){z+=A}z+="\n ";return z}function v(C,B){var z="",A;z+='\n <option selected="" value=\'';if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"'>";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+" (default)</option>\n ";return z}function u(C,B){var z="",A;z+="\n <option value='";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"'>";if(A=r.value){A=A.call(C,{hash:{},data:B})}else{A=C.value;A=typeof A===d?A.apply(C):A}z+=c(A)+"</option>\n ";return z}s+="<td class='code'>";if(j=r.name){j=j.call(t,{hash:{},data:y})}else{j=t.name;j=typeof j===d?j.apply(t):j}s+=c(j)+"</td>\n<td>\n <select ";e={hash:{},inverse:p.noop,fn:p.program(1,o,y),data:y};g=((j=r.isArray||t.isArray),j?j.call(t,t,e):q.call(t,"isArray",t,e));if(g||g===0){s+=g}s+=" class='parameter' name='";if(g=r.name){g=g.call(t,{hash:{},data:y})}else{g=t.name;g=typeof g===d?g.apply(t):g}s+=c(g)+"'>\n ";g=r["if"].call(t,t.required,{hash:{},inverse:p.program(5,l,y),fn:p.program(3,n,y),data:y});if(g||g===0){s+=g}s+="\n ";g=r.each.call(t,((j=t.allowableValues),j==null||j===false?j:j.descriptiveValues),{hash:{},inverse:p.noop,fn:p.program(13,w,y),data:y});if(g||g===0){s+=g}s+="\n </select>\n</td>\n<td>";if(g=r.description){g=g.call(t,{hash:{},data:y})}else{g=t.description;g=typeof g===d?g.apply(t):g}if(g||g===0){s+=g}s+="</td>\n<td>";if(g=r.paramType){g=g.call(t,{hash:{},data:y})}else{g=t.paramType;g=typeof g===d?g.apply(t):g}if(g||g===0){s+=g}s+='</td>\n<td><span class="model-signature"></span></td>';return s})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,h="function",j=this.escapeExpression,o=this;function e(t,s){var q="",r;q+="\n <textarea class='body-textarea' readonly='readonly' name='";if(r=f.name){r=r.call(t,{hash:{},data:s})}else{r=t.name;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>";if(r=f["default"]){r=r.call(t,{hash:{},data:s})}else{r=t["default"];r=typeof r===h?r.apply(t):r}q+=j(r)+"</textarea>\n ";return q}function c(t,s){var q="",r;q+="\n ";r=f["if"].call(t,t["default"],{hash:{},inverse:o.program(6,n,s),fn:o.program(4,p,s),data:s});if(r||r===0){q+=r}q+="\n ";return q}function p(t,s){var q="",r;q+="\n ";if(r=f["default"]){r=r.call(t,{hash:{},data:s})}else{r=t["default"];r=typeof r===h?r.apply(t):r}q+=j(r)+"\n ";return q}function n(r,q){return"\n (empty)\n "}i+="<td class='code'>";if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</td>\n<td>\n ";d=f["if"].call(m,m.isBody,{hash:{},inverse:o.program(3,c,k),fn:o.program(1,e,k),data:k});if(d||d===0){i+=d}i+="\n</td>\n<td>";if(d=f.description){d=d.call(m,{hash:{},data:k})}else{d=m.description;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="</td>\n<td>";if(d=f.paramType){d=d.call(m,{hash:{},data:k})}else{d=m.paramType;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+='</td>\n<td><span class="model-signature"></span></td>\n';return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly_required=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,h="function",j=this.escapeExpression,o=this;function e(t,s){var q="",r;q+="\n <textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='";if(r=f.name){r=r.call(t,{hash:{},data:s})}else{r=t.name;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>";if(r=f["default"]){r=r.call(t,{hash:{},data:s})}else{r=t["default"];r=typeof r===h?r.apply(t):r}q+=j(r)+"</textarea>\n ";return q}function c(t,s){var q="",r;q+="\n ";r=f["if"].call(t,t["default"],{hash:{},inverse:o.program(6,n,s),fn:o.program(4,p,s),data:s});if(r||r===0){q+=r}q+="\n ";return q}function p(t,s){var q="",r;q+="\n ";if(r=f["default"]){r=r.call(t,{hash:{},data:s})}else{r=t["default"];r=typeof r===h?r.apply(t):r}q+=j(r)+"\n ";return q}function n(r,q){return"\n (empty)\n "}i+="<td class='code required'>";if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</td>\n<td>\n ";d=f["if"].call(m,m.isBody,{hash:{},inverse:o.program(3,c,k),fn:o.program(1,e,k),data:k});if(d||d===0){i+=d}i+="\n</td>\n<td>";if(d=f.description){d=d.call(m,{hash:{},data:k})}else{d=m.description;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="</td>\n<td>";if(d=f.paramType){d=d.call(m,{hash:{},data:k})}else{d=m.paramType;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+='</td>\n<td><span class="model-signature"></span></td>\n';return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_required=b(function(f,q,o,j,u){this.compilerInfo=[4,">= 1.0.0"];o=this.merge(o,f.helpers);u=u||{};var p="",g,d="function",c=this.escapeExpression,n=this;function m(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.isFile,{hash:{},inverse:n.program(4,k,y),fn:n.program(2,l,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function l(z,y){var w="",x;w+='\n <input type="file" name=\'';if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function k(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z["default"],{hash:{},inverse:n.program(7,h,y),fn:n.program(5,i,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function i(z,y){var w="",x;w+="\n <textarea class='body-textarea required' placeholder='(required)' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'>";if(x=o["default"]){x=x.call(z,{hash:{},data:y})}else{x=z["default"];x=typeof x===d?x.apply(z):x}w+=c(x)+"</textarea>\n ";return w}function h(z,y){var w="",x;w+="\n <textarea class='body-textarea required' placeholder='(required)' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+'\'></textarea>\n <br />\n <div class="parameter-content-type" />\n ';return w}function e(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z.isFile,{hash:{},inverse:n.program(12,t,y),fn:n.program(10,v,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function v(z,y){var w="",x;w+="\n <input class='parameter' class='required' type='file' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function t(z,y){var w="",x;w+="\n ";x=o["if"].call(z,z["default"],{hash:{},inverse:n.program(15,r,y),fn:n.program(13,s,y),data:y});if(x||x===0){w+=x}w+="\n ";return w}function s(z,y){var w="",x;w+="\n <input class='parameter required' minlength='1' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"' placeholder='(required)' type='text' value='";if(x=o["default"]){x=x.call(z,{hash:{},data:y})}else{x=z["default"];x=typeof x===d?x.apply(z):x}w+=c(x)+"'/>\n ";return w}function r(z,y){var w="",x;w+="\n <input class='parameter required' minlength='1' name='";if(x=o.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===d?x.apply(z):x}w+=c(x)+"' placeholder='(required)' type='text' value=''/>\n ";return w}p+="<td class='code required'>";if(g=o.name){g=g.call(q,{hash:{},data:u})}else{g=q.name;g=typeof g===d?g.apply(q):g}p+=c(g)+"</td>\n<td>\n ";g=o["if"].call(q,q.isBody,{hash:{},inverse:n.program(9,e,u),fn:n.program(1,m,u),data:u});if(g||g===0){p+=g}p+="\n</td>\n<td>\n <strong>";if(g=o.description){g=g.call(q,{hash:{},data:u})}else{g=q.description;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+="</strong>\n</td>\n<td>";if(g=o.paramType){g=g.call(q,{hash:{},data:u})}else{g=q.paramType;g=typeof g===d?g.apply(q):g}if(g||g===0){p+=g}p+='</td>\n<td><span class="model-signature"></span></td>\n';return p})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.parameter_content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.consumes,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="parameterContentType"></label>\n<select name="parameterContentType">\n';c=f["if"].call(l,l.consumes,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.resource=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,p,h="function",j=this.escapeExpression,o=this,n=f.blockHelperMissing;function e(r,q){return" : "}function c(t,s){var q="",r;q+="<li>\n <a href='";if(r=f.url){r=r.call(t,{hash:{},data:s})}else{r=t.url;r=typeof r===h?r.apply(t):r}q+=j(r)+"'>Raw</a>\n </li>";return q}i+="<div class='heading'>\n <h2>\n <a href='#!/";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'\' class="toggleEndpointList" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">';if(d=f.name){d=d.call(m,{hash:{},data:k})}else{d=m.name;d=typeof d===h?d.apply(m):d}i+=j(d)+"</a> ";p={hash:{},inverse:o.noop,fn:o.program(1,e,k),data:k};if(d=f.summary){d=d.call(m,p)}else{d=m.summary;d=typeof d===h?d.apply(m):d}if(!f.summary){d=n.call(m,d,p)}if(d||d===0){i+=d}if(d=f.summary){d=d.call(m,{hash:{},data:k})}else{d=m.summary;d=typeof d===h?d.apply(m):d}if(d||d===0){i+=d}i+="\n </h2>\n <ul class='options'>\n <li>\n <a href='#!/";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+"' id='endpointListTogger_";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'\' class="toggleEndpointList" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">Show/Hide</a>\n </li>\n <li>\n <a href=\'#\' class="collapseResource" data-id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'">\n List Operations\n </a>\n </li>\n <li>\n <a href=\'#\' class="expandResource" data-id=';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+">\n Expand Operations\n </a>\n </li>\n ";p={hash:{},inverse:o.noop,fn:o.program(3,c,k),data:k};if(d=f.url){d=d.call(m,p)}else{d=m.url;d=typeof d===h?d.apply(m):d}if(!f.url){d=n.call(m,d,p)}if(d||d===0){i+=d}i+="\n </ul>\n</div>\n<ul class='endpoints' id='";if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+"_endpoint_list' style='display:none'>\n\n</ul>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.response_content_type=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var i="",c,h="function",m=this;function e(r,q){var o="",p;o+="\n ";p=f.each.call(r,r.produces,{hash:{},inverse:m.noop,fn:m.program(2,d,q),data:q});if(p||p===0){o+=p}o+="\n";return o}function d(r,q){var o="",p;o+='\n <option value="';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+='">';p=(typeof r===h?r.apply(r):r);if(p||p===0){o+=p}o+="</option>\n ";return o}function n(p,o){return'\n <option value="application/json">application/json</option>\n'}i+='<label for="responseContentType"></label>\n<select name="responseContentType">\n';c=f["if"].call(l,l.produces,{hash:{},inverse:m.program(4,n,j),fn:m.program(1,e,j),data:j});if(c||c===0){i+=c}i+="\n</select>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.signature=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<div>\n<ul class="signature-nav">\n <li><a class="description-link" href="#">Model</a></li>\n <li><a class="snippet-link" href="#">Model Schema</a></li>\n</ul>\n<div>\n\n<div class="signature-container">\n <div class="description">\n ';if(c=d.signature){c=c.call(k,{hash:{},data:i})}else{c=k.signature;c=typeof c===f?c.apply(k):c}if(c||c===0){g+=c}g+='\n </div>\n\n <div class="snippet">\n <pre><code>';if(c=d.sampleJSON){c=c.call(k,{hash:{},data:i})}else{c=k.sampleJSON;c=typeof c===f?c.apply(k):c}g+=h(c)+'</code></pre>\n <small class="notice"></small>\n </div>\n</div>\n\n';return g})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.status_code=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+="<td width='15%' class='code'>";if(c=d.code){c=c.call(k,{hash:{},data:i})}else{c=k.code;c=typeof c===f?c.apply(k):c}g+=h(c)+"</td>\n<td>";if(c=d.message){c=c.call(k,{hash:{},data:i})}else{c=k.message;c=typeof c===f?c.apply(k):c}if(c||c===0){g+=c}g+="</td>\n<td width='50%'><span class=\"model-signature\" /></td>";return g})})();(function(){var t,k,l,u,x,q,n,m,p,o,j,r,v,s,i,d,b,B,h,g,f,e,c,a,A,z,w={}.hasOwnProperty,y=function(F,D){for(var C in D){if(w.call(D,C)){F[C]=D[C]}}function E(){this.constructor=F}E.prototype=D.prototype;F.prototype=new E();F.__super__=D.prototype;return F};v=(function(D){y(C,D);function C(){s=C.__super__.constructor.apply(this,arguments);return s}C.prototype.dom_id="swagger_ui";C.prototype.options=null;C.prototype.api=null;C.prototype.headerView=null;C.prototype.mainView=null;C.prototype.initialize=function(E){var F=this;if(E==null){E={}}if(E.dom_id!=null){this.dom_id=E.dom_id;delete E.dom_id}if($("#"+this.dom_id)==null){$("body").append('<div id="'+this.dom_id+'"></div>')}this.options=E;this.options.success=function(){return F.render()};this.options.progress=function(G){return F.showMessage(G)};this.options.failure=function(G){if(F.api&&F.api.isValid===false){log("not a valid 2.0 spec, loading legacy client");F.api=new SwaggerApi(F.options);return F.api.build()}else{return F.onLoadFailure(G)}};this.headerView=new u({el:$("#header")});return this.headerView.on("update-swagger-ui",function(G){return F.updateSwaggerUi(G)})};C.prototype.setOption=function(E,F){return this.options[E]=F};C.prototype.getOption=function(E){return this.options[E]};C.prototype.updateSwaggerUi=function(E){this.options.url=E.url;return this.load()};C.prototype.load=function(){var F,E;if((E=this.mainView)!=null){E.clear()}F=this.options.url;if(F.indexOf("http")!==0){F=this.buildUrl(window.location.href.toString(),F)}this.options.url=F;this.headerView.update(F);this.api=new SwaggerClient(this.options);return this.api.build()};C.prototype.collapseAll=function(){return Docs.collapseEndpointListForResource("")};C.prototype.listAll=function(){return Docs.collapseOperationsForResource("")};C.prototype.expandAll=function(){return Docs.expandOperationsForResource("")};C.prototype.render=function(){var E=this;this.showMessage("Finished Loading Resource Information. Rendering Swagger UI...");this.mainView=new x({model:this.api,el:$("#"+this.dom_id),swaggerOptions:this.options}).render();this.showMessage();switch(this.options.docExpansion){case"full":this.expandAll();break;case"list":this.listAll()}if(this.options.onComplete){this.options.onComplete(this.api,this)}return setTimeout(function(){return Docs.shebang()},400)};C.prototype.buildUrl=function(G,E){var F,H;log("base is "+G);if(E.indexOf("/")===0){H=G.split("/");G=H[0]+"//"+H[2];return G+E}else{F=G.length;if(G.indexOf("?")>-1){F=Math.min(F,G.indexOf("?"))}if(G.indexOf("#")>-1){F=Math.min(F,G.indexOf("#"))}G=G.substring(0,F);if(G.indexOf("/",G.length-1)!==-1){return G+E}return G+"/"+E}};C.prototype.showMessage=function(E){if(E==null){E=""}$("#message-bar").removeClass("message-fail");$("#message-bar").addClass("message-success");return $("#message-bar").html(E)};C.prototype.onLoadFailure=function(E){var F;if(E==null){E=""}$("#message-bar").removeClass("message-success");$("#message-bar").addClass("message-fail");F=$("#message-bar").html(E);if(this.options.onFailure!=null){this.options.onFailure(E)}return F};return C})(Backbone.Router);window.SwaggerUi=v;u=(function(D){y(C,D);function C(){i=C.__super__.constructor.apply(this,arguments);return i}C.prototype.events={"click #show-pet-store-icon":"showPetStore","click #show-wordnik-dev-icon":"showWordnikDev","click #explore":"showCustom","keyup #input_baseUrl":"showCustomOnKeyup","keyup #input_apiKey":"showCustomOnKeyup"};C.prototype.initialize=function(){};C.prototype.showPetStore=function(E){return this.trigger("update-swagger-ui",{url:"http://petstore.swagger.wordnik.com/api/api-docs"})};C.prototype.showWordnikDev=function(E){return this.trigger("update-swagger-ui",{url:"http://api.wordnik.com/v4/resources.json"})};C.prototype.showCustomOnKeyup=function(E){if(E.keyCode===13){return this.showCustom()}};C.prototype.showCustom=function(E){if(E!=null){E.preventDefault()}return this.trigger("update-swagger-ui",{url:$("#input_baseUrl").val(),apiKey:$("#input_apiKey").val()})};C.prototype.update=function(F,G,E){if(E==null){E=false}$("#input_baseUrl").val(F);if(E){return this.trigger("update-swagger-ui",{url:F})}};return C})(Backbone.View);x=(function(C){var D;y(E,C);function E(){h=E.__super__.constructor.apply(this,arguments);return h}D={alpha:function(G,F){return G.path.localeCompare(F.path)},method:function(G,F){return G.method.localeCompare(F.method)}};E.prototype.initialize=function(J){var I,H,G,F,K,L;if(J==null){J={}}this.model.auths=[];L=this.model.securityDefinitions;for(H in L){K=L[H];I={name:H,type:K.type,value:K};this.model.auths.push(I)}if(this.model.info&&this.model.info.license&&typeof this.model.info.license==="string"){G=this.model.info.license;F=this.model.info.licenseUrl;this.model.info.license={};this.model.info.license.name=G;this.model.info.license.url=F}if(!this.model.info){this.model.info={}}if(!this.model.info.version){this.model.info.version=this.model.apiVersion}if(this.model.swaggerVersion==="2.0"){if("validatorUrl" in J.swaggerOptions){return this.model.validatorUrl=J.swaggerOptions.validatorUrl}else{if(this.model.url.indexOf("localhost")>0){return this.model.validatorUrl=null}else{return this.model.validatorUrl="http://online.swagger.io/validator"}}}};E.prototype.render=function(){var K,N,F,H,G,L,I,M,O,J;if(this.model.securityDefinitions){for(G in this.model.securityDefinitions){K=this.model.securityDefinitions[G];if(K.type==="apiKey"&&$("#apikey_button").length===0){N=new t({model:K}).render().el;$(".auth_main_container").append(N)}if(K.type==="basicAuth"&&$("#basic_auth_button").length===0){N=new k({model:K}).render().el;$(".auth_main_container").append(N)}}}$(this.el).html(Handlebars.templates.main(this.model));I={};F=0;J=this.model.apisArray;for(M=0,O=J.length;M<O;M++){L=J[M];H=L.name;while(typeof I[H]!=="undefined"){H=H+"_"+F;F+=1}L.id=H;I[H]=L;this.addResource(L,this.model.auths)}return this};E.prototype.addResource=function(H,G){var F;H.id=H.id.replace(/\s/g,"_");F=new p({model:H,tagName:"li",id:"resource_"+H.id,className:"resource",auths:G,swaggerOptions:this.options.swaggerOptions});return $("#resources").append(F.render().el)};E.prototype.clear=function(){return $(this.el).html("")};return E})(Backbone.View);p=(function(D){y(C,D);function C(){g=C.__super__.constructor.apply(this,arguments);return g}C.prototype.initialize=function(E){if(E==null){E={}}this.auths=E.auths;if(""===this.model.description){return this.model.description=null}};C.prototype.render=function(){var F,K,H,G,I,E,J;$(this.el).html(Handlebars.templates.resource(this.model));H={};if(this.model.description){this.model.summary=this.model.description}J=this.model.operationsArray;for(I=0,E=J.length;I<E;I++){G=J[I];F=0;K=G.nickname;while(typeof H[K]!=="undefined"){K=K+"_"+F;F+=1}H[K]=G;G.nickname=K;G.parentId=this.model.id;this.addOperation(G)}$(".toggleEndpointList",this.el).click(this.callDocs.bind(this,"toggleEndpointListForResource"));$(".collapseResource",this.el).click(this.callDocs.bind(this,"collapseOperationsForResource"));$(".expandResource",this.el).click(this.callDocs.bind(this,"expandOperationsForResource"));return this};C.prototype.addOperation=function(E){var F;E.number=this.number;F=new q({model:E,tagName:"li",className:"endpoint",swaggerOptions:this.options.swaggerOptions,auths:this.auths});$(".endpoints",$(this.el)).append(F.render().el);return this.number++};C.prototype.callDocs=function(F,E){E.preventDefault();return Docs[F](E.currentTarget.getAttribute("data-id"))};return C})(Backbone.View);q=(function(D){y(C,D);function C(){f=C.__super__.constructor.apply(this,arguments);return f}C.prototype.invocationUrl=null;C.prototype.events={"submit .sandbox":"submitOperation","click .submit":"submitOperation","click .response_hider":"hideResponse","click .toggleOperation":"toggleOperationContent","mouseenter .api-ic":"mouseEnter","mouseout .api-ic":"mouseExit"};C.prototype.initialize=function(E){if(E==null){E={}}this.auths=E.auths;return this};C.prototype.mouseEnter=function(J){var H,I,M,F,E,N,K,G,O,L;H=$(J.currentTarget.parentNode).find("#api_information_panel");O=J.pageX;L=J.pageY;N=$(window).scrollLeft();K=$(window).scrollTop();F=N+$(window).width();E=K+$(window).height();G=H.width();I=H.height();if(O+G>F){O=F-G}if(O<N){O=N}if(L+I>E){L=E-I}if(L<K){L=K}M={};M.top=L;M.left=O;H.css(M);return $(J.currentTarget.parentNode).find("#api_information_panel").show()};C.prototype.mouseExit=function(E){return $(E.currentTarget.parentNode).find("#api_information_panel").hide()};C.prototype.render=function(){var al,R,aj,F,W,V,af,S,ab,H,Z,G,U,X,ad,ak,E,ao,Y,aa,ai,ah,ag,ae,T,N,L,J,I,ac,an,am,Q,P,O,M,K;V=true;if(!V){this.model.isReadOnly=true}this.model.description=this.model.description||this.model.notes;if(this.model.description){this.model.description=this.model.description.replace(/(?:\r\n|\r|\n)/g,"<br />")}this.model.oauth=null;if(this.model.authorizations){if(Array.isArray(this.model.authorizations)){Q=this.model.authorizations;for(ai=0,T=Q.length;ai<T;ai++){aj=Q[ai];for(S in aj){R=aj[S];for(al in this.auths){R=this.auths[al];if(R.type==="oauth2"){this.model.oauth={};this.model.oauth.scopes=[];P=R.value.scopes;for(af in P){Y=P[af];ab={scope:af,description:Y};this.model.oauth.scopes.push(ab)}}}}}}else{O=this.model.authorizations;for(af in O){Y=O[af];if(af==="oauth2"){if(this.model.oauth===null){this.model.oauth={}}if(this.model.oauth.scopes===void 0){this.model.oauth.scopes=[]}for(ah=0,N=Y.length;ah<N;ah++){ab=Y[ah];this.model.oauth.scopes.push(ab)}}}}}if(typeof this.model.responses!=="undefined"){this.model.responseMessages=[];M=this.model.responses;for(F in M){aa=M[F];X=null;ad=this.model.responses[F].schema;if(ad&&ad["$ref"]){X=ad["$ref"];if(X.indexOf("#/definitions/")===0){X=X.substring("#/definitions/".length)}}this.model.responseMessages.push({code:F,message:aa.description,responseModel:X})}}if(typeof this.model.responseMessages==="undefined"){this.model.responseMessages=[]}$(this.el).html(Handlebars.templates.operation(this.model));if(this.model.responseClassSignature&&this.model.responseClassSignature!=="string"){ak={sampleJSON:this.model.responseSampleJSON,isParam:false,signature:this.model.responseClassSignature};U=new j({model:ak,tagName:"div"});$(".model-signature",$(this.el)).append(U.render().el)}else{this.model.responseClassSignature="string";$(".model-signature",$(this.el)).html(this.model.type)}W={isParam:false};W.consumes=this.model.consumes;W.produces=this.model.produces;K=this.model.parameters;for(ag=0,L=K.length;ag<L;ag++){H=K[ag];ao=H.type||H.dataType;if(typeof ao==="undefined"){X=H.schema;if(X&&X["$ref"]){Z=X["$ref"];if(Z.indexOf("#/definitions/")===0){ao=Z.substring("#/definitions/".length)}else{ao=Z}}}if(ao&&ao.toLowerCase()==="file"){if(!W.consumes){W.consumes="multipart/form-data"}}H.type=ao}G=new o({model:W});$(".response-content-type",$(this.el)).append(G.render().el);an=this.model.parameters;for(ae=0,J=an.length;ae<J;ae++){H=an[ae];this.addParameter(H,W.consumes)}am=this.model.responseMessages;for(ac=0,I=am.length;ac<I;ac++){E=am[ac];this.addStatusCode(E)}return this};C.prototype.addParameter=function(G,E){var F;G.consumes=E;F=new m({model:G,tagName:"tr",readOnly:this.model.isReadOnly});return $(".operation-params",$(this.el)).append(F.render().el)};C.prototype.addStatusCode=function(F){var E;E=new r({model:F,tagName:"tr"});return $(".operation-status",$(this.el)).append(E.render().el)};C.prototype.submitOperation=function(S){var U,K,R,H,M,E,N,Q,P,O,T,J,G,L,I,F;if(S!=null){S.preventDefault()}K=$(".sandbox",$(this.el));U=true;K.find("input.required").each(function(){var V=this;$(this).removeClass("error");if(jQuery.trim($(this).val())===""){$(this).addClass("error");$(this).wiggle({callback:function(){return $(V).focus()}});return U=false}});K.find("textarea.required").each(function(){var V=this;$(this).removeClass("error");if(jQuery.trim($(this).val())===""){$(this).addClass("error");$(this).wiggle({callback:function(){return $(V).focus()}});return U=false}});if(U){H={};E={parent:this};R=false;L=K.find("input");for(Q=0,T=L.length;Q<T;Q++){M=L[Q];if((M.value!=null)&&jQuery.trim(M.value).length>0){H[M.name]=M.value}if(M.type==="file"){R=true}}I=K.find("textarea");for(P=0,J=I.length;P<J;P++){M=I[P];if((M.value!=null)&&jQuery.trim(M.value).length>0){H[M.name]=M.value}}F=K.find("select");for(O=0,G=F.length;O<G;O++){M=F[O];N=this.getSelectedValue(M);if((N!=null)&&jQuery.trim(N).length>0){H[M.name]=N}}E.responseContentType=$("div select[name=responseContentType]",$(this.el)).val();E.requestContentType=$("div select[name=parameterContentType]",$(this.el)).val();$(".response_throbber",$(this.el)).show();if(R){return this.handleFileUpload(H,K)}else{return this.model["do"](H,E,this.showCompleteStatus,this.showErrorStatus,this)}}};C.prototype.success=function(E,F){return F.showCompleteStatus(E)};C.prototype.handleFileUpload=function(V,M){var Q,L,G,R,P,O,T,N,K,J,H,U,Y,X,W,I,F,E,Z,S=this;I=M.serializeArray();for(N=0,U=I.length;N<U;N++){R=I[N];if((R.value!=null)&&jQuery.trim(R.value).length>0){V[R.name]=R.value}}Q=new FormData();T=0;F=this.model.parameters;for(K=0,Y=F.length;K<Y;K++){O=F[K];if(O.paramType==="form"){if(O.type.toLowerCase()!=="file"&&V[O.name]!==void 0){Q.append(O.name,V[O.name])}}}G={};E=this.model.parameters;for(J=0,X=E.length;J<X;J++){O=E[J];if(O.paramType==="header"){G[O.name]=V[O.name]}}Z=M.find('input[type~="file"]');for(H=0,W=Z.length;H<W;H++){L=Z[H];if(typeof L.files[0]!=="undefined"){Q.append($(L).attr("name"),L.files[0]);T+=1}}this.invocationUrl=this.model.supportHeaderParams()?(G=this.model.getHeaderParams(V),this.model.urlify(V,false)):this.model.urlify(V,true);$(".request_url",$(this.el)).html("<pre></pre>");$(".request_url pre",$(this.el)).text(this.invocationUrl);P={type:this.model.method,url:this.invocationUrl,headers:G,data:Q,dataType:"json",contentType:false,processData:false,error:function(ab,ac,aa){return S.showErrorStatus(S.wrap(ab),S)},success:function(aa){return S.showResponse(aa,S)},complete:function(aa){return S.showCompleteStatus(S.wrap(aa),S)}};if(window.authorizations){window.authorizations.apply(P)}if(T===0){P.data.append("fake","true")}jQuery.ajax(P);return false};C.prototype.wrap=function(I){var G,J,L,F,K,H,E;L={};J=I.getAllResponseHeaders().split("\r");for(H=0,E=J.length;H<E;H++){F=J[H];G=F.split(":");if(G[0]!==void 0&&G[1]!==void 0){L[G[0].trim()]=G[1].trim()}}K={};K.content={};K.content.data=I.responseText;K.headers=L;K.request={};K.request.url=this.invocationUrl;K.status=I.status;return K};C.prototype.getSelectedValue=function(E){var H,G,J,F,I;if(!E.multiple){return E.value}else{G=[];I=E.options;for(J=0,F=I.length;J<F;J++){H=I[J];if(H.selected){G.push(H.value)}}if(G.length>0){return G}else{return null}}};C.prototype.hideResponse=function(E){if(E!=null){E.preventDefault()}$(".response",$(this.el)).slideUp();return $(".response_hider",$(this.el)).fadeOut()};C.prototype.showResponse=function(E){var F;F=JSON.stringify(E,null,"\t").replace(/\n/g,"<br>");return $(".response_body",$(this.el)).html(escape(F))};C.prototype.showErrorStatus=function(F,E){return E.showStatus(F)};C.prototype.showCompleteStatus=function(F,E){return E.showStatus(F)};C.prototype.formatXml=function(L){var H,K,F,M,R,N,G,E,P,Q,J,I,O;E=/(>)(<)(\/*)/g;Q=/[ ]*(.*)[ ]+\n/g;H=/(<.+>)(.+\n)/g;L=L.replace(E,"$1\n$2$3").replace(Q,"$1\n").replace(H,"$1\n$2");G=0;K="";R=L.split("\n");F=0;M="other";P={"single->single":0,"single->closing":-1,"single->opening":0,"single->other":0,"closing->single":0,"closing->closing":-1,"closing->opening":0,"closing->other":0,"opening->single":1,"opening->closing":0,"opening->opening":1,"opening->other":1,"other->single":0,"other->closing":-1,"other->opening":0,"other->other":0};J=function(X){var T,S,V,Z,W,U,Y;U={single:Boolean(X.match(/<.+\/>/)),closing:Boolean(X.match(/<\/.+>/)),opening:Boolean(X.match(/<[^!?].*>/))};W=((function(){var aa;aa=[];for(V in U){Y=U[V];if(Y){aa.push(V)}}return aa})())[0];W=W===void 0?"other":W;T=M+"->"+W;M=W;Z="";F+=P[T];Z=((function(){var ab,ac,aa;aa=[];for(S=ab=0,ac=F;0<=ac?ab<ac:ab>ac;S=0<=ac?++ab:--ab){aa.push(" ")}return aa})()).join("");if(T==="opening->closing"){return K=K.substr(0,K.length-1)+X+"\n"}else{return K+=Z+X+"\n"}};for(I=0,O=R.length;I<O;I++){N=R[I];J(N)}return K};C.prototype.showStatus=function(J){var G,N,P,M,H,Q,E,I,L,K,F;if(J.content===void 0){N=J.data;F=J.url}else{N=J.content.data;F=J.request.url}H=J.headers;P=null;if(H){P=H["Content-Type"]||H["content-type"];if(P){P=P.split(";")[0].trim()}}if(!N){G=$("<code />").text("no content");I=$('<pre class="json" />').append(G)}else{if(P==="application/json"||/\+json$/.test(P)){Q=null;try{Q=JSON.stringify(JSON.parse(N),null," ")}catch(O){M=O;Q="can't parse JSON. Raw result:\n\n"+N}G=$("<code />").text(Q);I=$('<pre class="json" />').append(G)}else{if(P==="application/xml"||/\+xml$/.test(P)){G=$("<code />").text(this.formatXml(N));I=$('<pre class="xml" />').append(G)}else{if(P==="text/html"){G=$("<code />").html(_.escape(N));I=$('<pre class="xml" />').append(G)}else{if(/^image\//.test(P)){I=$("<img>").attr("src",F)}else{G=$("<code />").text(N);I=$('<pre class="json" />').append(G)}}}}}L=I;$(".request_url",$(this.el)).html("<pre></pre>");$(".request_url pre",$(this.el)).text(F);$(".response_code",$(this.el)).html("<pre>"+J.status+"</pre>");$(".response_body",$(this.el)).html(L);$(".response_headers",$(this.el)).html("<pre>"+_.escape(JSON.stringify(J.headers,null," ")).replace(/\n/g,"<br>")+"</pre>");$(".response",$(this.el)).slideDown();$(".response_hider",$(this.el)).show();$(".response_throbber",$(this.el)).hide();K=$(".response_body",$(this.el))[0];E=this.options.swaggerOptions;if(E.highlightSizeThreshold&&J.data.length>E.highlightSizeThreshold){return K}else{return hljs.highlightBlock(K)}};C.prototype.toggleOperationContent=function(){var E;E=$("#"+Docs.escapeResourceName(this.model.parentId+"_"+this.model.nickname+"_content"));if(E.is(":visible")){return Docs.collapseOperation(E)}else{return Docs.expandOperation(E)}};return C})(Backbone.View);r=(function(D){y(C,D);function C(){e=C.__super__.constructor.apply(this,arguments);return e}C.prototype.initialize=function(){};C.prototype.render=function(){var F,E,G;G=this.template();$(this.el).html(G(this.model));if(swaggerUi.api.models.hasOwnProperty(this.model.responseModel)){F={sampleJSON:JSON.stringify(swaggerUi.api.models[this.model.responseModel].createJSONSample(),null,2),isParam:false,signature:swaggerUi.api.models[this.model.responseModel].getMockSignature()};E=new j({model:F,tagName:"div"});$(".model-signature",this.$el).append(E.render().el)}else{$(".model-signature",this.$el).html("")}return this};C.prototype.template=function(){return Handlebars.templates.status_code};return C})(Backbone.View);m=(function(D){y(C,D);function C(){c=C.__super__.constructor.apply(this,arguments);return c}C.prototype.initialize=function(){return Handlebars.registerHelper("isArray",function(F,E){if(F.type.toLowerCase()==="array"||F.allowMultiple){return E.fn(this)}else{return E.inverse(this)}})};C.prototype.render=function(){var E,F,I,G,J,H,M,N,L,K;K=this.model.type||this.model.dataType;if(typeof K==="undefined"){H=this.model.schema;if(H&&H["$ref"]){G=H["$ref"];if(G.indexOf("#/definitions/")===0){K=G.substring("#/definitions/".length)}else{K=G}}}this.model.type=K;this.model.paramType=this.model["in"]||this.model.paramType;if(this.model.paramType==="body"){this.model.isBody=true}if(K&&K.toLowerCase()==="file"){this.model.isFile=true}this.model["default"]=this.model["default"]||this.model.defaultValue;if(this.model.allowableValues){this.model.isList=true}L=this.template();$(this.el).html(L(this.model));M={sampleJSON:this.model.sampleJSON,isParam:true,signature:this.model.signature};if(this.model.sampleJSON){N=new j({model:M,tagName:"div"});$(".model-signature",$(this.el)).append(N.render().el)}else{$(".model-signature",$(this.el)).html(this.model.signature)}F=false;if(this.model.isBody){F=true}E={isParam:F};E.consumes=this.model.consumes;if(F){I=new n({model:E});$(".parameter-content-type",$(this.el)).append(I.render().el)}else{J=new o({model:E});$(".response-content-type",$(this.el)).append(J.render().el)}return this};C.prototype.template=function(){if(this.model.isList){return Handlebars.templates.param_list}else{if(this.options.readOnly){if(this.model.required){return Handlebars.templates.param_readonly_required}else{return Handlebars.templates.param_readonly}}else{if(this.model.required){return Handlebars.templates.param_required}else{return Handlebars.templates.param}}}};return C})(Backbone.View);j=(function(D){y(C,D);function C(){a=C.__super__.constructor.apply(this,arguments);return a}C.prototype.events={"click a.description-link":"switchToDescription","click a.snippet-link":"switchToSnippet","mousedown .snippet":"snippetToTextArea"};C.prototype.initialize=function(){};C.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));this.switchToSnippet();this.isParam=this.model.isParam;if(this.isParam){$(".notice",$(this.el)).text("Click to set as parameter value")}return this};C.prototype.template=function(){return Handlebars.templates.signature};C.prototype.switchToDescription=function(E){if(E!=null){E.preventDefault()}$(".snippet",$(this.el)).hide();$(".description",$(this.el)).show();$(".description-link",$(this.el)).addClass("selected");return $(".snippet-link",$(this.el)).removeClass("selected")};C.prototype.switchToSnippet=function(E){if(E!=null){E.preventDefault()}$(".description",$(this.el)).hide();$(".snippet",$(this.el)).show();$(".snippet-link",$(this.el)).addClass("selected");return $(".description-link",$(this.el)).removeClass("selected")};C.prototype.snippetToTextArea=function(E){var F;if(this.isParam){if(E!=null){E.preventDefault()}F=$("textarea",$(this.el.parentNode.parentNode.parentNode));if($.trim(F.val())===""){return F.val(this.model.sampleJSON)}}};return C})(Backbone.View);l=(function(C){y(D,C);function D(){A=D.__super__.constructor.apply(this,arguments);return A}D.prototype.initialize=function(){};D.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));$("label[for=contentType]",$(this.el)).text("Response Content Type");return this};D.prototype.template=function(){return Handlebars.templates.content_type};return D})(Backbone.View);o=(function(C){y(D,C);function D(){z=D.__super__.constructor.apply(this,arguments);return z}D.prototype.initialize=function(){};D.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));$("label[for=responseContentType]",$(this.el)).text("Response Content Type");return this};D.prototype.template=function(){return Handlebars.templates.response_content_type};return D})(Backbone.View);n=(function(D){y(C,D);function C(){d=C.__super__.constructor.apply(this,arguments);return d}C.prototype.initialize=function(){};C.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));$("label[for=parameterContentType]",$(this.el)).text("Parameter content type:");return this};C.prototype.template=function(){return Handlebars.templates.parameter_content_type};return C})(Backbone.View);t=(function(D){y(C,D);function C(){b=C.__super__.constructor.apply(this,arguments);return b}C.prototype.initialize=function(){};C.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));return this};C.prototype.events={"click #apikey_button":"toggleApiKeyContainer","click #apply_api_key":"applyApiKey"};C.prototype.applyApiKey=function(){var E;window.authorizations.add(this.model.name,new ApiKeyAuthorization(this.model.name,$("#input_apiKey_entry").val(),this.model["in"]));window.swaggerUi.load();return E=$("#apikey_container").show()};C.prototype.toggleApiKeyContainer=function(){var E;if($("#apikey_container").length>0){E=$("#apikey_container").first();if(E.is(":visible")){return E.hide()}else{$(".auth_container").hide();return E.show()}}};C.prototype.template=function(){return Handlebars.templates.apikey_button_view};return C})(Backbone.View);k=(function(D){y(C,D);function C(){B=C.__super__.constructor.apply(this,arguments);return B}C.prototype.initialize=function(){};C.prototype.render=function(){var E;E=this.template();$(this.el).html(E(this.model));return this};C.prototype.events={"click #basic_auth_button":"togglePasswordContainer","click #apply_basic_auth":"applyPassword"};C.prototype.applyPassword=function(){var F,E,G;console.log("applying password");G=$(".input_username").val();E=$(".input_password").val();window.authorizations.add(this.model.type,new PasswordAuthorization("basic",G,E));window.swaggerUi.load();return F=$("#basic_auth_container").hide()};C.prototype.togglePasswordContainer=function(){var E;if($("#basic_auth_container").length>0){E=$("#basic_auth_container").show();if(E.is(":visible")){return E.slideUp()}else{$(".auth_container").hide();return E.show()}}};C.prototype.template=function(){return Handlebars.templates.basic_auth_button_view};return C})(Backbone.View)}).call(this); |
{ | ||
"name": "swagger-tools", | ||
"version": "0.6.13", | ||
"version": "0.7.0", | ||
"description": "Various tools for using and integrating with Swagger.", | ||
@@ -43,3 +43,3 @@ "main": "index.js", | ||
"brfs": "^1.2.0", | ||
"browserify": "^5.12.1", | ||
"browserify": "^5.13.1", | ||
"connect": "^3.1.0", | ||
@@ -59,13 +59,15 @@ "exposify": "^0.2.0", | ||
"async": "^0.9.0", | ||
"commander": "^2.3.0", | ||
"jjv": "^1.0.0", | ||
"jjve": "^0.4.0", | ||
"commander": "^2.5.0", | ||
"json-refs": "^0.1.4", | ||
"lodash": "^2.4.1", | ||
"parseurl": "^1.2.0", | ||
"path-to-regexp": "^0.2.3", | ||
"serve-static": "^1.6.3", | ||
"path-to-regexp": "^0.2.5", | ||
"serve-static": "^1.7.1", | ||
"spark-md5": "0.0.5", | ||
"string": "^2.1.0", | ||
"traverse": "^0.6.6" | ||
"superagent": "^0.21.0", | ||
"traverse": "^0.6.6", | ||
"yamljs": "^0.2.1", | ||
"z-schema": "^3.1.5" | ||
} | ||
} |
The project provides various tools for integrating and interacting with Swagger. This project is in its infancy but | ||
what is within the repository should be fully tested and reusable. Please visit the [issue tracker][project-issues] to | ||
see what issues we are aware of and what features/enhancements we are working on. | ||
see what issues we are aware of and what features/enhancements we are working on. Otherwise, feel free to review the | ||
[Release Notes][release-notes] to see what is new and improved. | ||
@@ -17,3 +18,3 @@ ## Project Badges | ||
* [1.2][swagger-docs-v1_2] | ||
* [2.0 (WIP)][swagger-docs-v2_0] | ||
* [2.0][swagger-docs-v2_0] | ||
@@ -27,2 +28,3 @@ ## Features | ||
* Connect middleware for adding pertinent Swagger information to your requests _(Node only)_ | ||
* Connect middleware for wiring up security handlers for requests based on Swagger documentation _(Node only)_ | ||
* Connect middleware for wiring request handlers to requests based on Swagger documentation _(Node only)_ | ||
@@ -58,2 +60,3 @@ * Connect middleware for serving your Swagger documents and [Swagger UI][swagger-ui] _(Node only)_ | ||
[quick-start]: https://github.com/apigee-127/swagger-tools/blob/master/docs/QuickStart.md | ||
[release-notes]: https://github.com/apigee-127/swagger-tools/blob/master/RELEASE_NOTES.md | ||
[swagger]: https://helloreverb.com/developers/swagger | ||
@@ -60,0 +63,0 @@ [swagger-docs-v1_2]: https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md |
@@ -57,5 +57,6 @@ { | ||
"format": "mime-type" | ||
} | ||
}, | ||
"uniqueItems": true | ||
} | ||
} | ||
} |
@@ -10,3 +10,3 @@ { | ||
"properties": { | ||
"method": { "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS" ] }, | ||
"method": { "enum": [ "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS" ] }, | ||
"summary": { "type": "string", "maxLength": 120 }, | ||
@@ -62,5 +62,6 @@ "notes": { "type": "string" }, | ||
"format": "mime-type" | ||
} | ||
}, | ||
"uniqueItems": true | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
843258
17034
63
13
18
+ Addedjson-refs@^0.1.4
+ Addedsuperagent@^0.21.0
+ Addedyamljs@^0.2.1
+ Addedz-schema@^3.1.5
+ Addedargparse@1.0.10(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedcombined-stream@0.0.7(transitive)
+ Addedcomponent-emitter@1.1.2(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedcookiejar@2.0.1(transitive)
+ Addedcore-js@2.6.12(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddelayed-stream@0.0.5(transitive)
+ Addedextend@1.2.1(transitive)
+ Addedform-data@0.1.3(transitive)
+ Addedformidable@1.0.14(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedglob@7.2.3(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedjson-refs@0.1.10(transitive)
+ Addedlodash-compat@3.10.2(transitive)
+ Addedlodash.get@4.4.2(transitive)
+ Addedlodash.isequal@4.5.0(transitive)
+ Addedmethods@1.0.1(transitive)
+ Addedmime@1.2.11(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedqs@1.2.0(transitive)
+ Addedreadable-stream@1.0.27-1(transitive)
+ Addedreduce-component@1.0.1(transitive)
+ Addedsprintf-js@1.0.3(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addedsuperagent@0.21.0(transitive)
+ Addedvalidator@10.11.0(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedyamljs@0.2.10(transitive)
+ Addedz-schema@3.25.1(transitive)
- Removedjjv@^1.0.0
- Removedjjve@^0.4.0
- Removedjjv@1.0.2(transitive)
- Removedjjve@0.4.0(transitive)
Updatedcommander@^2.5.0
Updatedpath-to-regexp@^0.2.5
Updatedserve-static@^1.7.1