Skip to content

Commit

Permalink
generate swagger definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
tjwebb committed Sep 3, 2015
1 parent 44e618c commit 52fd840
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,2 +1,4 @@
.tmp
*.sw*
dist/
node_modules/
6 changes: 1 addition & 5 deletions api/controllers/SwaggerController.js
@@ -1,10 +1,6 @@
const SwaggerController = {
doc (req, res) {
let doc = sails.hooks.swagger.doc

console.log(doc)

return res.status(200).jsonx(doc)
return res.status(200).jsonx(sails.hooks.swagger.doc)
}
}

Expand Down
117 changes: 81 additions & 36 deletions lib/xfmr.js
Expand Up @@ -11,7 +11,8 @@ const Transformer = {
'http',
'https'
],
paths: Transformer.getPaths(sails.router._privateRouter.routes)
definitions: Transformer.getDefinitions(sails),
paths: Transformer.getPaths(sails)
}
},

Expand All @@ -32,63 +33,108 @@ const Transformer = {
})
},

getDefinitions (sails) {
return _.transform(sails.models, (definitions, model, modelName) => {
definitions[model.globalId] = {
id: model.identity,
properties: model.definition
}
})
/*
return _.chain(sails.models)
.mapKeys((model, _) => {
return model.globalId
})
.mapValues((model, _) => {
return {
id: model.identity,
properties: model.attributes
}
})
.value()
*/
},

/**
* Convert the internal Sails route map into a Swagger Paths
* Object
* http://swagger.io/specification/#pathsObject
* http://swagger.io/specification/#pathItemObject
*/
getPaths (routes) {
getPaths (sails) {
let routes = sails.router._privateRouter.routes
let pathGroups = _.chain(routes)
.values()
.flatten()
.unique(route => {
return route.path + route.method + JSON.stringify(route.keys)
})
.groupBy('path')
.mapKeys((_, path) => {
return path.replace(/:(\w+)\??/g, '{$1}')
})
.value()

return _.mapValues(pathGroups, Transformer.getPathItem)
return _.mapValues(pathGroups, (pathGroup, key) => {
return Transformer.getPathItem(sails, pathGroup, key)
})
},

getModelFromPath (sails, fullPath) {
let [ $, path = ''] = fullPath.split(' /')
let [ parentModelName, parentId, childAttributeName, childId ] = path.split('/')
let parentModel = sails.models[parentModelName]
let childAttribute = _.get(parentModel, [ 'attributes', childAttributeName ])
let childModelName = _.get(childAttribute, 'collection') || _.get(childAttribute, 'model')
let childModel = sails.models[childModelName]

return childModel || parentModel
},

/**
* http://swagger.io/specification/#definitionsObject
*/
getDefinitionReference (sails, path) {
let model = Transformer.getModelFromPath(sails, path)
if (model) {
return '#/definitions/' + model.identity
}
},

getPathItem (pathGroup, key) {
/**
* http://swagger.io/specification/#pathItemObject
*/
getPathItem (sails, pathGroup, pathkey) {
let methodGroups = _.chain(pathGroup)
.groupBy('method')
.indexBy('method')
.pick([
'get', 'post', 'put', 'head', 'options', 'patch', 'delete'
])
.mapValues(_.flatten)
.value()

return _.mapValues(methodGroups, Transformer.getOperation)
return _.mapValues(methodGroups, (methodGroup, method) => {
return Transformer.getOperation(sails, methodGroup, method)
})
},

/**
* http://swagger.io/specification/#operationObject
*/
getOperation (methodGroup, method) {
getOperation (sails, methodGroup, method) {
return {
description: 'a route',
consumes: [
'application/json'
],
produces: [
'application/json'
],
parameters: Transformer.getParameters(methodGroup),
responses: Transformer.getResponses(methodGroup),
summary: `${method}`,
consumes: [ 'application/json' ],
produces: [ 'application/json' ],
parameters: Transformer.getParameters(sails, methodGroup),
responses: Transformer.getResponses(sails, methodGroup)
}
},

/**
* http://swagger.io/specification/#parameterObject
*/
getParameters (methodGroup) {
let routeParams = _.chain(methodGroup)
.pluck('keys')
.flatten()
.unique('name')
.value()
getParameters (sails, methodGroup) {
let routeParams = methodGroup.keys

if (!routeParams.length) return

Expand All @@ -105,20 +151,19 @@ const Transformer = {
/**
* http://swagger.io/specification/#responsesObject
*/
getResponses (methodGroups) {
getResponses (sails, methodGroup) {
let $ref = Transformer.getDefinitionReference(sails, methodGroup.path)
let ok = {
description: 'The requested resource'
}
if ($ref) {
ok.schema = { '$ref': $ref }
}
return {
'200': {
description: 'the result'
},
'403': {
description: 'Not permitted'
},
'404': {
description: 'Not found'
},
'500': {
description: 'Internal server error'
}
'200': ok,
'403': { description: 'Not permitted' },
'404': { description: 'Not found' },
'500': { description: 'Internal server error' }
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -4,7 +4,7 @@
"description": "swagger.io integration for sails.js",
"main": "dist/api/hooks/swagger/index.js",
"scripts": {
"test": "mocha --reporter spec --compilers js:babel/register",
"test": "gulp && mocha --reporter spec --compilers js:babel/register",
"prepublish": "gulp"
},
"repository": {
Expand Down Expand Up @@ -32,7 +32,8 @@
"gulp": "^3.9.0",
"gulp-babel": "^5.2.1",
"mocha": "^2.2.5",
"sails": "balderdashy/sails"
"sails": "balderdashy/sails",
"sails-disk": "^0.10.8"
},
"dependencies": {
"hoek": "^2.14.0",
Expand Down
2 changes: 1 addition & 1 deletion test/bootstrap.test.js
Expand Up @@ -3,7 +3,7 @@ import _ from 'lodash'
import Sails from 'sails'

const config = {
appPath: path.dirname(require.resolve('@balderdash/sails-crm')),
appPath: path.resolve(path.dirname(require.resolve('@balderdash/sails-crm')), '../../../../'),
hooks: {
grunt: false
},
Expand Down
20 changes: 16 additions & 4 deletions test/xfmr.test.js
Expand Up @@ -8,9 +8,8 @@ describe('xfmr', () => {
it('should generate complete and correct Swagger doc', () => {
let swagger = xfmr.getSwagger(sails, pkg)

assert(swagger)

//console.log(swagger)
assert(swagger)
})
})
describe('#getInfo', () => {
Expand All @@ -28,8 +27,7 @@ describe('xfmr', () => {
assert(_.isObject(sails.router._privateRouter.routes))
})
it('should transform routes to paths', () => {
let allRoutes = sails.router._privateRouter.routes
let paths = xfmr.getPaths(allRoutes)
let paths = xfmr.getPaths(sails)

assert(paths)
})
Expand Down Expand Up @@ -78,4 +76,18 @@ describe('xfmr', () => {
assert(_.isObject(swaggerResponses))
})
})
describe('#getDefinitionReference()', () => {
it('should generate a Swagger $ref from a simple path /contact', () => {
assert.equal('#/definitions/contact', xfmr.getDefinitionReference(sails, 'GET /contact'))
})
it('should generate a Swagger $ref from a simple path /address/:id', () => {
assert.equal('#/definitions/address', xfmr.getDefinitionReference(sails, 'GET /address/:id'))
})
it('should generate a Swagger $ref from an association path /contact/:parentid/groups', () => {
assert.equal('#/definitions/group', xfmr.getDefinitionReference(sails, 'GET /contact/:parentid/groups'))
})
it('should generate a Swagger $ref from an association path /organization/:parentid/location/:id', () => {
assert.equal('#/definitions/group', xfmr.getDefinitionReference(sails, 'GET /organization/:parentid/groups/:id'))
})
})
})

0 comments on commit 52fd840

Please sign in to comment.