From 2433135b0389034a4e17ee41c83a1b4beb566949 Mon Sep 17 00:00:00 2001 From: o1lab Date: Thu, 14 Jun 2018 09:55:19 +0100 Subject: [PATCH] Feature : flag to enable read only apis --- README.md | 3 ++ bin/index.js | 1 + index.js | 1 + lib/util/cmd.helper.js | 5 ++- lib/xapi.js | 72 ++++++++++++++++++++++++++++-------------- lib/xsql.js | 8 +++-- package.json | 2 +- 7 files changed, 64 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 29225955c5..08813b10e5 100644 --- a/README.md +++ b/README.md @@ -935,11 +935,14 @@ http://localhost:3000/_version -d, --database database schema name -r, --ipAddress IP interface of your server / locahost by default -n, --portNumber Port number for app -> 3000 by default + -o, --port Port number of mysql -> 3306 by default -a, --apiPrefix Api url prefix -> /api/ by default -s, --storageFolder Storage folder -> current working dir by default (available only with local) -i, --ignoreTables Comma separated table names to ignore + -y, --readOnly readonly apis -> false by default -h, --help Output usage information + Examples: $ xmysql -u username -p password -d databaseSchema diff --git a/bin/index.js b/bin/index.js index 77a205168a..09ec15101e 100755 --- a/bin/index.js +++ b/bin/index.js @@ -48,6 +48,7 @@ moreApis.init((err, results) => { console.log(' '); console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1)); + console.log(" API's base URL : " + "localhost:"+sqlConfig.portNumber); console.log(' '); console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '); diff --git a/index.js b/index.js index 9d00bfbe4e..2d8501598c 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,7 @@ moreApis.init((err, results) => { console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1)); + console.log(" API's base URL : " + "localhost:"+sqlConfig.portNumber); console.log(' '); console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '); diff --git a/lib/util/cmd.helper.js b/lib/util/cmd.helper.js index 2b4e50940a..e93d67683d 100644 --- a/lib/util/cmd.helper.js +++ b/lib/util/cmd.helper.js @@ -24,6 +24,7 @@ program .option('-s, --storageFolder ', 'storage folder / current working dir by default / available only with local') .option('-i, --ignoreTables ', 'comma separated table names to ignore') .option('-a, --apiPrefix ', 'api url prefix / "/api/" by default') + .option('-y, --readOnly', 'readonly apis / false by default') .parse(process.argv) @@ -33,6 +34,7 @@ function paintHelp(txt) { function processInvalidArguments(program) { + let err = ''; if (!program.password) { @@ -60,6 +62,7 @@ exports.handle = program => { program.host = program.host || 'localhost'; program.storageFolder = program.storageFolder || process.cwd() program.apiPrefix = program.apiPrefix || '/api/' + program.readOnly = program.readOnly || false; if (program.ignoreTables) { let ignoreTables = program.ignoreTables.split(',') @@ -76,7 +79,7 @@ exports.handle = program => { if (program.host === 'localhost' || program.host === '127.0.0.1' || program.host === '::1') { program.dynamic = 1 } - //console.log(program.rawArgs); + // console.log(program); /**************** END : default values ****************/ diff --git a/lib/xapi.js b/lib/xapi.js index 66d952010a..d4ba75059f 100644 --- a/lib/xapi.js +++ b/lib/xapi.js @@ -118,6 +118,8 @@ class Xapi { stat.tables = 0 stat.apis = 0 + // console.log('this.config while setting up routes', this.config); + // show routes for database schema this.app.get('/', this.asyncMiddleware(this.root.bind(this))) @@ -128,7 +130,7 @@ class Xapi { this.app.route(this.config.apiPrefix + 'xjoin') .get(this.asyncMiddleware(this.xjoin.bind(this))); - stat.api += 3; + stat.apis += 3; /**************** START : setup routes for each table ****************/ @@ -164,8 +166,9 @@ class Xapi { break; case 'create': - this.app.route(routes[i]['routeUrl']) - .post(this.asyncMiddleware(resourceCtrl.create.bind(resourceCtrl))); + if (!this.config.readOnly) + this.app.route(routes[i]['routeUrl']) + .post(this.asyncMiddleware(resourceCtrl.create.bind(resourceCtrl))); break; case 'read': @@ -174,33 +177,55 @@ class Xapi { break; case 'bulkInsert': - this.app.route(routes[i]['routeUrl']) - .post(this.asyncMiddleware(resourceCtrl.bulkInsert.bind(resourceCtrl))); + if (!this.config.readOnly) { + this.app.route(routes[i]['routeUrl']) + .post(this.asyncMiddleware(resourceCtrl.bulkInsert.bind(resourceCtrl))); + } break; case 'bulkRead': - this.app.route(routes[i]['routeUrl']) - .get(this.asyncMiddleware(resourceCtrl.bulkRead.bind(resourceCtrl))); + if (!this.config.readOnly){ + this.app.route(routes[i]['routeUrl']) + .get(this.asyncMiddleware(resourceCtrl.bulkRead.bind(resourceCtrl))); + } else { + stat.apis--; + } break; case 'bulkDelete': - this.app.route(routes[i]['routeUrl']) - .delete(this.asyncMiddleware(resourceCtrl.bulkDelete.bind(resourceCtrl))); + if (!this.config.readOnly){ + this.app.route(routes[i]['routeUrl']) + .delete(this.asyncMiddleware(resourceCtrl.bulkDelete.bind(resourceCtrl))); + } else { + stat.apis--; + } break; case 'patch': - this.app.route(routes[i]['routeUrl']) - .patch(this.asyncMiddleware(resourceCtrl.patch.bind(resourceCtrl))); + if (!this.config.readOnly){ + this.app.route(routes[i]['routeUrl']) + .patch(this.asyncMiddleware(resourceCtrl.patch.bind(resourceCtrl))); + } else { + stat.apis--; + } break; case 'update': - this.app.route(routes[i]['routeUrl']) - .put(this.asyncMiddleware(resourceCtrl.update.bind(resourceCtrl))); + if (!this.config.readOnly){ + this.app.route(routes[i]['routeUrl']) + .put(this.asyncMiddleware(resourceCtrl.update.bind(resourceCtrl))); + } else { + stat.apis--; + } break; case 'delete': - this.app.route(routes[i]['routeUrl']) - .delete(this.asyncMiddleware(resourceCtrl.delete.bind(resourceCtrl))); + if (!this.config.readOnly){ + this.app.route(routes[i]['routeUrl']) + .delete(this.asyncMiddleware(resourceCtrl.delete.bind(resourceCtrl))); + } else { + stat.apis--; + } break; case 'exists': @@ -259,7 +284,7 @@ class Xapi { /**************** END : setup routes for each table ****************/ - if (this.config.dynamic === 1) { + if (this.config.dynamic === 1 && !this.config.readOnly) { this.app.route('/dynamic*') .post(this.asyncMiddleware(this.runQuery.bind(this))); @@ -270,15 +295,16 @@ class Xapi { this.app.get('/download', this.downloadFile.bind(this)); /**************** END : multer routes ****************/ - /**************** START : health and version ****************/ - this.app.get('/_health', this.asyncMiddleware(this.health.bind(this))); - this.app.get('/_version', this.asyncMiddleware(this.version.bind(this))); - /**************** END : health and version ****************/ + stat.apis += 4; + } - stat.api += 4; + /**************** START : health and version ****************/ + this.app.get('/_health', this.asyncMiddleware(this.health.bind(this))); + this.app.get('/_version', this.asyncMiddleware(this.version.bind(this))); + stat.apis += 2; + /**************** END : health and version ****************/ - } let statStr = ' Generated: ' + stat.apis + ' REST APIs for ' + stat.tables + ' tables ' @@ -304,7 +330,7 @@ class Xapi { this.mysql.prepareJoinQuery(req, res, obj) //console.log(obj); - if(obj.query.length){ + if (obj.query.length) { let results = await this.mysql.exec(obj.query, obj.params) res.status(200).json(results) } else { diff --git a/lib/xsql.js b/lib/xsql.js index f0089871da..0e555867cd 100644 --- a/lib/xsql.js +++ b/lib/xsql.js @@ -561,6 +561,8 @@ class Xsql { let isView = this.metaDb.tables[tableName]['isView']; tableObj['resource'] = tableName; + + // order of routes is important for express routing - DO NOT CHANGE ORDER routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/describe', 'describe')) routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/count', 'count')) routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/groupby', 'groupby')) @@ -571,18 +573,18 @@ class Xsql { routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/findOne', 'findOne')) routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/autoChart', 'autoChart')) - if (!isView) { + if (!isView && !this.sqlConfig.readOnly) { routes.push(this.prepareRoute(internal, 'post', apiPrefix, tableName, 'create')) } routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName, 'list')) - if (!isView) { + if (!isView && !this.sqlConfig.readOnly) { routes.push(this.prepareRoute(internal, 'post', apiPrefix, tableName + '/bulk', 'bulkInsert')) routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/bulk', 'bulkDelete')) } routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/bulk', 'bulkRead')) - if (!isView) { + if (!isView && !this.sqlConfig.readOnly) { routes.push(this.prepareRoute(internal, 'put', apiPrefix, tableName, 'update')) routes.push(this.prepareRoute(internal, 'patch', apiPrefix, tableName + '/:id', 'patch')) routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/:id', 'delete')) diff --git a/package.json b/package.json index 78a759ff10..425002af8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmysql", - "version": "0.4.5", + "version": "0.4.6", "description": "One command to generate REST APIs for any MySql database", "main": "index.js", "scripts": {