swagger-node-express
Advanced tools
@@ -30,3 +30,3 @@ /** | ||
exports.path = function(name, description, dataType, allowableValues) { | ||
exports.path = function(name, description, dataType, allowableValues, defaultValue) { | ||
return { | ||
@@ -39,11 +39,15 @@ "name" : name, | ||
"allowableValues" : allowableValues, | ||
"paramType" : "path" | ||
"paramType" : "path", | ||
"defaultValue" : defaultValue | ||
}; | ||
}; | ||
exports.post = function(dataType, description, defaultValue) { | ||
exports.body = function(name, description, dataType, defaultValue) { | ||
return { | ||
"name" : name, | ||
"description" : description, | ||
"dataType" : dataType, | ||
"required" : true, | ||
"allowMultiple" : false, | ||
"paramType" : "body", | ||
@@ -54,2 +58,14 @@ "defaultValue" : defaultValue | ||
exports.form = function(name, description, dataType, defaultValue) { | ||
return { | ||
"name" : name, | ||
"description" : description, | ||
"dataType" : "string", | ||
"required" : true, | ||
"allowMultiple" : false, | ||
"paramType" : "form", | ||
"defaultValue" : defaultValue | ||
}; | ||
}; | ||
exports.header = function(name, description, dataType, required) { | ||
@@ -60,6 +76,6 @@ return { | ||
"dataType" : dataType, | ||
"required" : true, | ||
"required" : required, | ||
"allowMultiple" : false, | ||
"paramType" : "header" | ||
}; | ||
}; | ||
}; |
@@ -16,3 +16,3 @@ /** | ||
*/ | ||
var _ = require('lodash'); | ||
var formatString = ".{format}"; | ||
@@ -27,3 +27,3 @@ var resourcePath = "/api-docs" + formatString; | ||
var appHandler = null; | ||
var allowedMethods = ['get', 'post', 'put', 'delete']; | ||
var allowedMethods = ['get', 'post', 'put', 'patch', 'delete']; | ||
var allowedDataTypes = ['string', 'int', 'long', 'double', 'boolean', 'date', 'array']; | ||
@@ -33,2 +33,15 @@ var params = require(__dirname + '/paramTypes.js'); | ||
// Default error handler | ||
var errorHandler = function (req, res, error) { | ||
if (error.code && error.reason) | ||
res.send(JSON.stringify(error), error.code); | ||
else { | ||
console.error(req.method + " failed for path '" + require('url').parse(req.url).href + "': " + error); | ||
res.send(JSON.stringify({ | ||
"reason": "unknown error", | ||
"code": 500 | ||
}), 500); | ||
} | ||
}; | ||
function configureSwaggerPaths(format, path, suffix) { | ||
@@ -42,2 +55,3 @@ formatString = format; | ||
// subdocuments. It should only be done once, and during bootstrap of the app | ||
function configure(bp, av) { | ||
@@ -52,13 +66,13 @@ basePath = bp; | ||
for(key in resources) { | ||
var r = resources[key]; | ||
r.apiVersion = av; | ||
r.basePath = bp; | ||
} | ||
_.forOwn(resources, function (resource) { | ||
resource.apiVersion = av; | ||
resource.basePath = bp; | ||
}); | ||
} | ||
// Convenience to set default headers in each response. | ||
function setHeaders(res) { | ||
res.header('Access-Control-Allow-Origin', "*"); | ||
res.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); | ||
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE"); | ||
res.header("Access-Control-Allow-Headers", "Content-Type, api_key"); | ||
@@ -69,8 +83,10 @@ res.header("Content-Type", "application/json; charset=utf-8"); | ||
// creates declarations for each resource path. | ||
function setResourceListingPaths(app) { | ||
for (var key in resources) { | ||
_.forOwn(resources, function (resource, key) { | ||
// pet.json => api-docs.json/pet | ||
var path = baseApiFromPath(key); | ||
app.get(path, function(req, res) { | ||
app.get(path, function (req, res) { | ||
// find the api base path from the request URL | ||
@@ -86,5 +102,7 @@ // /api-docs.json/pet => /pet.json | ||
console.error("unable to find listing"); | ||
return stopWithError(res, {'description': 'internal error', 'code': 500}); | ||
} | ||
else { | ||
return stopWithError(res, { | ||
'reason': 'internal error', | ||
'code': 500 | ||
}); | ||
} else { | ||
exports.setHeaders(res); | ||
@@ -94,4 +112,4 @@ var data = filterApiListing(req, res, r); | ||
if (data.code) { | ||
res.send(data, data.code); } | ||
else { | ||
res.send(data, data.code); | ||
} else { | ||
res.send(JSON.stringify(filterApiListing(req, res, r))); | ||
@@ -101,3 +119,3 @@ } | ||
}); | ||
} | ||
}); | ||
} | ||
@@ -118,47 +136,46 @@ | ||
// methods and models that the user actually has access to. | ||
function filterApiListing(req, res, r) { | ||
var route = req.route; | ||
var excludedPaths = []; | ||
if (!r || !r.apis) { | ||
return stopWithError(res, {'description': 'internal error', 'code': 500}); | ||
return stopWithError(res, { | ||
'reason': 'internal error', | ||
'code': 500 | ||
}); | ||
} | ||
for (var key in r.apis) { | ||
var api = r.apis[key]; | ||
_.forOwn(r.apis, function (api) { | ||
for (var opKey in api.operations) { | ||
if (!api.operations.hasOwnProperty(opKey)) { | ||
continue; | ||
} | ||
var op = api.operations[opKey]; | ||
var path = api.path.replace(formatString, "").replace(/{.*\}/, "*"); | ||
if (!canAccessResource(req, path, op.httpMethod)) { | ||
excludedPaths.push(op.httpMethod + ":" + api.path); } | ||
excludedPaths.push(op.httpMethod + ":" + api.path); | ||
} | ||
} | ||
} | ||
}); | ||
// clone attributes in the resource | ||
var output = shallowClone(r); | ||
// models required in the api listing | ||
var requiredModels = []; | ||
// clone methods that user can access | ||
output.apis = []; | ||
var apis = JSON.parse(JSON.stringify(r.apis)); | ||
for (var i in apis) { | ||
var api = apis[i]; | ||
_.forOwn(apis, function (api) { | ||
var clonedApi = shallowClone(api); | ||
clonedApi.operations = []; | ||
var shouldAdd = true; | ||
for (var o in api.operations) { | ||
var operation = api.operations[o]; | ||
if (excludedPaths.indexOf(operation.httpMethod + ":" + api.path) >= 0) { | ||
break; | ||
} | ||
else { | ||
_.forOwn(api.operations, function (operation) { | ||
if (!excludedPaths.indexOf(operation.httpMethod + ":" + api.path) >= 0) { | ||
clonedApi.operations.push(JSON.parse(JSON.stringify(operation))); | ||
addModelsFromPost(operation, requiredModels); | ||
addModelsFromBody(operation, requiredModels); | ||
addModelsFromResponse(operation, requiredModels); | ||
} | ||
} | ||
}); | ||
// only add cloned api if there are operations | ||
@@ -168,24 +185,23 @@ if (clonedApi.operations.length > 0) { | ||
} | ||
} | ||
}); | ||
// add required models to output | ||
output.models = {}; | ||
for (var i in requiredModels){ | ||
var modelName = requiredModels[i]; | ||
var model = allModels.models[modelName]; | ||
if(model){ | ||
output.models[requiredModels[i]] = model; | ||
_.forOwn(requiredModels, function (modelName) { | ||
var model = allModels[modelName]; | ||
if (model) { | ||
output.models[modelName] = model; | ||
} | ||
} | ||
}); | ||
// look in object graph | ||
for (key in output.models) { | ||
var model = output.models[key]; | ||
_.forOwn(output.models, function (model) { | ||
if (model && model.properties) { | ||
for (var key in model.properties) { | ||
var t = model.properties[key].type; | ||
_.forOwn(model.properties, function (property) { | ||
var type = property.type; | ||
switch (t){ | ||
switch (type) { | ||
case "array": | ||
case "Array": | ||
if (model.properties[key].items) { | ||
var ref = model.properties[key].items.$ref; | ||
if (property.items) { | ||
var ref = property.items.$ref; | ||
if (ref && requiredModels.indexOf(ref) < 0) { | ||
@@ -200,19 +216,18 @@ requiredModels.push(ref); | ||
default: | ||
if (requiredModels.indexOf(t) < 0) { | ||
requiredModels.push(t); | ||
if (requiredModels.indexOf(type) < 0) { | ||
requiredModels.push(type); | ||
} | ||
break; | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
for (var i in requiredModels){ | ||
var modelName = requiredModels[i]; | ||
if(!output[modelName]) { | ||
var model = allModels.models[modelName]; | ||
if(model){ | ||
output.models[requiredModels[i]] = model; | ||
}); | ||
_.forOwn(requiredModels, function (modelName) { | ||
if (!output[modelName]) { | ||
var model = allModels[modelName]; | ||
if (model) { | ||
output.models[modelName] = model; | ||
} | ||
} | ||
} | ||
}); | ||
return output; | ||
@@ -222,33 +237,22 @@ } | ||
// Add model to list and parse List[model] elements | ||
function addModelsFromPost(operation, models){ | ||
if(operation.parameters) { | ||
for(var i in operation.parameters) { | ||
var param = operation.parameters[i]; | ||
if(param.paramType == "body" && param.dataType) { | ||
var model = param.dataType.replace(/^List\[/,"").replace(/\]/,""); | ||
if(models.indexOf(model) < 0) { | ||
models.push(responseModel); | ||
} | ||
models.push(param.dataType); | ||
function addModelsFromBody(operation, models) { | ||
if (operation.parameters) { | ||
_.forOwn(operation.parameters, function (param) { | ||
if (param.paramType == "body" && param.dataType) { | ||
var model = param.dataType.replace(/^List\[/, "").replace(/\]/, ""); | ||
models.push(model); | ||
} | ||
} | ||
}); | ||
} | ||
var responseModel = operation.responseClass; | ||
if (responseModel) { | ||
responseModel = responseModel.replace(/^List\[/,"").replace(/\]/,""); | ||
if (models.indexOf(responseModel) < 0) { | ||
models.push(responseModel); | ||
} | ||
} | ||
} | ||
// Add model to list and parse List[model] elements | ||
// Add model to list and parse List[model] elements | ||
function addModelsFromResponse(operation, models){ | ||
function addModelsFromResponse(operation, models) { | ||
var responseModel = operation.responseClass; | ||
if (responseModel) { | ||
responseModel = responseModel.replace(/^List\[/,"").replace(/\]/,""); | ||
responseModel = responseModel.replace(/^List\[/, "").replace(/\]/, ""); | ||
if (models.indexOf(responseModel) < 0) { | ||
models.push(responseModel); | ||
models.push(responseModel); | ||
} | ||
@@ -259,5 +263,9 @@ } | ||
// clone anything but objects to avoid shared references | ||
function shallowClone(obj) { | ||
var cloned = {}; | ||
for (var i in obj) { | ||
if (!obj.hasOwnProperty(i)) { | ||
continue; | ||
} | ||
if (typeof (obj[i]) != "object") { | ||
@@ -272,6 +280,9 @@ cloned[i] = obj[i]; | ||
// if consumer can access the resource, method returns true. | ||
function canAccessResource(req, path, httpMethod) { | ||
for (var i in validators) { | ||
if (!validators[i](req,path,httpMethod)) | ||
for (var i = 0; i < validators.length; i++) { | ||
var validator = validators[i]; | ||
if (_.isFunction(validator) && !validator(req, path, httpMethod)) { | ||
return false; | ||
} | ||
} | ||
@@ -283,18 +294,22 @@ return true; | ||
* returns the json representation of a resource | ||
* | ||
* | ||
* @param request | ||
* @param response | ||
*/ | ||
function resourceListing(req, res) { | ||
var r = { | ||
"apiVersion" : apiVersion, | ||
"swaggerVersion" : swaggerVersion, | ||
"basePath" : basePath, | ||
"apis" : [] | ||
"apiVersion": apiVersion, | ||
"swaggerVersion": swaggerVersion, | ||
"basePath": basePath, | ||
"apis": [] | ||
}; | ||
for (var key in resources) { | ||
var p = resourcePath + "/" + key.replace(formatString,""); | ||
r.apis.push({"path": p, "description": "none"}); | ||
} | ||
_.forOwn(resources, function (value, key) { | ||
var p = resourcePath + "/" + key.replace(formatString, ""); | ||
r.apis.push({ | ||
"path": p, | ||
"description": "none" | ||
}); | ||
}); | ||
@@ -307,2 +322,3 @@ exports.setHeaders(res); | ||
// Adds a method to the api along with a spec. If the spec fails to validate, it won't be added | ||
function addMethod(app, callback, spec) { | ||
@@ -314,4 +330,3 @@ var apiRootPath = spec.path.split("/")[1]; | ||
// this path already exists in swagger resources | ||
for (var key in root.apis) { | ||
var api = root.apis[key]; | ||
_.forOwn(root.apis, function (api) { | ||
if (api && api.path == spec.path && api.method == spec.method) { | ||
@@ -322,12 +337,19 @@ // add operation & return | ||
} | ||
} | ||
}); | ||
} | ||
var api = {"path" : spec.path}; | ||
var api = { | ||
"path": spec.path | ||
}; | ||
if (!resources[apiRootPath]) { | ||
if (!root) { | ||
// | ||
var resourcePath = "/" + apiRootPath.replace(formatString, ""); | ||
var resourcePath = "/" + apiRootPath.replace(formatString, ""); | ||
root = { | ||
"apiVersion" : apiVersion, "swaggerVersion": swaggerVersion, "basePath": basePath, "resourcePath": resourcePath, "apis": [], "models" : [] | ||
"apiVersion": apiVersion, | ||
"swaggerVersion": swaggerVersion, | ||
"basePath": basePath, | ||
"resourcePath": resourcePath, | ||
"apis": [], | ||
"models": [] | ||
}; | ||
@@ -342,6 +364,6 @@ } | ||
// convert .{format} to .json, make path params happy | ||
var fullPath = spec.path.replace(formatString, jsonSuffix).replace(/\/{/g, "/:").replace(/\}/g,""); | ||
var fullPath = spec.path.replace(formatString, jsonSuffix).replace(/\/{/g, "/:").replace(/\}/g, ""); | ||
var currentMethod = spec.method.toLowerCase(); | ||
if (allowedMethods.indexOf(currentMethod)>-1) { | ||
app[currentMethod](fullPath, function(req,res) { | ||
if (allowedMethods.indexOf(currentMethod) > -1) { | ||
app[currentMethod](fullPath, function (req, res) { | ||
exports.setHeaders(res); | ||
@@ -352,19 +374,20 @@ | ||
if (!canAccessResource(req, path, req.method)) { | ||
res.send(JSON.stringify({"description":"forbidden", "code":403}), 403); | ||
} else { | ||
res.send(JSON.stringify({ | ||
"reason": "forbidden", | ||
"code": 403 | ||
}), 403); | ||
} else { | ||
try { | ||
callback(req,res); | ||
} | ||
catch (ex) { | ||
if (ex.code && ex.description) | ||
res.send(JSON.stringify(ex), ex.code); | ||
else { | ||
console.error(spec.method + " failed for path '" + require('url').parse(req.url).href + "': " + ex); | ||
res.send(JSON.stringify({"description":"unknown error","code":500}), 500); | ||
callback(req, res); | ||
} catch (error) { | ||
if (typeof errorHandler === "function") { | ||
errorHandler(req, res, error); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
} else { | ||
console.error('unable to add ' + currentMethod.toUpperCase() + ' handler'); | ||
console.error('unable to add ' + currentMethod.toUpperCase() + ' handler'); | ||
return; | ||
@@ -375,2 +398,3 @@ } | ||
// Set expressjs app handler | ||
function setAppHandler(app) { | ||
@@ -380,23 +404,31 @@ appHandler = app; | ||
// Change error handler | ||
// Error handler should be a function that accepts parameters req, res, error | ||
function setErrorHandler(handler) { | ||
errorHandler = handler; | ||
} | ||
// Add swagger handlers to express | ||
function addHandlers(type, handlers) { | ||
for (var i = 0; i < handlers.length; i++) { | ||
var handler = handlers[i]; | ||
_.forOwn(handlers, function (handler) { | ||
handler.spec.method = type; | ||
addMethod(appHandler, handler.action, handler.spec); | ||
} | ||
}); | ||
} | ||
// Discover swagger handler from resource | ||
function discover(resource) { | ||
for (var key in resource) { | ||
if (resource[key].spec && resource[key].spec.method && allowedMethods.indexOf(resource[key].spec.method.toLowerCase())>-1) { | ||
addMethod(appHandler, resource[key].action, resource[key].spec); | ||
} | ||
else | ||
console.error('auto discover failed for: ' + key); | ||
} | ||
_.forOwn(resource, function (handler, key) { | ||
if (handler.spec && handler.spec.method && allowedMethods.indexOf(handler.spec.method.toLowerCase()) > -1) { | ||
addMethod(appHandler, handler.action, handler.spec); | ||
} else | ||
console.error('auto discover failed for: ' + key); | ||
}); | ||
} | ||
// Discover swagger handler from resource file path | ||
function discoverFile(file) { | ||
@@ -407,2 +439,3 @@ return discover(require(file)); | ||
// adds get handler | ||
function addGet() { | ||
@@ -414,2 +447,3 @@ addHandlers('GET', arguments); | ||
// adds post handler | ||
function addPost() { | ||
@@ -421,3 +455,4 @@ addHandlers('POST', arguments); | ||
// adds delete handler | ||
function addDelete() { | ||
function addDelete() { | ||
addHandlers('DELETE', arguments); | ||
@@ -428,2 +463,3 @@ return this; | ||
// adds put handler | ||
function addPut() { | ||
@@ -434,10 +470,33 @@ addHandlers('PUT', arguments); | ||
// adds patch handler | ||
function addPatch() { | ||
addHandlers('PATCH', arguments); | ||
return this; | ||
} | ||
// adds models to swagger | ||
function addModels(models) { | ||
if(!allModels['models']) { | ||
models = _.cloneDeep(models); | ||
if (!allModels) { | ||
allModels = models; | ||
} else { | ||
for(k in models['models']) { | ||
allModels['models'][k] = models['models'][k]; | ||
} | ||
_.forOwn(models, function (model, key) { | ||
var required = model.required; | ||
_.forOwn(model.properties, function (property, propertyKey) { | ||
// convert enum to allowableValues | ||
if (typeof property.enum !== 'undefined') { | ||
property.allowableValues = { | ||
"valueType": "LIST", | ||
"values": property.enum | ||
} | ||
} | ||
// convert existence in v4 required array to required attribute | ||
if (required && required.indexOf(propertyKey) > -1) { | ||
property.required = true; | ||
} | ||
}); | ||
allModels[key] = model; | ||
}); | ||
} | ||
@@ -447,48 +506,70 @@ return this; | ||
function wrap(callback, req, resp){ | ||
callback(req,resp); | ||
function wrap(callback, req, resp) { | ||
callback(req, resp); | ||
} | ||
// appends a spec to an existing operation | ||
function appendToApi(rootResource, api, spec) { | ||
if (!api.description) { | ||
api.description = spec.description; | ||
api.description = spec.description; | ||
} | ||
var validationErrors = []; | ||
if(!spec.nickname || spec.nickname.indexOf(" ")>=0){ | ||
if (!spec.nickname || spec.nickname.indexOf(" ") >= 0) { | ||
// nicknames don't allow spaces | ||
validationErrors.push({"path": api.path, "error": "invalid nickname '" + spec.nickname + "'"}); | ||
} | ||
validationErrors.push({ | ||
"path": api.path, | ||
"error": "invalid nickname '" + spec.nickname + "'" | ||
}); | ||
} | ||
// validate params | ||
for ( var paramKey in spec.params) { | ||
var param = spec.params[paramKey]; | ||
if(param.allowableValues) { | ||
_.forOwn(spec.params, function (param) { | ||
if (param.allowableValues) { | ||
var avs = param.allowableValues.toString(); | ||
var type = avs.split('[')[0]; | ||
if(type == 'LIST'){ | ||
var values = avs.match(/\[(.*)\]/g).toString().replace('\[','').replace('\]', '').split(','); | ||
param.allowableValues = {valueType: type, values: values}; | ||
if (type == 'LIST') { | ||
var values = avs.match(/\[(.*)\]/g).toString().replace('\[', '').replace('\]', '').split(','); | ||
param.allowableValues = { | ||
valueType: type, | ||
values: values | ||
}; | ||
} else if (type == 'RANGE') { | ||
var values = avs.match(/\[(.*)\]/g).toString().replace('\[', '').replace('\]', '').split(','); | ||
param.allowableValues = { | ||
valueType: type, | ||
min: values[0], | ||
max: values[1] | ||
}; | ||
} | ||
else if (type == 'RANGE') { | ||
var values = avs.match(/\[(.*)\]/g).toString().replace('\[','').replace('\]', '').split(','); | ||
param.allowableValues = {valueType: type, min: values[0], max: values[1]}; | ||
} | ||
} | ||
switch (param.paramType) { | ||
case "path": | ||
if (api.path.indexOf("{" + param.name + "}") < 0) { | ||
validationErrors.push({"path": api.path, "name": param.name, "error": "invalid path"}); | ||
} | ||
break; | ||
case "query": | ||
break; | ||
case "body": | ||
break; | ||
default: | ||
validationErrors.push({"path": api.path, "name": param.name, "error": "invalid param type " + param.paramType}); | ||
break; | ||
case "path": | ||
if (api.path.indexOf("{" + param.name + "}") < 0) { | ||
validationErrors.push({ | ||
"path": api.path, | ||
"name": param.name, | ||
"error": "invalid path" | ||
}); | ||
} | ||
break; | ||
case "query": | ||
break; | ||
case "body": | ||
break; | ||
case "form": | ||
break; | ||
case "header": | ||
break; | ||
default: | ||
validationErrors.push({ | ||
"path": api.path, | ||
"name": param.name, | ||
"error": "invalid param type " + param.paramType | ||
}); | ||
break; | ||
} | ||
} | ||
}); | ||
@@ -499,20 +580,25 @@ if (validationErrors.length > 0) { | ||
} | ||
if (!api.operations) { | ||
api.operations = []; } | ||
api.operations = []; | ||
} | ||
// TODO: replace if existing HTTP operation in same api path | ||
var op = { | ||
"parameters" : spec.params, | ||
"httpMethod" : spec.method, | ||
"notes" : spec.notes, | ||
"errorResponses" : spec.errorResponses, | ||
"nickname" : spec.nickname, | ||
"summary" : spec.summary | ||
"parameters": spec.params, | ||
"httpMethod": spec.method, | ||
"notes": spec.notes, | ||
"errorResponses": spec.errorResponses, | ||
"nickname": spec.nickname, | ||
"summary": spec.summary, | ||
"consumes" : spec.consumes, | ||
"produces" : spec.produces | ||
}; | ||
// Add custom fields. | ||
op = _.extend({}, spec, op); | ||
if (spec.responseClass) { | ||
op.responseClass = spec.responseClass; | ||
} | ||
else { | ||
op.responseClass = spec.responseClass; | ||
} else { | ||
op.responseClass = "void"; | ||
@@ -523,3 +609,3 @@ } | ||
if (!rootResource.models) { | ||
rootResource.models = {}; | ||
rootResource.models = {}; | ||
} | ||
@@ -533,13 +619,21 @@ } | ||
// Create Error JSON by code and text | ||
function error(code, description) { | ||
return {"code" : code, "description" : description}; | ||
return { | ||
"code": code, | ||
"reason": description | ||
}; | ||
} | ||
// Stop express ressource with error code | ||
function stopWithError(res, error) { | ||
exports.setHeaders(res); | ||
if (error && error.description && error.code) | ||
if (error && error.reason && error.code) | ||
res.send(JSON.stringify(error), error.code); | ||
else | ||
res.send(JSON.stringify({'description': 'internal error', 'code': 500}), 500); | ||
res.send(JSON.stringify({ | ||
'reason': 'internal error', | ||
'code': 500 | ||
}), 500); | ||
} | ||
@@ -549,19 +643,40 @@ | ||
exports.errors = { | ||
'notFound': function(field, res) { | ||
if (!res) { | ||
return {"code": 404, "description": field + ' not found'}; } | ||
else { | ||
res.send({"code": 404, "description": field + ' not found'}, 404); } | ||
'notFound': function (field, res) { | ||
if (!res) { | ||
return { | ||
"code": 404, | ||
"reason": field + ' not found' | ||
}; | ||
} else { | ||
res.send({ | ||
"code": 404, | ||
"reason": field + ' not found' | ||
}, 404); | ||
} | ||
}, | ||
'invalid': function(field, res) { | ||
if (!res) { | ||
return {"code": 400, "description": 'invalid ' + field}; } | ||
else { | ||
res.send({"code": 400, "description": 'invalid ' + field}, 404); } | ||
'invalid': function (field, res) { | ||
if (!res) { | ||
return { | ||
"code": 400, | ||
"reason": 'invalid ' + field | ||
}; | ||
} else { | ||
res.send({ | ||
"code": 400, | ||
"reason": 'invalid ' + field | ||
}, 404); | ||
} | ||
}, | ||
'forbidden': function(res) { | ||
if (!res) { | ||
return {"code": 403, "description": 'forbidden' }; } | ||
else { | ||
res.send({"code": 403, "description": 'forbidden'}, 403); } | ||
'forbidden': function (res) { | ||
if (!res) { | ||
return { | ||
"code": 403, | ||
"reason": 'forbidden' | ||
}; | ||
} else { | ||
res.send({ | ||
"code": 403, | ||
"reason": 'forbidden' | ||
}, 403); | ||
} | ||
} | ||
@@ -573,3 +688,4 @@ }; | ||
exports.pathParam = exports.params.path; | ||
exports.postParam = exports.params.post; | ||
exports.bodyParam = exports.params.body; | ||
exports.formParam = exports.params.form; | ||
exports.getModels = allModels; | ||
@@ -589,2 +705,3 @@ | ||
exports.addPut = addPut; | ||
exports.addPatch = addPatch; | ||
exports.addDelete = addDelete; | ||
@@ -594,8 +711,10 @@ exports.addGET = addGet; | ||
exports.addPUT = addPut; | ||
exports.addPATCH = addPatch; | ||
exports.addDELETE = addDelete; | ||
exports.addModels = addModels; | ||
exports.setAppHandler = setAppHandler; | ||
exports.setErrorHandler = setErrorHandler; | ||
exports.discover = discover; | ||
exports.discoverFile = discoverFile; | ||
exports.configureSwaggerPaths = configureSwaggerPaths; | ||
exports.setHeaders = setHeaders; | ||
exports.setHeaders = setHeaders; |
{ | ||
"name": "swagger-node-express", | ||
"version": "1.2.3", | ||
"version": "1.3.1", | ||
"author": { | ||
@@ -30,5 +30,6 @@ "name": "Tony Tam", | ||
"express": "3.x", | ||
"docco": "0.4.x" | ||
"docco": "0.4.x", | ||
"lodash": "1.3.1" | ||
}, | ||
"license": "apache 2.0" | ||
} |
@@ -22,3 +22,3 @@ This is the Wordnik Swagger code for the express framework. For more on Swagger, please visit http://swagger.wordnik.com. For more on express, please visit https://github.com/visionmedia/express | ||
or from [swagger UI], mounted at `/docs`: [http://localhost:8002/docs](http://localhost:8002/docs). | ||
or from [swagger UI](https://github.com/wordnik/swagger-ui), mounted at `/docs`: [http://localhost:8002/docs](http://localhost:8002/docs). | ||
@@ -34,13 +34,9 @@ ### How it works | ||
For the sample app, the models are defined here: | ||
For the sample app, the models are defined here: [Apps/petstore/models.js](https://github.com/wordnik/swagger-node-express/blob/master/Apps/petstore/models.js) | ||
(Apps/petstore/models.js)[https://github.com/wordnik/swagger-node-express/blob/master/Apps/petstore/models.js] | ||
You could load this from a static file or generate them programatically as in the | ||
sample. | ||
The operations and the callback functions are defined in this file: | ||
The operations and the callback functions are defined in this file: [Apps/petstore/petResources.js](https://github.com/wordnik/swagger-node-express/blob/master/Apps/petstore/petResources.js) | ||
(Apps/petstore/petResources.js)[https://github.com/wordnik/swagger-node-express/blob/master/Apps/petstore/petResources.js] | ||
Each spec defines input/output params with helper functions to generate the swagger | ||
@@ -47,0 +43,0 @@ metadata. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
183261
1.42%13
8.33%860
14.67%4
33.33%