Commit ccaf6d88 authored by Alex Quispe's avatar Alex Quispe

Estructura actualizada

parent fe86a559
/node_modules
/src/template
module.exports = {
"env": {
"node": true,
"commonjs": true,
"es6": true
},
"extends": "standard",
"parserOptions": {
"ecmaVersion": 2017
},
"rules": {
"no-multi-spaces": "off",
"key-spacing": ["error", {
"align": "value",
"align": "colon",
"align": { "beforeColon": true, "afterColon": true, "on": "colon" }
}]
},
"globals": {
"describe": true,
"expect": true,
"it": true,
"before": true,
"after": true,
"beforeEach": true,
"afterEach": true
}
}
......@@ -2,3 +2,4 @@
/node_modules
/temp
/package-lock.json
/test/app
This diff is collapsed.
This diff is collapsed.
const test = require('ava')
const request = require('supertest')
const app = require('../')
test.serial.cb('[Api V1 Users] [get] /api/v1/users/', t => {
request(app).get('/api/v1/users/')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.end((err, res) => {
t.pass()
t.end()
})
})
test.serial.cb('[Api V1 Users] [get] /api/v1/users/:id', t => {
request(app).get('/api/v1/users/:id')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.end((err, res) => {
t.pass()
t.end()
})
})
test.serial.cb('[Api V1 Users] [post] /api/v1/users/', t => {
request(app).post('/api/v1/users/')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.end((err, res) => {
t.pass()
t.end()
})
})
const ApiGen = require('./../../')
const path = require('path')
ApiGen.API_URL = process.env.API_URL || 'http://localhost:4000'
ApiGen.DOC_SERVER_PORT = process.env.DOC_SERVER_PORT || 5000
ApiGen.BUILD_PATH = path.resolve(__dirname, 'build')
ApiGen.SRC_PATH = path.resolve(__dirname, 'src')
ApiGen.HELP_TYPE = 'YAML' // YAML o JSON
const SWAGGER_JSON_URL = `http://localhost:${ApiGen.DOC_SERVER_PORT}/swagger.json`
let description = ''
description += `Swagger: http://localhost:${ApiGen.DOC_SERVER_PORT}/swagger?url=${SWAGGER_JSON_URL}\n`
description += `ApidocJS: http://localhost:${ApiGen.DOC_SERVER_PORT}/apidoc\n`
ApiGen.DESCRIPTION = description
ApiGen.create().catch(e => console.log(e))
const ApiGen = require('./../../')
const path = require('path')
ApiGen.TEST_PATH = path.resolve(__dirname, '../test')
ApiGen.TEMPLATE_PATH = path.resolve(__dirname, 'template')
const app = require(process.cwd())
ApiGen.scaffoldTest(app)
const ApiGen = require('./../../')
const path = require('path')
ApiGen.SRC_PATH = path.resolve(__dirname, 'src')
ApiGen.HELP_TYPE = 'YAML' // YAML o JSON
const app = require(process.cwd())
ApiGen.scaffold(app)
const ApiGen = require('./../../')
const path = require('path')
ApiGen.DOC_SERVER_PORT = process.env.DOC_SERVER_PORT || 5000
ApiGen.BUILD_PATH = path.resolve(__dirname, 'build')
const SWAGGER_JSON_URL = `http://localhost:${ApiGen.DOC_SERVER_PORT}/swagger.json`
ApiGen.REDIRECT_PATH = `/swagger?url=${SWAGGER_JSON_URL}`
ApiGen.server()
const ApiGen = require('../../../')
module.exports = async () => {
await ApiGen.get('/api/custom/other/route').generate()
// <!-- [ROUTE DEFINITION] --!> //
}
-
method: get
path: /api/custom/other/route
const ApiGen = require('../../../')
module.exports = async () => {
await ApiGen.get('/api/v1/users/').generate()
await ApiGen.get('/api/v1/users/:id').generate()
await ApiGen.post('/api/v1/users/').generate()
await ApiGen.post('/api/v1/users/bulk').generate()
// <!-- [ROUTE DEFINITION] --!> //
}
-
method: get
path: /api/v1/users/
-
method: get
path: '/api/v1/users/:id'
-
method: post
path: /api/v1/users/
-
method: post
path: /api/v1/users/bulk
const ApiGen = require('../../../')
module.exports = async () => {
await ApiGen.get('/ruta/sin/grupo').generate()
// <!-- [ROUTE DEFINITION] --!> //
}
-
method: get
path: /ruta/sin/grupo
test.serial.cb('[GROUP] [METHOD] PATH', t => {
t.pass()
t.end()
// request(app).METHOD('PATH')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
// <!-- [TEST DEFINITION] --!> //
const test = require('ava')
const request = require('supertest')
const app = require(process.cwd())
// <!-- [TEST DEFINITION] --!> //
module.exports = require('./src/app')
\ No newline at end of file
{
"name": "example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index",
"test": "NODE_ENV=test ava test/* --serial --verbose",
"doc:scaffold": "node documentation/scaffold",
"doc:scaffold:test": "node documentation/scaffold-test",
"doc:generate": "node documentation/generate",
"doc:server": "node documentation/server",
"doc:start": "npm run doc:scaffold && npm run doc:generate && npm run doc:server"
},
"author": "",
"license": "ISC",
"dependencies": {
"ava": "^0.25.0",
"supertest": "^3.3.0"
}
}
const test = require('ava')
const request = require('supertest')
const app = require(process.cwd())
test.serial.cb('[Api Custom] [get] /api/custom/other/route', t => {
t.pass()
t.end()
// request(app).get('/api/custom/other/route')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
// <!-- [TEST DEFINITION] --!> //
const test = require('ava')
const request = require('supertest')
const app = require(process.cwd())
test.serial.cb('[Api V1 Users] [get] /api/v1/users/', t => {
t.pass()
t.end()
// request(app).get('/api/v1/users/')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
test.serial.cb('[Api V1 Users] [get] /api/v1/users/:id', t => {
t.pass()
t.end()
// request(app).get('/api/v1/users/:id')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
test.serial.cb('[Api V1 Users] [post] /api/v1/users/', t => {
t.pass()
t.end()
// request(app).post('/api/v1/users/')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
test.serial.cb('[Api V1 Users] [post] /api/v1/users/bulk', t => {
t.pass()
t.end()
// request(app).post('/api/v1/users/bulk')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
// <!-- [TEST DEFINITION] --!> //
const test = require('ava')
const request = require('supertest')
const app = require(process.cwd())
test.serial.cb('[Default] [get] /ruta/sin/grupo', t => {
t.pass()
t.end()
// request(app).get('/ruta/sin/grupo')
// .set('Accept', 'application/json')
// .expect('Content-Type', /json/)
// .end((err, res) => {
// t.pass()
// t.end()
// })
})
// <!-- [TEST DEFINITION] --!> //
module.exports = require('./class/ApidocGenerator')
module.exports = {
ApidocGenerator : require('./src/class/ApidocGenerator'),
ApidocRequest : require('./src/class/ApidocRequest')
}
This diff is collapsed.
{
"name": "apidoc-generator",
"name": "agetic-bpm-doc-generator",
"version": "1.0.0",
"description": "Genera la documentación de un servicio web RESTFull para ApidocJS y Swagger",
"description": "Generador de Apidoc y Test de Integración para servicios web creados con express.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "npm run test-unit && npm run test-integration",
"test-unit": "./node_modules/.bin/ava test/unit/* --serial --verbose",
"test-integration": "./node_modules/.bin/ava test/integration/* --serial --verbose",
"lint": "./node_modules/.bin/eslint src"
},
"author": "AGETIC",
"license": "GPL v2",
"directories": {
"test": "test"
"bin": {
"doc": "src/cli/doc.js"
},
"repository": {
"type": "git",
"url": "git@gitlab.geo.gob.bo:wilmer.quispe/apidoc-generator.git"
"url": "git@gitlab.geo.gob.bo:agetic/agetic-bpm-doc-generator.git"
},
"author": "Alex Quispe <wilmer.quispe@agetic.gob.bo>",
"license": "MIT",
"dependencies": {
"apidoc": "^0.17.6",
"cors": "^2.8.4",
"ejs": "^2.6.1",
"cli-table": "^0.3.1",
"commander": "^2.19.0",
"cors": "^2.8.5",
"express": "^4.16.4",
"lodash": "^4.17.11",
"mkdirp": "^0.5.1",
"request": "^2.88.0",
"sequelize": "^4.39.1",
"sequelize": "^4.41.2",
"supertest": "^3.3.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
"ava": "^0.25.0",
"eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^3.1.0"
}
}
......@@ -190,14 +190,14 @@ function _headerSwagger (route) {
description = `<strong>PERMISOS:</strong> <code>${route.permissions}</code><br><br>${description}`
}
const swaggerDefinition = {
path: route.swaggerPath(),
method:route.method,
content: {
"tags": [route.group],
"responses": { "200": { "description": route.description } },
"consumes": [ "application/json" ],
"produces": [ "application/json" ],
"description": description
path : route.swaggerPath(),
method : route.method,
content : {
tags : [route.group],
responses : { '200': { description: route.description } },
consumes : [ 'application/json' ],
produces : [ 'application/json' ],
description : description
}
}
if (route.permissions) {
......@@ -263,10 +263,6 @@ function _createApidocSwagger (fullprop, obj, apidocProperty, type, propName = '
const field = obj[prop]
const property = (fullprop !== '') ? `${fullprop}.${prop}` : prop
if (_isField(field)) {
const ONLY_TYPE = apidocProperty === '@apiSuccess'
const description = _createDescription(field, prop)
const validateDescription = _createValidateDescription(field, ONLY_TYPE)
let fieldName = ONLY_TYPE ? `${property}` : _apidocProp(field, property)
let fieldType = _apidocType(field, true) // es true, porque siempre se mostrará solamente el tipo de dato.
apidoc[prop] = { type: _toTypeSwager(fieldType), example: _exampleData(field) }
} else {
......
const _ = require('lodash')
const supertest = require('supertest')
const Route = require('./Route')
const RouteBuilder = require('./RouteBuilder')
const config = require('../config/config')
class ApidocGenerator {
constructor () {
this.route = new Route()
}
static globalProperties (routeProperties) {
const app = require(config.appPath)
const request = supertest(app)
ApidocGenerator.requestInstance = request
ApidocGenerator.routeProperties = routeProperties
}
static get (routePath, routeKey) { return ApidocGenerator._createRoute('get', routePath, routeKey) }
static post (routePath, routeKey) { return ApidocGenerator._createRoute('post', routePath, routeKey) }
static put (routePath, routeKey) { return ApidocGenerator._createRoute('put', routePath, routeKey) }
static patch (routePath, routeKey) { return ApidocGenerator._createRoute('patch', routePath, routeKey) }
static delete (routePath, routeKey) { return ApidocGenerator._createRoute('delete', routePath, routeKey) }
static _createRoute (routeMethod, routePath, routeKey) {
const routeBuilder = new RouteBuilder()
routeBuilder.method(routeMethod).path(routePath).key(routeKey)
const routeProperties = _.clone(ApidocGenerator.routeProperties)
routeProperties.requestInstance = ApidocGenerator.requestInstance
routeBuilder.updatePropertiesWithoutRequest(routeProperties)
routeBuilder.loadHelp(routeBuilder.route.groupKey)
return routeBuilder
}
}
module.exports = ApidocGenerator
const supertest = require('supertest')
const Route = require('./Route')
const RouteBuilder = require('./RouteBuilder')
const config = require('../config/config')
class ApidocRequest {
constructor () {
this.route = new Route()
}
static init () {
const app = require(config.appPath)
const request = supertest(app)
ApidocRequest.requestInstance = request
}
static get (routePath, routeKey) { return ApidocRequest._createRoute('get', routePath, routeKey) }
static post (routePath, routeKey) { return ApidocRequest._createRoute('post', routePath, routeKey) }
static put (routePath, routeKey) { return ApidocRequest._createRoute('put', routePath, routeKey) }
static patch (routePath, routeKey) { return ApidocRequest._createRoute('patch', routePath, routeKey) }
static delete (routePath, routeKey) { return ApidocRequest._createRoute('delete', routePath, routeKey) }
static _createRoute (routeMethod, routePath, routeKey) {
const routeBuilder = new RouteBuilder()
routeBuilder.method(routeMethod).path(routePath).key(routeKey)
const routeProperties = {
requestInstance : ApidocRequest.requestInstance,
request : true
}
routeBuilder.updatePropertiesWithoutRequest(routeProperties)
return routeBuilder
}
}
module.exports = ApidocRequest
......@@ -521,9 +521,9 @@ function _getMaxItem (array) {
function getField (OBJ) {
switch (typeof OBJ) {
case 'string': return FieldCreator.STRING({ example: OBJ, allowNull: false });
case 'boolean': return FieldCreator.BOOLEAN({ example: OBJ, allowNull: false });
case 'number': return FieldCreator.INTEGER({ example: OBJ, allowNull: false });
case 'string' : return FieldCreator.STRING({ example: OBJ, allowNull: false })
case 'boolean' : return FieldCreator.BOOLEAN({ example: OBJ, allowNull: false })
case 'number' : return FieldCreator.INTEGER({ example: OBJ, allowNull: false })
}
return OBJ
}
......
const _ = require('lodash')
const request = require('request')
const FieldCreator = require('./FieldCreator')
const _ = require('lodash')
class Route {
constructor () {
......@@ -18,7 +15,12 @@ class Route {
this.output = null // FieldGroup
this.inputData = null // Datos de entrada obj = { headers, params, query, body }
this.outputData = null // Datos de salida obj = body
this.request = false
this.request = false // Indica si se va a aejecutar la petición
this.verified = false // Indica si la ruta ha sido verificada con una consulta
this.inputExamples = null // Lista de ejemplos de entrada Ej: [{ title, data }]
this.outputExamples = null // Lista de ejemplos de salida
this.requestInstance = null // Objeto creado con supertest para realizar consultas
this.responseInstance = null // Resultado de la consulta
}
setName (name) {
......@@ -55,7 +57,13 @@ class Route {
}
setInputData (inputData) {
this.inputData = inputData
if (typeof inputData !== 'undefined') {
if (inputData === null) { this.inputData = null }
if (inputData && typeof inputData.headers !== 'undefined') { this.inputData = this.inputData || {}; this.inputData.headers = inputData.headers }
if (inputData && typeof inputData.params !== 'undefined') { this.inputData = this.inputData || {}; this.inputData.params = inputData.params }
if (inputData && typeof inputData.query !== 'undefined') { this.inputData = this.inputData || {}; this.inputData.query = inputData.query }
if (inputData && typeof inputData.body !== 'undefined') { this.inputData = this.inputData || {}; this.inputData.body = inputData.body }
}
}
setOutputData (outputData) {
......@@ -74,29 +82,29 @@ class Route {
this.request = value
}
async updateProperties (options = {}) {
const PROPS = options.properties || {}
this.key = this.key || PROPS.key
this.permissions = this.permissions || PROPS.permissions
this.version = this.version || PROPS.version
this.request = this.request || PROPS.request
this.name = this.name || PROPS.name || `[${this.method}] ${_toWords(this.path)}${this.key ? ` (${this.key})` : ''}`
this.description = this.description || PROPS.description || this.name
this.inputData = this.inputData || PROPS.inputData
this.outputData = this.outputData || PROPS.outputData
this.inputExamples = this.inputExamples || PROPS.inputExamples
this.outputExamples = this.outputExamples || PROPS.outputExamples
if (this.request === true) {
this.outputData = this.outputData || await _request(this, options)
}
this.input = this.input || FieldCreator.groupObj(this.inputData) || {}
this.output = this.output || FieldCreator.groupObj(this.outputData) || {}
setVerified (value) {
this.verified = value
}
setInputExamples (inputExamples) {
this.inputExamples = inputExamples
}
setOutputExamples (outputExamples) {
this.outputExamples = outputExamples
}
setRequestInstance (requestInstance) {
this.requestInstance = requestInstance
}
setResponseInstance (responseInstance) {
this.responseInstance = responseInstance
}
swaggerPath () {
const split = this.path.split('/')
const path2 = []
let pathSwagger = this.path
split.forEach(prop => {
path2.push(prop.startsWith(':') ? `{${prop.substr(1)}}` : prop)
})
......@@ -104,16 +112,45 @@ class Route {
return swaggerPath
}
requestPath (inputDataParams = {}) {
requestPath () {
let requestPath = this.path
Object.keys(inputDataParams).forEach(prop => {
requestPath = requestPath.replace(`:${prop}`, `${inputDataParams[prop]}`)
})
return requestPath
if (this.inputData && this.inputData.params) {
Object.keys(this.inputData.params).forEach(prop => {
requestPath = requestPath.replace(`:${prop}`, `${this.inputData.params[prop]}`)
})
}
if (this.inputData && this.inputData.query) {
requestPath += '?'
Object.keys(this.inputData.query).forEach(prop => {
requestPath += `${prop}=${this.inputData.query[prop]}&`
})
}
return _.trim(requestPath, '&')
}