function createMiddleware(swagger, router, callback) {
// Shift args if needed
if (util.isExpressRouter(swagger)) {
router = swagger;
swagger = callback = undefined;
}
else if (!util.isExpressRouter(router)) {
callback = router;
router = undefined;
}
var middleware = new module.exports.Middleware(router);
if (swagger) {
middleware.init(swagger, callback);
}
return middleware;
}n/a
function DataStore() {
/**
* The Express Application or Router that's used to determine case-sensitivity and/or strict matching
* of collection paths and resource names.
*
* @type {express#Router}
* @protected
*/
this.__router = {};
}n/a
function FileDataStore(baseDir) {
DataStore.call(this);
this.__baseDir = baseDir || process.cwd();
}n/a
function MemoryDataStore() {
DataStore.call(this);
/**
* This implementation of DataStore uses an in-memory array.
* @type {Resource[]}
* @private
*/
this.__resourceStore = [];
}n/a
function Middleware(sharedRouter) {
sharedRouter = util.isExpressRouter(sharedRouter) ? sharedRouter : undefined;
var self = this;
var context = new MiddlewareContext(sharedRouter);
/**
* Initializes the middleware with the given Swagger API.
* This method can be called again to re-initialize with a new or modified API.
*
* @param {string|object} [swagger]
* - The file path or URL of a Swagger 2.0 API spec, in YAML or JSON format.
* Or a valid Swagger API object (see https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#swagger-object).
*
* @param {function} [callback]
* - It will be called when the API has been parsed, validated, and dereferenced, or when an error occurs.
*/
this.init = function(swagger, callback) {
//the swagger variable should only ever be a string or a populated object.
var invalidSwagger = _.isFunction(swagger) || _.isDate(swagger) || _.isEmpty(swagger);
if (invalidSwagger) {
throw new Error('Expected a Swagger file or object');
}
//Need to retrieve the Swagger API and metadata from the Swagger .yaml or .json file.
var parser = new SwaggerParser();
parser.dereference(swagger, function(err, api) {
if (err) {
util.warn(err);
}
context.error = err;
context.api = api;
context.parser = parser;
context.emit('change');
if (_.isFunction(callback)) {
callback(err, self, context.api, context.parser);
}
});
};
/**
* Serves the Swagger API file(s) in JSON and YAML formats,
* so they can be used with third-party front-end tools like Swagger UI and Swagger Editor.
*
* @param {express#Router} [router]
* - Express routing options (e.g. `caseSensitive`, `strict`).
* If an Express Application or Router is passed, then its routing settings will be used.
*
* @param {fileServer.defaultOptions} [options]
* - Options for how the files are served (see {@link fileServer.defaultOptions})
*
* @returns {function[]}
*/
this.files = function(router, options) {
if (arguments.length === 1 && !util.isExpressRouter(router) && !util.isExpressRoutingOptions(router)) {
// Shift arguments
options = router;
router = sharedRouter;
}
return fileServer(context, router, options);
};
/**
* Annotates the HTTP request (the `req` object) with Swagger metadata.
* This middleware populates {@link Request#swagger}.
*
* @param {express#Router} [router]
* - Express routing options (e.g. `caseSensitive`, `strict`).
* If an Express Application or Router is passed, then its routing settings will be used.
*
* @returns {function[]}
*/
this.metadata = function(router) {
return requestMetadata(context, router);
};
/**
* Handles CORS preflight requests and sets CORS headers for all requests
* according the Swagger API definition.
*
* @returns {function[]}
*/
this.CORS = function() {
return CORS();
};
/**
* Parses the HTTP request into typed values.
* This middleware populates {@link Request#params}, {@link Request#headers}, {@link Request#cookies},
* {@link Request#signedCookies}, {@link Request#query}, {@link Request#body}, and {@link Request#files}.
*
* @param {express#Router} [router]
* - An Express Application or Router. If provided, this will be used to register path-param middleware
* via {@link Router#param} (see http://expressjs.com/4x/api.html#router.param).
* If not provided, then path parameters will always be parsed as strings.
*
* @param {requestParser.defaultOptions} [options]
* - Options for each of the request-parsing middleware (see {@link requestParser.defaultOptions})
*
* @returns {function[]}
*/
this.parseRequest = function(router, options) {
if (arguments.length === 1 && !util.isExpressRouter(router) && !util.isExpressRoutingOptions(router)) {
// Shift arguments
options = router;
router = sharedRouter;
}
return req ...n/a
function Resource(path, name, data) {
switch (arguments.length) {
case 0:
this.collection = '';
this.name = '/';
this.data = undefined;
break;
case 1:
this.collection = getCollectionFromPath(path);
this.name = getNameFromPath(path);
this.data = undefined;
break;
case 2:
this.merge(name);
this.collection = getCollectionFromPath(path);
this.name = getNameFromPath(path);
break;
default:
this.collection = normalizeCollection(path);
this.name = normalizeName(name);
this.merge(data);
}
this.createdOn = null;
this.modifiedOn = null;
}n/a
function MiddlewareContext(router) {
events.EventEmitter.call(this);
/**
* Express routing options (e.g. `caseSensitive`, `strict`).
* If set to an Express Application or Router, then its routing settings will be used.
* @type {express#Router}
*/
this.router = router || {};
/**
* The parsed Swagger API
* @type {SwaggerObject}
*/
this.api = null;
/**
* The {@link SwaggerParser} instance that was used to parse the API.
* @type {SwaggerParser}
*/
this.parser = null;
/**
* If the Swagger API contains errors, this will be set
* @type {Error}
*/
this.error = null;
}n/a
function JsonSchema(schema) {
if (!schema) {
throw ono({status: 500}, 'Missing JSON schema');
}
if (schema.type !== undefined && dataTypes.indexOf(schema.type) === -1) {
throw ono({status: 500}, 'Invalid JSON schema type: %s', schema.type);
}
this.schema = schema;
}n/a
function paramParser() {
return [parseSimpleParams, parseFormDataParams, parseBodyParam];
}n/a
function DataStore() {
/**
* The Express Application or Router that's used to determine case-sensitivity and/or strict matching
* of collection paths and resource names.
*
* @type {express#Router}
* @protected
*/
this.__router = {};
}n/a
__openDataStore = function (collection, callback) {}n/a
__saveDataStore = function (collection, resources, callback) {}n/a
delete = function (resources, callback) {
call(this, remove, arguments);
}...
);
// Add custom middleware
app.patch('/pets/:petName', function(req, res, next) {
if (req.body.name !== req.params.petName) {
// The pet's name has changed, so change its URL.
// Start by deleting the old resource
myDB.delete(new Resource(req.path), function(err, pet) {
if (pet) {
// Merge the new data with the old data
pet.merge(req.body);
}
else {
pet = req.body;
}
...deleteCollection = function (collection, callback) {
var self = this;
openCollection(self, collection, function(err, collection, resources) {
if (err) {
doCallback(callback, err);
}
else {
// Remove all resources in the collection
var removed = _.remove(resources, collection.filter(self.__router, true));
if (removed.length > 0) {
// Normalize the collection name
var collectionName = collection.valueOf(self.__router, true);
// Save the changes
self.__saveDataStore(collectionName, resources, function(err) {
if (err) {
doCallback(callback, err);
}
else {
doCallback(callback, null, removed);
}
});
}
else {
doCallback(callback, null, []);
}
}
});
}n/a
get = function (resource, callback) {
var self = this;
if (_.isString(resource)) {
resource = new Resource(resource);
}
openCollection(self, resource, function(err, collection, resources) {
if (err) {
doCallback(callback, err);
}
else {
// Find the resource
resource = _.find(resources, resource.filter(self.__router));
doCallback(callback, null, resource);
}
});
}...
res.set(header, responseHeaders[header]);
}
else {
// Set the header to a sensible default
switch (header) {
case accessControl.allowOrigin:
// By default, allow the origin host. Fallback to wild-card.
res.set(header, req.get('Origin') || '*');
break;
case accessControl.allowMethods:
if (req.swagger && req.swagger.path) {
// Return the allowed methods for this Swagger path
res.set(header, util.getAllowedMethods(req.swagger.path));
}
...getCollection = function (collection, callback) {
var self = this;
openCollection(self, collection, function(err, collection, resources) {
if (err) {
doCallback(callback, err);
}
else {
// Return the resources in the collection
resources = _.filter(resources, collection.filter(self.__router, true));
doCallback(callback, null, resources);
}
});
}n/a
remove = function (resources, callback) {
call(this, remove, arguments);
}n/a
removeCollection = function (collection, callback) {
var self = this;
openCollection(self, collection, function(err, collection, resources) {
if (err) {
doCallback(callback, err);
}
else {
// Remove all resources in the collection
var removed = _.remove(resources, collection.filter(self.__router, true));
if (removed.length > 0) {
// Normalize the collection name
var collectionName = collection.valueOf(self.__router, true);
// Save the changes
self.__saveDataStore(collectionName, resources, function(err) {
if (err) {
doCallback(callback, err);
}
else {
doCallback(callback, null, removed);
}
});
}
else {
doCallback(callback, null, []);
}
}
});
}n/a
save = function (resources, callback) {
call(this, save, arguments);
}...
var app = express();
var middleware = new Middleware(app);
middleware.init(path.join(__dirname, 'PetStore.yaml'), function(err) {
// Create a custom data store with some initial mock data
var myDB = new MemoryDataStore();
myDB.save(
new Resource('/pets/Lassie', {name: 'Lassie', type: 'dog', tags: ['brown', 'white
']}),
new Resource('/pets/Clifford', {name: 'Clifford', type: 'dog', tags: ['red', 'big
']}),
new Resource('/pets/Garfield', {name: 'Garfield', type: 'cat', tags: ['orange']}),
new Resource('/pets/Snoopy', {name: 'Snoopy', type: 'dog', tags: ['black', 'white
']}),
new Resource('/pets/Hello%20Kitty', {name: 'Hello Kitty', type: 'cat', tags: ['white']})
);
...function FileDataStore(baseDir) {
DataStore.call(this);
this.__baseDir = baseDir || process.cwd();
}n/a
__openDataStore = function (collection, callback) {
fs.readFile(getFilePath(this.__baseDir, collection), {encoding: 'utf8'}, function(err, data) {
if (err) {
if (err.code === 'ENOENT') {
// The file doesn't exist yet, so just return an empty array
callback(null, []);
}
else {
callback(err);
}
}
else {
var resources;
try {
// Parse the JSON data into an array of Resource objects
resources = Resource.parse(data);
}
catch (e) {
callback(e);
return;
}
// Call the callback outside of the try..catch block,
// so we don't catch any errors that happen in third-party code
callback(null, resources);
}
});
}n/a
__saveDataStore = function (collection, resources, callback) {
var self = this;
// Create the directory path
mkdirp(getDirectory(this.__baseDir, collection), function(err) {
if (err) {
callback(err);
}
else {
// Write the JSON data to the file
fs.writeFile(getFilePath(self.__baseDir, collection), JSON.stringify(resources, null, 2), callback);
}
});
}n/a
function FileDataStore(baseDir) {
DataStore.call(this);
this.__baseDir = baseDir || process.cwd();
}n/a
function MemoryDataStore() {
DataStore.call(this);
/**
* This implementation of DataStore uses an in-memory array.
* @type {Resource[]}
* @private
*/
this.__resourceStore = [];
}n/a
__openDataStore = function (collection, callback) {
setImmediate(callback, null, this.__resourceStore);
}n/a
__saveDataStore = function (collection, resources, callback) {
try {
this.__resourceStore = Resource.parse(resources);
setImmediate(callback);
}
catch (e) {
callback(e);
}
}n/a
function MemoryDataStore() {
DataStore.call(this);
/**
* This implementation of DataStore uses an in-memory array.
* @type {Resource[]}
* @private
*/
this.__resourceStore = [];
}n/a
function Resource(path, name, data) {
switch (arguments.length) {
case 0:
this.collection = '';
this.name = '/';
this.data = undefined;
break;
case 1:
this.collection = getCollectionFromPath(path);
this.name = getNameFromPath(path);
this.data = undefined;
break;
case 2:
this.merge(name);
this.collection = getCollectionFromPath(path);
this.name = getNameFromPath(path);
break;
default:
this.collection = normalizeCollection(path);
this.name = normalizeName(name);
this.merge(data);
}
this.createdOn = null;
this.modifiedOn = null;
}n/a
parse = function (json) {
if (!_.isString(json)) {
// Convert the data to JSON, to match real-world serialization
json = JSON.stringify(json);
}
json = JSON.parse(json);
var isArray = _.isArray(json);
if (!isArray) {
json = [json];
}
var resources = [];
json.forEach(function(pojo) {
var resource = new Resource(pojo.collection, pojo.name, pojo.data);
resource.createdOn = new Date(pojo.createdOn);
resource.modifiedOn = new Date(pojo.modifiedOn);
resources.push(resource);
});
return isArray ? resources : resources[0];
}...
else if (schema.default === undefined) {
// The parameter is optional, and there's no default value
return undefined;
}
}
try {
return new JsonSchema(schema).parse(value);
}
catch (e) {
throw ono(e, {status: e.status}, 'The "%s" %s parameter is invalid (%j)',
param.name, param.in, value === undefined ? param.default : value);
}
}
...filter = function (router, collectionOnly) {
var myValue = this.valueOf(router, collectionOnly);
return function(resource) {
return myValue === resource.valueOf(router, collectionOnly);
};
}...
* This is useful for setting HTTP headers such as Allow and Access-Control-Allow-Methods.
*
* @param {object} path - A Path object, from the Swagger API.
* @returns {string}
*/
exports.getAllowedMethods = function(path) {
return swaggerMethods
.filter(function(method) { return !!path[method]; })
.join(', ')
.toUpperCase();
};
/**
* Returns the given operation's Response objects that have HTTP response codes between
* the given min and max (inclusive).
...merge = function (other) {
this.modifiedOn = new Date();
var otherData = other ? other instanceof Resource ? other.data : other : other;
// Merge with the other resource's data, if possible; otherwise, overwrite.
if ((_.isArray(this.data) && _.isArray(otherData)) ||
(_.isPlainObject(this.data) && _.isPlainObject(otherData))) {
_.merge(this.data, otherData);
}
else {
this.data = otherData;
}
}...
* @param {fileServer.defaultOptions} [options]
* @returns {function[]}
*/
function fileServer(context, router, options) {
router = router || context.router;
// Override default options
options = _.merge({}, fileServer.defaultOptions, options);
// Only return the middleware that's allowed
var middleware = [];
options.apiPath && middleware.push(serveDereferencedSwaggerFile);
options.rawFilesPath && middleware.push(serveRawSwaggerFiles);
return middleware;
...toString = function () {
return this.collection + this.name;
}...
function parseBoolean(schema, value, propPath) {
// Handle missing, required, and default
value = getValueToValidate(schema, value);
// "Parse" the value
var parsedValue = value;
var stringValue = _(value).toString().toLowerCase();
if (stringValue === 'true') {
parsedValue = true;
}
else if (stringValue === 'false') {
parsedValue = false;
}
...valueOf = function (router, collectionOnly) {
if (router) {
var myValue = collectionOnly ? this.collection : this.toString();
return util.normalizePath(myValue, router);
}
else {
return this.toString();
}
}...
return _(value).toString();
}
}
function sampleDate(schema) {
var min, max;
if (schema.minimum !== undefined) {
min = parseInt(new Date(schema.minimum).valueOf()) + (schema.exclusiveMinimum ? 1 :
0);
}
else {
min = Date.UTC(1970, 0, 1);
min = Math.min(min, new Date(schema.maximum).valueOf()) || min;
}
if (schema.maximum !== undefined) {
...function MiddlewareContext(router) {
events.EventEmitter.call(this);
/**
* Express routing options (e.g. `caseSensitive`, `strict`).
* If set to an Express Application or Router, then its routing settings will be used.
* @type {express#Router}
*/
this.router = router || {};
/**
* The parsed Swagger API
* @type {SwaggerObject}
*/
this.api = null;
/**
* The {@link SwaggerParser} instance that was used to parse the API.
* @type {SwaggerParser}
*/
this.parser = null;
/**
* If the Swagger API contains errors, this will be set
* @type {Error}
*/
this.error = null;
}n/a
function addListener(type, listener) {
return _addListener(this, type, listener, false);
}n/a
function emit(type) {
var er, handler, len, args, i, events, domain;
var needDomainExit = false;
var doError = (type === 'error');
events = this._events;
if (events)
doError = (doError && events.error == null);
else if (!doError)
return false;
domain = this.domain;
// If there is no 'error' event listener then throw.
if (doError) {
er = arguments[1];
if (domain) {
if (!er)
er = new Error('Uncaught, unspecified "error" event');
er.domainEmitter = this;
er.domain = domain;
er.domainThrown = false;
domain.emit('error', er);
} else if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
return false;
}
handler = events[type];
if (!handler)
return false;
if (domain && this !== process) {
domain.enter();
needDomainExit = true;
}
var isFn = typeof handler === 'function';
len = arguments.length;
switch (len) {
// fast cases
case 1:
emitNone(handler, isFn, this);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
break;
case 3:
emitTwo(handler, isFn, this, arguments[1], arguments[2]);
break;
case 4:
emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}
if (needDomainExit)
domain.exit();
return true;
}...
if (err) {
util.warn(err);
}
context.error = err;
context.api = api;
context.parser = parser;
context.emit('change');
if (_.isFunction(callback)) {
callback(err, self, context.api, context.parser);
}
});
};
...function eventNames() {
return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
}n/a
function getMaxListeners() {
return $getMaxListeners(this);
}n/a
function listenerCount(type) {
const events = this._events;
if (events) {
const evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener) {
return evlistener.length;
}
}
return 0;
}n/a
function listeners(type) {
var evlistener;
var ret;
var events = this._events;
if (!events)
ret = [];
else {
evlistener = events[type];
if (!evlistener)
ret = [];
else if (typeof evlistener === 'function')
ret = [evlistener];
else
ret = arrayClone(evlistener, evlistener.length);
}
return ret;
}n/a
function addListener(type, listener) {
return _addListener(this, type, listener, false);
}...
router = util.isExpressRouter(router) ? router : context.router;
if (util.isExpressRouter(router)) {
// This is special path-param middleware, which sets `req.params`
registerPathParamMiddleware();
// If the API changes, register any new path-params
context.on('change', registerPathParamMiddleware);
}
else {
util.debug(
'WARNING! An Express Router/Application was not passed to the requestParser middleware. ' +
'req.params will not be parsed. Use req.pathParams instead.'
);
}
...function once(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.on(type, _onceWrap(this, type, listener));
return this;
}n/a
function prependListener(type, listener) {
return _addListener(this, type, listener, true);
}n/a
function prependOnceListener(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.prependListener(type, _onceWrap(this, type, listener));
return this;
}n/a
function removeAllListeners(type) {
var listeners, events;
events = this._events;
if (!events)
return this;
// not listening for removeListener, no need to emit
if (!events.removeListener) {
if (arguments.length === 0) {
this._events = new EventHandlers();
this._eventsCount = 0;
} else if (events[type]) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
for (var i = 0, key; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = new EventHandlers();
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
do {
this.removeListener(type, listeners[listeners.length - 1]);
} while (listeners[0]);
}
return this;
}n/a
function removeListener(type, listener) {
var list, events, position, i, originalListener;
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
events = this._events;
if (!events)
return this;
list = events[type];
if (!list)
return this;
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
position = -1;
for (i = list.length; i-- > 0;) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list[0] = undefined;
if (--this._eventsCount === 0) {
this._events = new EventHandlers();
return this;
} else {
delete events[type];
}
} else {
spliceOne(list, position);
}
if (events.removeListener)
this.emit('removeListener', type, originalListener || listener);
}
return this;
}n/a
function setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || isNaN(n))
throw new TypeError('"n" argument must be a positive number');
this._maxListeners = n;
return this;
}n/a
function JsonSchema(schema) {
if (!schema) {
throw ono({status: 500}, 'Missing JSON schema');
}
if (schema.type !== undefined && dataTypes.indexOf(schema.type) === -1) {
throw ono({status: 500}, 'Invalid JSON schema type: %s', schema.type);
}
this.schema = schema;
}n/a
parse = function (value, propPath) {
switch (this.schema.type) {
case 'number':
return parseNumber(this.schema, value, propPath);
case 'integer':
return parseInteger(this.schema, value, propPath);
case 'boolean':
return parseBoolean(this.schema, value, propPath);
case 'array':
return parseArray(this.schema, value, propPath);
case 'object':
case undefined:
return parseObject(this.schema, value, propPath);
case 'file':
return parseFile(this.schema, value, propPath);
case 'string':
switch (this.schema.format) {
case 'byte':
return parseInteger(this.schema, value, propPath);
case 'date':
case 'date-time':
return parseDate(this.schema, value, propPath);
default:
return parseString(this.schema, value, propPath);
}
}
}...
else if (schema.default === undefined) {
// The parameter is optional, and there's no default value
return undefined;
}
}
try {
return new JsonSchema(schema).parse(value);
}
catch (e) {
throw ono(e, {status: e.status}, 'The "%s" %s parameter is invalid (%j)',
param.name, param.in, value === undefined ? param.default : value);
}
}
...sample = function () {
switch (this.schema.type) {
case 'number':
return sampleNumber(this.schema);
case 'integer':
return sampleInteger(this.schema);
case 'boolean':
return sampleBoolean(this.schema);
case 'array':
return sampleArray(this.schema);
case 'object':
case undefined:
return sampleObject(this.schema);
case 'string':
switch (this.schema.format) {
case 'byte':
return sampleInteger(this.schema);
case 'date':
case 'date-time':
return sampleDate(this.schema);
default:
return sampleString(this.schema);
}
}
}...
maxItems = Math.max(50, minItems);
}
var array = [];
var itemSchema = new JsonSchema(schema.items);
var length = _.random(minItems, maxItems);
for (var i = 0; i < length; i++) {
array.push(itemSchema.sample());
}
return array;
}
function parseObject(schema, value, propPath) {
// Handle missing, required, and default
...serialize = function (value, propPath) {
switch (this.schema.type) {
case 'number':
return serializeNumber(this.schema, value, propPath);
case 'integer':
return serializeInteger(this.schema, value, propPath);
case 'boolean':
return serializeBoolean(this.schema, value, propPath);
case 'array':
return serializeArray(this.schema, value, propPath);
case 'object':
case undefined:
return serializeObject(this.schema, value, propPath);
case 'file':
return serializeFile(this.schema, value, propPath);
case 'string':
switch (this.schema.format) {
case 'byte':
return serializeInteger(this.schema, value, propPath);
case 'date':
case 'date-time':
return serializeDate(this.schema, value, propPath);
default:
return serializeString(this.schema, value, propPath);
}
}
}...
function serializeArray(schema, value, propPath) {
value = getValueToValidate(schema, value);
if (_.isArray(value) && schema.items) {
var itemSchema = new JsonSchema(schema.items);
for (var i = 0; i < value.length; i++) {
value[i] = itemSchema.serialize(value[i], propPath + '[' + i + ']
x27;);
}
}
return value;
}
function sampleArray(schema) {
...function paramParser() {
return [parseSimpleParams, parseFormDataParams, parseBodyParam];
}n/a
function parseParameter(param, value, schema) {
if (value === undefined) {
if (param.required) {
// The parameter is required, but was not provided, so throw a 400 error
var errCode = 400;
if (param.in === 'header' && param.name.toLowerCase() === 'content-length') {
// Special case for the Content-Length header. It has it's own HTTP error code.
errCode = 411; // (Length Required)
}
//noinspection ExceptionCaughtLocallyJS
throw ono({status: errCode}, 'Missing required %s parameter "%s"', param.in, param.name);
}
else if (schema.default === undefined) {
// The parameter is optional, and there's no default value
return undefined;
}
}
try {
return new JsonSchema(schema).parse(value);
}
catch (e) {
throw ono(e, {status: e.status}, 'The "%s" %s parameter is invalid (%j)',
param.name, param.in, value === undefined ? param.default : value);
}
}...
// Parse each path param
for (var i = 1; i < values.length; i++) {
var paramName = paramNames[i - 1];
var paramValue = decodeURIComponent(values[i]);
var param = _.find(req.swagger.params, {in: 'path', name: paramName});
util.debug(' Parsing the "%s" path parameter', paramName);
req.pathParams[paramName] = paramParser.parseParameter(param, paramValue, param
);
}
}
}
next();
}
}
...function debug() {
// disabled?
if (!debug.enabled) return;
var self = debug;
// set `diff` timestamp
var curr = +new Date();
var ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
// turn the `arguments` into a proper Array
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
args[0] = exports.coerce(args[0]);
if ('string' !== typeof args[0]) {
// anything else let's inspect with %O
args.unshift('%O');
}
// apply any `formatters` transformations
var index = 0;
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
// if we encounter an escaped % then don't increase the array index
if (match === '%%') return match;
index++;
var formatter = exports.formatters[format];
if ('function' === typeof formatter) {
var val = args[index];
match = formatter.call(self, val);
// now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
// apply env-specific formatting (colors, etc.)
exports.formatArgs.call(self, args);
var logFn = debug.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}...
}
/**
* Handles CORS preflight requests.
*/
function corsPreflight(req, res, next) {
if (req.method === 'OPTIONS') {
util.debug('OPTIONS %s is a CORS preflight request. Sending HTTP 200 response
.', req.path);
res.send();
}
else {
next();
}
}
...getAllowedMethods = function (path) {
return swaggerMethods
.filter(function(method) { return !!path[method]; })
.join(', ')
.toUpperCase();
}...
// By default, allow the origin host. Fallback to wild-card.
res.set(header, req.get('Origin') || '*');
break;
case accessControl.allowMethods:
if (req.swagger && req.swagger.path) {
// Return the allowed methods for this Swagger path
res.set(header, util.getAllowedMethods(req.swagger.path));
}
else {
// By default, allow all of the requested methods. Fallback to ALL methods.
res.set(header, req.get('Access-Control-Request-Method') || swaggerMethods.join(', ').toUpperCase());
}
break;
...getParameters = function (path, operation) {
var pathParams = [], operationParams = [];
// Get the path and operation parameters
if (path && path.parameters) {
pathParams = path.parameters;
}
if (operation && operation.parameters) {
operationParams = operation.parameters;
}
// Combine the path and operation parameters,
// with the operation params taking precedence over the path params
return _.unique(operationParams.concat(pathParams), function(param) {
return param.name + param.in;
});
}...
next();
}
/**
* Sets `req.swagger.params`
*/
function swaggerParamsMetadata(req, res, next) {
req.swagger.params = util.getParameters(req.swagger.path, req.swagger.operation);
next();
}
/**
* Sets `req.swagger.security`
*/
function swaggerSecurityMetadata(req, res, next) {
...getRequestSchema = function (path, operation) {
var params = exports.getParameters(path, operation);
// If there's a "body" parameter, then use its schema
var bodyParam = _.find(params, {in: 'body'});
if (bodyParam) {
if (bodyParam.schema.type === 'array') {
return bodyParam.schema.items;
}
else {
return bodyParam.schema;
}
}
else {
var schema = {type: 'object', required: [], properties: {}};
// If there are "formData" parameters, then concatenate them into a single JSON schema
_.where(params, {in: 'formData'}).forEach(function(param) {
schema.properties[param.name] = param;
if (param.required) {
schema.required.push(param.name);
}
});
return schema;
}
}n/a
getResponsesBetween = function (operation, min, max) {
return _.map(operation.responses,
function(response, responseCode) {
return {
code: parseInt(responseCode) || responseCode,
api: response
};
})
.sort(function(a, b) {
// Sort by response code. "default" comes last.
a = _.isNumber(a.code) ? a.code : 999;
b = _.isNumber(b.code) ? b.code : 999;
return a - b;
})
.filter(function(response) {
return (response.code >= min && response.code <= max) || _.isString(response.code);
});
}n/a
isExpressApp = function (router) {
return exports.isExpressRouter(router) &&
_.isFunction(router.get) &&
_.isFunction(router.set) &&
_.isFunction(router.enabled) &&
_.isFunction(router.disabled);
}...
exports.normalizePath = function(path, router) {
var caseSensitive, strict;
if (!path) {
return '';
}
if (exports.isExpressApp(router)) {
caseSensitive = router.enabled('case sensitive routing');
strict = router.enabled('strict routing');
}
else {
// This could be an Express Router, or a POJO
caseSensitive = !!router.caseSensitive;
strict = !!router.strict;
...isExpressRouter = function (router) {
return _.isFunction(router) &&
_.isFunction(router.param);
}...
* - An Express Application or Router. If provided, this will be used to determine routing settings
* (case sensitivity, strictness), and to register path-param middleware via {@link Router#param}
* (see http://expressjs.com/4x/api.html#router.param).
*
* @constructor
*/
function Middleware(sharedRouter) {
sharedRouter = util.isExpressRouter(sharedRouter) ? sharedRouter : undefined;
var self = this;
var context = new MiddlewareContext(sharedRouter);
/**
* Initializes the middleware with the given Swagger API.
* This method can be called again to re-initialize with a new or modified API.
...isExpressRoutingOptions = function (router) {
return _.isObject(router) &&
('caseSensitive' in router || 'strict' in router || 'mergeParams' in router);
}...
*
* @param {fileServer.defaultOptions} [options]
* - Options for how the files are served (see {@link fileServer.defaultOptions})
*
* @returns {function[]}
*/
this.files = function(router, options) {
if (arguments.length === 1 && !util.isExpressRouter(router) && !util.isExpressRoutingOptions
(router)) {
// Shift arguments
options = router;
router = sharedRouter;
}
return fileServer(context, router, options);
};
...isSwaggerRequest = function (req) {
// If req.swagger.operation is set, then so are req.swagger.api and req.swagger.path
return req.swagger && req.swagger.operation;
}...
}
/**
* Parses all Swagger path parameters and sets `req.pathParams`.
* NOTE: This middleware cannot set `req.params`. That requires special path-param middleware (see above)
*/
function parsePathParams(req, res, next) {
if (util.isSwaggerRequest(req)) {
req.pathParams = {};
if (req.swagger.pathName.indexOf('{') >= 0) {
// Convert the Swagger path to a RegExp
var paramNames = [];
var pathPattern = req.swagger.pathName.replace(util.swaggerParamRegExp, function(match, paramName) {
paramNames.push(paramName);
...normalizePath = function (path, router) {
var caseSensitive, strict;
if (!path) {
return '';
}
if (exports.isExpressApp(router)) {
caseSensitive = router.enabled('case sensitive routing');
strict = router.enabled('strict routing');
}
else {
// This could be an Express Router, or a POJO
caseSensitive = !!router.caseSensitive;
strict = !!router.strict;
}
if (!caseSensitive) {
path = path.toLowerCase();
}
if (!strict && _.endsWith(path, '/')) {
path = path.substr(0, path.length - 1);
}
return path;
}...
/**
* Serves the fully-dereferenced Swagger API in JSON format.
*/
function serveDereferencedSwaggerFile(req, res, next) {
if (req.method === 'GET' || req.method === 'HEAD') {
var configPath = getConfiguredPath(options.apiPath);
configPath = util.normalizePath(configPath, router);
var reqPath = util.normalizePath(req.path, router);
if (reqPath === configPath) {
if (context.api) {
util.debug('%s %s => Sending the Swagger API as JSON', req.method, req.path);
res.json(context.api);
}
...rfc1123 = function (date) {
// jscs:disable maximumLineLength
var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getUTCDay()];
var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getUTCMonth()];
return [
dayName, ', ', _.padLeft(date.getUTCDate(), 2, '0'), ' ', monthName, ' ', date.getUTCFullYear(), ' ',
_.padLeft(date.getUTCHours(), 2, '0'), ':', _.padLeft(date.getUTCMinutes(), 2, '0'), ':', _.padLeft(date.getUTCSeconds(), 2, '
0'), ' GMT'
].join('');
// jscs:enable maximumLineLength
}n/a
warn = function (err, message, params) {
if (process.env.WARN !== 'off') {
if (_.isString(err)) {
console.warn(format.apply(null, arguments));
}
else if (arguments.length > 1) {
console.warn(format.apply(null, _.drop(arguments, 1)) + ' \n' + err.stack);
}
else {
console.warn(err.stack);
}
}
}...
if (reqPath === configPath) {
if (context.api) {
util.debug('%s %s => Sending the Swagger API as JSON', req.method, req.path);
res.json(context.api);
}
else {
util.warn('WARNING! The Swagger API is empty. Sending an HTTP 500 response
to %s %s', req.method, req.path);
res.status(500).json({});
}
return;
}
}
next();
...