Browse Source

Feature : flag to enable read only apis

pull/39/head
o1lab 6 years ago
parent
commit
2433135b03
  1. 3
      README.md
  2. 1
      bin/index.js
  3. 1
      index.js
  4. 5
      lib/util/cmd.helper.js
  5. 72
      lib/xapi.js
  6. 8
      lib/xsql.js
  7. 2
      package.json

3
README.md

@ -935,11 +935,14 @@ http://localhost:3000/_version
-d, --database <n> database schema name -d, --database <n> database schema name
-r, --ipAddress <n> IP interface of your server / locahost by default -r, --ipAddress <n> IP interface of your server / locahost by default
-n, --portNumber <n> Port number for app -> 3000 by default -n, --portNumber <n> Port number for app -> 3000 by default
-o, --port <n> Port number of mysql -> 3306 by default
-a, --apiPrefix <n> Api url prefix -> /api/ by default -a, --apiPrefix <n> Api url prefix -> /api/ by default
-s, --storageFolder <n> Storage folder -> current working dir by default (available only with local) -s, --storageFolder <n> Storage folder -> current working dir by default (available only with local)
-i, --ignoreTables <n> Comma separated table names to ignore -i, --ignoreTables <n> Comma separated table names to ignore
-y, --readOnly readonly apis -> false by default
-h, --help Output usage information -h, --help Output usage information
Examples: Examples:
$ xmysql -u username -p password -d databaseSchema $ xmysql -u username -p password -d databaseSchema

1
bin/index.js

@ -48,6 +48,7 @@ moreApis.init((err, results) => {
console.log(' '); console.log(' ');
console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1)); console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1));
console.log(" API's base URL : " + "localhost:"+sqlConfig.portNumber);
console.log(' '); console.log(' ');
console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '); console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ');

1
index.js

@ -49,6 +49,7 @@ moreApis.init((err, results) => {
console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1)); console.log(" Xmysql took : %d seconds",dataHelp.round(t2,1));
console.log(" API's base URL : " + "localhost:"+sqlConfig.portNumber);
console.log(' '); console.log(' ');
console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '); console.log(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ');

5
lib/util/cmd.helper.js

@ -24,6 +24,7 @@ program
.option('-s, --storageFolder <n>', 'storage folder / current working dir by default / available only with local') .option('-s, --storageFolder <n>', 'storage folder / current working dir by default / available only with local')
.option('-i, --ignoreTables <n>', 'comma separated table names to ignore') .option('-i, --ignoreTables <n>', 'comma separated table names to ignore')
.option('-a, --apiPrefix <n>', 'api url prefix / "/api/" by default') .option('-a, --apiPrefix <n>', 'api url prefix / "/api/" by default')
.option('-y, --readOnly', 'readonly apis / false by default')
.parse(process.argv) .parse(process.argv)
@ -33,6 +34,7 @@ function paintHelp(txt) {
function processInvalidArguments(program) { function processInvalidArguments(program) {
let err = ''; let err = '';
if (!program.password) { if (!program.password) {
@ -60,6 +62,7 @@ exports.handle = program => {
program.host = program.host || 'localhost'; program.host = program.host || 'localhost';
program.storageFolder = program.storageFolder || process.cwd() program.storageFolder = program.storageFolder || process.cwd()
program.apiPrefix = program.apiPrefix || '/api/' program.apiPrefix = program.apiPrefix || '/api/'
program.readOnly = program.readOnly || false;
if (program.ignoreTables) { if (program.ignoreTables) {
let ignoreTables = program.ignoreTables.split(',') 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') { if (program.host === 'localhost' || program.host === '127.0.0.1' || program.host === '::1') {
program.dynamic = 1 program.dynamic = 1
} }
//console.log(program.rawArgs); // console.log(program);
/**************** END : default values ****************/ /**************** END : default values ****************/

72
lib/xapi.js

@ -118,6 +118,8 @@ class Xapi {
stat.tables = 0 stat.tables = 0
stat.apis = 0 stat.apis = 0
// console.log('this.config while setting up routes', this.config);
// show routes for database schema // show routes for database schema
this.app.get('/', this.asyncMiddleware(this.root.bind(this))) this.app.get('/', this.asyncMiddleware(this.root.bind(this)))
@ -128,7 +130,7 @@ class Xapi {
this.app.route(this.config.apiPrefix + 'xjoin') this.app.route(this.config.apiPrefix + 'xjoin')
.get(this.asyncMiddleware(this.xjoin.bind(this))); .get(this.asyncMiddleware(this.xjoin.bind(this)));
stat.api += 3; stat.apis += 3;
/**************** START : setup routes for each table ****************/ /**************** START : setup routes for each table ****************/
@ -164,8 +166,9 @@ class Xapi {
break; break;
case 'create': case 'create':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly)
.post(this.asyncMiddleware(resourceCtrl.create.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.post(this.asyncMiddleware(resourceCtrl.create.bind(resourceCtrl)));
break; break;
case 'read': case 'read':
@ -174,33 +177,55 @@ class Xapi {
break; break;
case 'bulkInsert': case 'bulkInsert':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly) {
.post(this.asyncMiddleware(resourceCtrl.bulkInsert.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.post(this.asyncMiddleware(resourceCtrl.bulkInsert.bind(resourceCtrl)));
}
break; break;
case 'bulkRead': case 'bulkRead':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly){
.get(this.asyncMiddleware(resourceCtrl.bulkRead.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.get(this.asyncMiddleware(resourceCtrl.bulkRead.bind(resourceCtrl)));
} else {
stat.apis--;
}
break; break;
case 'bulkDelete': case 'bulkDelete':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly){
.delete(this.asyncMiddleware(resourceCtrl.bulkDelete.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.delete(this.asyncMiddleware(resourceCtrl.bulkDelete.bind(resourceCtrl)));
} else {
stat.apis--;
}
break; break;
case 'patch': case 'patch':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly){
.patch(this.asyncMiddleware(resourceCtrl.patch.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.patch(this.asyncMiddleware(resourceCtrl.patch.bind(resourceCtrl)));
} else {
stat.apis--;
}
break; break;
case 'update': case 'update':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly){
.put(this.asyncMiddleware(resourceCtrl.update.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.put(this.asyncMiddleware(resourceCtrl.update.bind(resourceCtrl)));
} else {
stat.apis--;
}
break; break;
case 'delete': case 'delete':
this.app.route(routes[i]['routeUrl']) if (!this.config.readOnly){
.delete(this.asyncMiddleware(resourceCtrl.delete.bind(resourceCtrl))); this.app.route(routes[i]['routeUrl'])
.delete(this.asyncMiddleware(resourceCtrl.delete.bind(resourceCtrl)));
} else {
stat.apis--;
}
break; break;
case 'exists': case 'exists':
@ -259,7 +284,7 @@ class Xapi {
/**************** END : setup routes for each table ****************/ /**************** END : setup routes for each table ****************/
if (this.config.dynamic === 1) { if (this.config.dynamic === 1 && !this.config.readOnly) {
this.app.route('/dynamic*') this.app.route('/dynamic*')
.post(this.asyncMiddleware(this.runQuery.bind(this))); .post(this.asyncMiddleware(this.runQuery.bind(this)));
@ -270,15 +295,16 @@ class Xapi {
this.app.get('/download', this.downloadFile.bind(this)); this.app.get('/download', this.downloadFile.bind(this));
/**************** END : multer routes ****************/ /**************** END : multer routes ****************/
/**************** START : health and version ****************/ stat.apis += 4;
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.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 ' let statStr = ' Generated: ' + stat.apis + ' REST APIs for ' + stat.tables + ' tables '
@ -304,7 +330,7 @@ class Xapi {
this.mysql.prepareJoinQuery(req, res, obj) this.mysql.prepareJoinQuery(req, res, obj)
//console.log(obj); //console.log(obj);
if(obj.query.length){ if (obj.query.length) {
let results = await this.mysql.exec(obj.query, obj.params) let results = await this.mysql.exec(obj.query, obj.params)
res.status(200).json(results) res.status(200).json(results)
} else { } else {

8
lib/xsql.js

@ -561,6 +561,8 @@ class Xsql {
let isView = this.metaDb.tables[tableName]['isView']; let isView = this.metaDb.tables[tableName]['isView'];
tableObj['resource'] = tableName; 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 + '/describe', 'describe'))
routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/count', 'count')) routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/count', 'count'))
routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/groupby', 'groupby')) 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 + '/findOne', 'findOne'))
routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/autoChart', 'autoChart')) 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, 'post', apiPrefix, tableName, 'create'))
} }
routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName, 'list')) 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, 'post', apiPrefix, tableName + '/bulk', 'bulkInsert'))
routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/bulk', 'bulkDelete')) routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/bulk', 'bulkDelete'))
} }
routes.push(this.prepareRoute(internal, 'get', apiPrefix, tableName + '/bulk', 'bulkRead')) 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, 'put', apiPrefix, tableName, 'update'))
routes.push(this.prepareRoute(internal, 'patch', apiPrefix, tableName + '/:id', 'patch')) routes.push(this.prepareRoute(internal, 'patch', apiPrefix, tableName + '/:id', 'patch'))
routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/:id', 'delete')) routes.push(this.prepareRoute(internal, 'delete', apiPrefix, tableName + '/:id', 'delete'))

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "xmysql", "name": "xmysql",
"version": "0.4.5", "version": "0.4.6",
"description": "One command to generate REST APIs for any MySql database", "description": "One command to generate REST APIs for any MySql database",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

Loading…
Cancel
Save