Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
o1lab committed Oct 29, 2017
0 parents commit 67515e0
Show file tree
Hide file tree
Showing 13 changed files with 6,899 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
"eol-last": "error",
"indent": ["error", 2, { "SwitchCase": 1 }],
"no-trailing-spaces": "error",
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }]
}
}
77 changes: 77 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# OS
# ===========
.DS_Store
ehthumbs.db
Icon?
Thumbs.db

# Node and related ecosystem
# ==========================
.nodemonignore
.sass-cache/
node_modules/
help/
a
public/lib/
app/tests/coverage/
.bower-*/
.idea/
coverage/

# MEAN.js app and assets
# ======================
public/dist/
uploads
modules/users/client/img/profile/uploads
config/env/local.js
*.pem

# Ignoring MEAN.JS's gh-pages branch for documenation
_site/

# General
# =======
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.tmp
*.bak
*.swp
logs/
build/
uploads/

# Sublime editor
# ==============
.sublime-project
*.sublime-project
*.sublime-workspace

# Eclipse project files
# =====================
.project
.settings/
.*.md.html
.metadata
*~.nib
local.properties

# IntelliJ
# ========
*.iml

# Cloud9 IDE
# =========
.c9/
data/
mongod

# Visual Studio
# =========
*.suo
*.ntvs*
*.njsproj
*.sln
146 changes: 146 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# xmysql: one command to generate REST APIs for **any** MySql database

> Requires node >= 7.6.0
## Why this ?
Deriving REST APIs for a database which do not follow conventions of frameworks such as rails, django etc
is like a small adventure ..

<p align="center">
<img src="https://media.giphy.com/media/8gWrk3QZrjF1C/giphy.gif" alt="Rick & Morty"/>
</p>

Hence this.

Powered by node packages : (express, mysql) => { xmysql }

## FEATURES
* Generates API for **ANY** MySql database
* Serves APIs irrespective of naming conventions of primary keys, foreign keys, tables etc
* CRUD : Usual suspects
* Support for composite primary keys
* Pagination
* Sorting
* Fields
* Relations
* Run dynamic queries

## Sample usage
* npm install -g xmysql
* xmysql -h localhost -u mysqlUsername -p mysqlPassword -d databaseName
* [http://localhost:3000](#http://localhost:3000)


Run HTTP client [Postman](https://www.getpostman.com/) or [similar tools](https://chrome.google.com/webstore/search/http%20client?_category=apps) to invoke REST API calls

## CRUD APIs Usual Suspects
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName
* POST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/:id
* PUT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/:id
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/count
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/exists
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:parentTable/:id/:childTable
* DELETE&nbsp; /api/:tableName/:id
* POST&nbsp;&nbsp;&nbsp;&nbsp; /dynamic

## Other APIS
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/describe
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/tables

## Support for composite primary keys

#### ___ (three underscores)

```
/api/payments/103___JM555205
```
*___* : If there are multiple primary keys - seperate them by three underscores as shown

## Pagination

#### _p & _size

_p indicates page and _size indicates size of response rows

By default 20 records and max of 100 are returned per GET request on a table.

```
/api/payments?_size=50
```
```
/api/payments?_p=2
```
```
/api/payments?_p=2&_size=50
```


## Sorting

#### _sort

```
/api/payments?_sort=column1
```
eg: sorts ascending by column1

```
/api/payments?_sort=-column1
```
eg: sorts descending by column1

```
/api/payments?_sort=column1,-column2
```
eg: sorts ascending by column1 and descending by column2


## Fields
```
/api/payments?_fields=customerNumber,checkNumber
```
eg: gets only customerNumber and checkNumber in response of each record
```
/api/payments?_fields=-checkNumber
```
eg: gets all fields in table row but not checkNumber


## Run dynamic queries
Dynamic queries on a database can be run by POST method to URL localhost:3000/dynamic

This is enabled only in local i.e -h localhost or -h 127.0.0.1 option.

Post body takes two fields : query and params.

>query: SQL query or SQL prepared query (ones with ?? and ?)
>params : parameters for SQL prepared query
```
POST /dynamic
{
"query": "select * from ?? limit 1,20",
"params": ["customers"]
}
```
## Relational Tables
xmysql identifies foreign key relations automatically and provides GET api.
```
/api/customers/103/payments
```
eg: Customers is parent table and payments is child table. API invocation will result in all payments with customer 103.


## When to use ?
* You need REST APIs without much hassle for (ANY) MySql database
* You are learning new frontend frameworks and need REST APIs for your MySql database.
* You are working on a demo, hacks etc

## When NOT to use ?
* Other times not mentioned in when to use section




39 changes: 39 additions & 0 deletions bin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#! /usr/bin/env node

const morgan = require('morgan');
const bodyParser = require('body-parser');
const express = require('express');
const sqlConfig = require('commander');
const mysql = require('mysql');

const Xapi = require('../lib/xapi.js');
const cmdargs = require('../lib/util/cmd.helper.js');

cmdargs.handle(sqlConfig)



/**************** START : setup express ****************/
let app = express();
app.use(morgan('tiny'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
/**************** END : setup express ****************/


/**************** START : setup mysql ****************/
let mysqlPool = mysql.createPool(sqlConfig);
/**************** END : setup mysql ****************/


/**************** START : setup Xapi ****************/
let moreApis = new Xapi(sqlConfig,mysqlPool,app);

moreApis.init((err, results) => {

app.listen(sqlConfig.portNumber)

})
/**************** END : setup Xapi ****************/
39 changes: 39 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#! /usr/bin/env node

const morgan = require('morgan');
const bodyParser = require('body-parser');
const express = require('express');
const sqlConfig = require('commander');
const mysql = require('mysql');

const Xapi = require('./lib/xapi.js');
const cmdargs = require('./lib/util/cmd.helper.js');

cmdargs.handle(sqlConfig)



/**************** START : setup express ****************/
let app = express();
app.use(morgan('tiny'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
/**************** END : setup express ****************/


/**************** START : setup mysql ****************/
let mysqlPool = mysql.createPool(sqlConfig);
/**************** END : setup mysql ****************/


/**************** START : setup Xapi ****************/
let moreApis = new Xapi(sqlConfig,mysqlPool,app);

moreApis.init((err, results) => {

app.listen(sqlConfig.portNumber)

})
/**************** END : setup Xapi ****************/
70 changes: 70 additions & 0 deletions lib/util/cmd.helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';
const program = require('commander');
const colors = require('colors');

program.on('--help', () => {
console.log('')
console.log(' Examples:'.blue)
console.log('')
console.log(' $ xmysql -u username -p password -d databaseSchema'.blue)
console.log('')
})

program
.version('0.0.2')
.option('-h, --host <n>', 'hostname')
.option('-d, --database <n>', 'database schema name')
.option('-u, --user <n>', 'username of database / root by default')
.option('-p, --password <n>', 'password of database / empty by default')
.option('-n, --portNumber <n>', 'port number : 3000 by default')
.parse(process.argv)


function paintHelp(txt) {
return colors.magenta(txt) //display the help text in a color
}

function processInvalidArguments(program) {

let err = '';

if (!program.password) {
err += 'Error: password for database is missing\n';
}

if (!program.database) {
err += 'Error: database name is missing\n';
}

if (err !== '') {
program.outputHelp(paintHelp)
console.log(err.red)
}
}

exports.handle = program => {

/**************** START : default values ****************/
program.portNumber = program.portNumber || 3000;
program.user = program.user || 'root';
program.password = program.password || '';
program.host = program.host || 'localhost';


program.connectionLimit = 10;

if (program.host === 'localhost' || program.host === '127.0.0.1') {
program.dynamic = 1
}
//console.log(program.rawArgs);
/**************** END : default values ****************/


if (program.database && program.host && program.user) {
console.log('Starting server at:', 'http://'+program.host + ':' + program.portNumber)
} else {
processInvalidArguments(program)
process.exit(1)
}

};

0 comments on commit 67515e0

Please sign in to comment.