{"id":13827695,"url":"https://github.com/o1lab/xmysql","last_synced_at":"2025-04-06T02:12:40.263Z","repository":{"id":40257596,"uuid":"371238171","full_name":"o1lab/xmysql","owner":"o1lab","description":"xmysql is now https://github.com/nocodb/nocodb","archived":false,"fork":false,"pushed_at":"2024-05-27T21:36:15.000Z","size":681,"stargazers_count":170,"open_issues_count":46,"forks_count":52,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-05-28T07:44:37.879Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/nocodb/nocodb","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/o1lab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-27T03:44:31.000Z","updated_at":"2024-05-29T22:04:32.642Z","dependencies_parsed_at":"2024-01-04T02:54:45.822Z","dependency_job_id":"46e33073-adc3-4a83-8e1e-1d54b066e3d8","html_url":"https://github.com/o1lab/xmysql","commit_stats":{"total_commits":3,"total_committers":1,"mean_commits":3.0,"dds":0.0,"last_synced_commit":"8c6b00ee22860230975e43ab705d015d2235e308"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1lab%2Fxmysql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1lab%2Fxmysql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1lab%2Fxmysql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1lab%2Fxmysql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/o1lab","download_url":"https://codeload.github.com/o1lab/xmysql/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247423516,"owners_count":20936626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T09:02:05.548Z","updated_at":"2025-04-06T02:12:40.235Z","avatar_url":"https://github.com/o1lab.png","language":"JavaScript","readme":"![npm version](https://img.shields.io/node/v/xmysql.svg)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/o1lab/xmysql/master/LICENSE)\n\n\u003ch1 align=\"center\" style=\"border-bottom: none\"\u003e\n    \u003cb\u003e\n        \u003ca href=\"https://www.github.com/nocodb/nocodb\"\u003eXmysql is now NocoDB \u003c/a\u003e\u003cbr\u003e\n    \u003c/b\u003e\n    ✨ The Open Source Airtable Alternative ✨ \u003cbr\u003e\n\n\u003c/h1\u003e\n\nhttps://github.com/nocodb/nocodb\n\n## Xmysql : One command to generate REST APIs for any MySql database\n\n## Why this ?\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/rick-and-morty.gif\" alt=\"xmysql gif\"/\u003e\n\u003c/p\u003e\n\nGenerating REST APIs for a MySql database which does not follow conventions of \nframeworks such as rails, django, laravel etc is a small adventure that one like to avoid ..\n\nHence this.\n\n## Setup and Usage\n\nxmysql requires node \u003e= 7.6.0\n\n```\nnpm install -g xmysql\n```\n```\nxmysql -h localhost -u mysqlUsername -p mysqlPassword -d databaseName\n```\n```\nhttp://localhost:3000\n```\n\u003cbr\u003e\n\nThat is it! Simple and minimalistic! \n\nHappy hackery!\n \n\u003c!-- Place this tag where you want the button to render. --\u003e\n\n\n## Example : Generate REST APIs for [Magento](http://www.magereverse.com/index/magento-sql-structure/version/1-7-0-2)\n\nPowered by popular node packages : ([express](https://github.com/expressjs/express), [mysql](https://github.com/mysqljs/mysql)) =\u003e { [xmysql](https://github.com/o1lab/xmysql) }\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/log.gif\" alt=\"xmysql gif\" width=\"750\"/\u003e\n\u003c/p\u003e\n\n \n\u003c!-- AddToAny BEGIN --\u003e\n\u003cdiv align=\"right\"\u003e\n\u003ch3\u003eBoost Your Hacker Karma By Sharing : \u003c/h3\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/sina_weibo?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/weibo.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/renren?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/renren.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/douban?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/doubon.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/vk?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/vk.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/wykop?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/wykop.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/linkedin.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/reddit.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/facebook.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/twitter?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/twitter.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/hacker_news?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=Show%20HN:%20REST%20APIs%20for%20Magento%20database%20within%20seconds!\" target=\"_blank\"\u003e\u003cimg src=\"./assets/hn1.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\u003c!-- AddToAny END --\u003e\n\n\n\n## Features\n* Generates API for **ANY** MySql database :fire::fire:\n* Serves APIs irrespective of naming conventions of primary keys, foreign keys, tables etc :fire::fire:\n* Support for composite primary keys :fire::fire:\n* REST API Usual suspects : CRUD, List, FindOne, Count, Exists, Distinct\n* Bulk insert, Bulk delete, Bulk read :fire:   \n* Relations\n* Pagination \n* Sorting\n* Column filtering - Fields :fire:  \n* Row filtering - Where :fire:\n* Aggregate functions\n* Group By, Having (as query params) :fire::fire:  \n* Group By, Having (as a separate API) :fire::fire:  \n* Multiple group by in one API :fire::fire::fire::fire:\n* Chart API for numeric column :fire::fire::fire::fire::fire::fire:\n* Auto Chart API - (a gift for lazy while prototyping) :fire::fire::fire::fire::fire::fire:\n* [XJOIN - (Supports any number of JOINS)](#xjoin) :fire::fire::fire::fire::fire::fire::fire::fire::fire:\n* Supports views  \n* Prototyping (features available when using local MySql server only)\n    * Run dynamic queries :fire::fire::fire:\n    * Upload single file\n    * Upload multiple files\n    * Download file\n* Health and version apis\n* Use more than one CPU Cores\n* [Docker support](#docker) and [Nginx reverse proxy config](#nginx-reverse-proxy-config-with-docker) :fire::fire::fire: - Thanks to [@markuman](https://github.com/markuman)  \n* AWS Lambda Example - Thanks to [@bertyhell](https://github.com/bertyhell) :fire::fire::fire:\n\n\nUse HTTP clients like [Postman](https://www.getpostman.com/) or [similar tools](https://chrome.google.com/webstore/search/http%20client?_category=apps) to invoke REST API calls\n\n____\n\nDownload [node](https://nodejs.org/en/download/current/), \n[mysql](https://dev.mysql.com/downloads/mysql/) \n[(setup mysql)](https://dev.mysql.com/doc/mysql-getting-started/en/#mysql-getting-started-installing), \n[sample database](https://dev.mysql.com/doc/employee/en/employees-installation.html) -\nif you haven't on your system.\n\n\n## API Overview\n\n| HTTP Type | API URL                          | Comments                                               |\n|-----------|----------------------------------|--------------------------------------------------------- \n| GET       | /                                | Gets all REST APIs                                     |\n| GET       | /api/tableName                   | Lists rows of table                                    |\n| POST      | /api/tableName                   | Create a new row                                       |\n| PUT       | /api/tableName                   | Replaces existing row with new row                     |\n| POST :fire:| /api/tableName/bulk             | Create multiple rows - send object array in request body|\n| GET  :fire:| /api/tableName/bulk             | Lists multiple rows - /api/tableName/bulk?_ids=1,2,3   |\n| DELETE :fire:| /api/tableName/bulk           | Deletes multiple rows - /api/tableName/bulk?_ids=1,2,3 |\n| GET       | /api/tableName/:id               | Retrieves a row by primary key                         |\n| PATCH     | /api/tableName/:id               | Updates row element by primary key                     |\n| DELETE    | /api/tableName/:id               | Delete a row by primary key                            |\n| GET       | /api/tableName/findOne           | Works as list but gets single record matching criteria |\n| GET       | /api/tableName/count             | Count number of rows in a table                        |\n| GET       | /api/tableName/distinct          | Distinct row(s) in table - /api/tableName/distinct?_fields=col1|\n| GET       | /api/tableName/:id/exists        | True or false whether a row exists or not              |\n| GET       | [/api/parentTable/:id/childTable](#relational-tables)             | Get list of child table rows with parent table foreign key   | \n| GET :fire:| [/api/tableName/aggregate](#aggregate-functions)                  | Aggregate results of numeric column(s)                 |\n| GET :fire:| [/api/tableName/groupby](#group-by-having-as-api)                 | Group by results of column(s)                          |\n| GET :fire:| [/api/tableName/ugroupby](#union-of-multiple-group-by-statements) | Multiple group by results using one call               |\n| GET :fire:| [/api/tableName/chart](#chart)                                    | Numeric column distribution based on (min,max,step) or(step array) or (automagic)|\n| GET :fire:| [/api/tableName/autochart](#autochart)                            | Same as Chart but identifies which are numeric column automatically - gift for lazy while prototyping|\n| GET :fire:| [/api/xjoin](#xjoin)                                              | handles join                                        |\n| GET :fire:| [/dynamic](#run-dynamic-queries)                                  | execute dynamic mysql statements with params           |\n| GET :fire:| [/upload](#upload-single-file)                                    | upload single file                                     |\n| GET :fire:| [/uploads](#upload-multiple-files)                                | upload multiple files                                  |\n| GET :fire:| [/download](#download-file)                                       | download a file                                        |\n| GET       | /api/tableName/describe                                           | describe each table for its columns      |\n| GET       | /api/tables                                                       | get all tables in database                           |\n| GET       | [/_health](#health)                                               | gets health of process and mysql -- details query params for more details |\n| GET       | [/_version](#version)                                             | gets version of Xmysql, mysql, node|\n\n\n## Relational Tables \nxmysql identifies foreign key relations automatically and provides GET api.\n```\n/api/blogs/103/comments\n```\neg: blogs is parent table and comments is child table. API invocation will result in all comments for blog primary key 103.\n[:arrow_heading_up:](#api-overview)\n\n\n## Support for composite primary keys\n\n#### ___ (three underscores)\n\n```\n/api/payments/103___JM555205\n```\n*___* : If there are multiple primary keys - separate them by three underscores as shown\n\n## Pagination\n\n#### _p \u0026 _size\n\n_p indicates page and _size indicates size of response rows\n\nBy default 20 records and max of 100 are returned per GET request on a table.\n\n```\n/api/payments?_size=50\n```\n```\n/api/payments?_p=2\n```\n```\n/api/payments?_p=2\u0026_size=50\n```\n\nWhen _size is greater than 100 - number of records defaults to 100 (i.e maximum)\n\nWhen _size is less than or equal to 0 - number of records defaults to 20 (i.e minimum)\n\n## Order by / Sorting \n\n#### ASC\n\n```\n/api/payments?_sort=column1\n```\neg: sorts ascending by column1\n\n#### DESC\n\n```\n/api/payments?_sort=-column1\n```\neg: sorts descending by column1\n\n#### Multiple fields in sort \n\n```\n/api/payments?_sort=column1,-column2\n```\neg: sorts ascending by column1 and descending by column2\n\n\n## Column filtering / Fields\n```\n/api/payments?_fields=customerNumber,checkNumber\n```\neg: gets only customerNumber and checkNumber in response of each record\n```\n/api/payments?_fields=-checkNumber\n```\neg: gets all fields in table row but not checkNumber\n\n## Row filtering / Where\n\n#### Comparison operators\n\n```\neq      -   '='         -  (colName,eq,colValue)\nne      -   '!='        -  (colName,ne,colValue)\ngt      -   '\u003e'         -  (colName,gt,colValue)\ngte     -   '\u003e='        -  (colName,gte,colValue)\nlt      -   '\u003c'         -  (colName,lt,colValue)\nlte     -   '\u003c='        -  (colName,lte,colValue)\nis      -   'is'        -  (colName,is,true/false/null)\nin      -   'in'        -  (colName,in,val1,val2,val3,val4)\nbw      -   'between'   -  (colName,bw,val1,val2) \nlike    -   'like'      -  (colName,like,~name)   note: use ~ in place of % \nnlike   -   'not like'  -  (colName,nlike,~name)  note: use ~ in place of %\n```\n\n#### Use of comparison operators\n```\n/api/payments?_where=(checkNumber,eq,JM555205)~or((amount,gt,200)~and(amount,lt,2000))\n```\n\n#### Logical operators\n```\n~or     -   'or'\n~and    -   'and'\n~xor    -   'xor'\n```\n\n#### Use of logical operators\n\neg: simple logical expression\n```\n/api/payments?_where=(checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933)\n```\n\neg: complex logical expression\n```\n/api/payments?_where=((checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933))~and(amount,gt,100)\n```\n\neg: logical expression with sorting(_sort), pagination(_p), column filtering (_fields)\n```\n/api/payments?_where=(amount,gte,1000)\u0026_sort=-amount\u0026p=2\u0026_fields=customerNumber\n```\n\neg: filter of rows using _where is available for relational route URLs too.\n```\n/api/offices/1/employees?_where=(jobTitle,eq,Sales%20Rep)\n```\n\n## FindOne\n```\n/api/tableName/findOne?_where=(id,eq,1)\n```\nWorks similar to list but only returns top/one result. Used in conjunction with _where\n[:arrow_heading_up:](#api-overview)\n\n## Count\n```\n/api/tableName/count\n```\n\nReturns number of rows in table\n[:arrow_heading_up:](#api-overview)\n\n## Exists\n```\n/api/tableName/1/exists\n```\n\nReturns true or false depending on whether record exists\n[:arrow_heading_up:](#api-overview)\n\n## Group By Having as query params\n[:arrow_heading_up:](#api-overview)\n\n```\n/api/offices?_groupby=country\n```\neg: SELECT country,count(*) FROM offices GROUP BY country\n\n```\n/api/offices?_groupby=country\u0026_having=(_count,gt,1)\n```\neg: SELECT country,count(1) as _count FROM offices GROUP BY country having _count \u003e 1\n\n\n## Group By Having as API\n[:arrow_heading_up:](#api-overview)\n\n```\n/api/offices/groupby?_fields=country\n```\neg: SELECT country,count(*) FROM offices GROUP BY country\n\n```\n/api/offices/groupby?_fields=country,city\n```\neg: SELECT country,city,count(*) FROM offices GROUP BY country,city\n\n```\n/api/offices/groupby?_fields=country,city\u0026_having=(_count,gt,1)\n```\neg: SELECT country,city,count(*) as _count FROM offices GROUP BY country,city having _count \u003e 1\n\n\n### Group By, Order By\n[:arrow_heading_up:](#api-overview)\n\n```\n/api/offices/groupby?_fields=country,city\u0026_sort=city\n```\neg: SELECT country,city,count(*) FROM offices GROUP BY country,city ORDER BY city ASC\n\n```\n/api/offices/groupby?_fields=country,city\u0026_sort=city,country\n```\neg: SELECT country,city,count(*) FROM offices GROUP BY country,city ORDER BY city ASC, country ASC\n\n```\n/api/offices/groupby?_fields=country,city\u0026_sort=city,-country\n```\neg: SELECT country,city,count(*) FROM offices GROUP BY country,city ORDER BY city ASC, country DESC\n\n\n## Aggregate functions\n[:arrow_heading_up:](#api-overview)\n\n```\nhttp://localhost:3000/api/payments/aggregate?_fields=amount\n\nresponse body\n[\n    {\n        \"min_of_amount\": 615.45,\n        \"max_of_amount\": 120166.58,\n        \"avg_of_amount\": 32431.645531,\n        \"sum_of_amount\": 8853839.23,\n        \"stddev_of_amount\": 20958.625377426568,\n        \"variance_of_amount\": 439263977.71130896\n    }\n]\n```\n\neg: retrieves all numeric aggregate of a column in a table\n\n```\nhttp://localhost:3000/api/orderDetails/aggregate?_fields=priceEach,quantityOrdered\n\nresponse body\n[\n    {\n        \"min_of_priceEach\": 26.55,\n        \"max_of_priceEach\": 214.3,\n        \"avg_of_priceEach\": 90.769499,\n        \"sum_of_priceEach\": 271945.42,\n        \"stddev_of_priceEach\": 36.576811252187795,\n        \"variance_of_priceEach\": 1337.8631213781719,\n        \"min_of_quantityOrdered\": 6,\n        \"max_of_quantityOrdered\": 97,\n        \"avg_of_quantityOrdered\": 35.219,\n        \"sum_of_quantityOrdered\": 105516,\n        \"stddev_of_quantityOrdered\": 9.832243813502942,\n        \"variance_of_quantityOrdered\": 96.67301840816688\n    }\n]\n```\n\neg: retrieves numeric aggregate can be done for multiple columns too \n\n## Union of multiple group by statements \n[:arrow_heading_up:](#api-overview)\n\n:fire::fire:**[ HOTNESS ALERT ]**\n\nGroup by multiple columns in one API call using _fields query params - comes really handy\n\n```\nhttp://localhost:3000/api/employees/ugroupby?_fields=jobTitle,reportsTo\n\nresponse body\n{  \n   \"jobTitle\":[  \n      {  \n         \"Sales Rep\":17\n      },\n      {  \n         \"President\":1\n      },\n      {  \n         \"Sale Manager (EMEA)\":1\n      },\n      {  \n         \"Sales Manager (APAC)\":1\n      },\n      {  \n         \"Sales Manager (NA)\":1\n      },\n      {  \n         \"VP Marketing\":1\n      },\n      {  \n         \"VP Sales\":1\n      }\n   ],\n   \"reportsTo\":[  \n      {  \n         \"1002\":2\n      },\n      {  \n         \"1056\":4\n      },\n      {  \n         \"1088\":3\n      },\n      {  \n         \"1102\":6\n      },\n      {  \n         \"1143\":6\n      },\n      {  \n         \"1621\":1\n      }\n      {  \n         \"\":1\n      },\n   ]\n}\n```\n\n\n## Chart \n[:arrow_heading_up:](#api-overview)\n\n:fire::fire::fire::fire::fire::fire: **[ HOTNESS ALERT ]**\n\nChart API returns distribution of a numeric column in a table\n\nIt comes in **SEVEN** powerful flavours\n\n1. Chart : With min, max, step in query params :fire::fire:\n[:arrow_heading_up:](#api-overview)\n\nThis API returns the number of rows where amount is between (0,25000), (25001,50000) ...\n\n```\n/api/payments/chart?_fields=amount\u0026min=0\u0026max=131000\u0026step=25000\n\nResponse\n\n[\n  {\n    \"amount\": \"0 to 25000\",\n    \"_count\": 107\n  },\n  {\n    \"amount\": \"25001 to 50000\",\n    \"_count\": 124\n  },\n  {\n    \"amount\": \"50001 to 75000\",\n    \"_count\": 30\n  },\n  {\n    \"amount\": \"75001 to 100000\",\n    \"_count\": 7\n  },\n  {\n    \"amount\": \"100001 to 125000\",\n    \"_count\": 5\n  },\n  {\n    \"amount\": \"125001 to 150000\",\n    \"_count\": 0\n  }\n]\n\n```\n\n2. Chart : With step array in params :fire::fire:\n[:arrow_heading_up:](#api-overview)\n\nThis API returns distribution between the step array specified\n\n```\n/api/payments/chart?_fields=amount\u0026steparray=0,10000,20000,70000,140000\n\nResponse\n\n[\n  {\n    \"amount\": \"0 to 10000\",\n    \"_count\": 42\n  },\n  {\n    \"amount\": \"10001 to 20000\",\n    \"_count\": 36\n  },\n  {\n    \"amount\": \"20001 to 70000\",\n    \"_count\": 183\n  },\n  {\n    \"amount\": \"70001 to 140000\",\n    \"_count\": 12\n  }\n]\n\n\n```\n\n3. Chart : With step pairs in params :fire::fire:\n[:arrow_heading_up:](#api-overview)\n\nThis API returns distribution between each step pair\n\n```\n/api/payments/chart?_fields=amount\u0026steppair=0,50000,40000,100000\n\nResponse\n\n[\n    {\"amount\":\"0 to 50000\",\"_count\":231},\n    {\"amount\":\"40000 to 100000\",\"_count\":80}\n]\n\n\n```\n\n4. Chart : with no params :fire::fire:\n[:arrow_heading_up:](#api-overview)\n\nThis API figures out even distribution of a numeric column in table and returns the data\n\n```\n/api/payments/chart?_fields=amount\n\nResponse\n[\n  {\n    \"amount\": \"-9860 to 11100\",\n    \"_count\": 45\n  },\n  {\n    \"amount\": \"11101 to 32060\",\n    \"_count\": 91\n  },\n  {\n    \"amount\": \"32061 to 53020\",\n    \"_count\": 109\n  },\n  {\n    \"amount\": \"53021 to 73980\",\n    \"_count\": 16\n  },\n  {\n    \"amount\": \"73981 to 94940\",\n    \"_count\": 7\n  },\n  {\n    \"amount\": \"94941 to 115900\",\n    \"_count\": 3\n  },\n  {\n    \"amount\": \"115901 to 130650\",\n    \"_count\": 2\n  }\n]\n\n```\n\n5. Chart : range, min, max, step in query params :fire::fire:\n [:arrow_heading_up:](#api-overview)\n \n This API returns the number of rows where amount is between (0,25000), (0,50000) ... (0,maxValue)\n \n Number of records for amount is counted from min value to extended *Range* instead of incremental steps\n \n ```\n /api/payments/chart?_fields=amount\u0026min=0\u0026max=131000\u0026step=25000\u0026range=1\n \n Response\n \n[\n    {\n        \"amount\": \"0 to 25000\",\n        \"_count\": 107\n    },\n    {\n        \"amount\": \"0 to 50000\",\n        \"_count\": 231\n    },\n    {\n        \"amount\": \"0 to 75000\",\n        \"_count\": 261\n    },\n    {\n        \"amount\": \"0 to 100000\",\n        \"_count\": 268\n    },\n    {\n        \"amount\": \"0 to 125000\",\n        \"_count\": 273\n    }\n]\n \n ```\n\n6. Range can be specified with step array like below\n\n ```\n/api/payments/chart?_fields=amount\u0026steparray=0,10000,20000,70000,140000\u0026range=1\n\n[\n    {\n        \"amount\": \"0 to 10000\",\n        \"_count\": 42\n    },\n    {\n        \"amount\": \"0 to 20000\",\n        \"_count\": 78\n    },\n    {\n        \"amount\": \"0 to 70000\",\n        \"_count\": 261\n    },\n    {\n        \"amount\": \"0 to 140000\",\n        \"_count\": 273\n    }\n]\n ```\n \n7. Range can be specified without any step params like below\n\n```\n/api/payments/chart?_fields=amount\u0026range=1\n\n[\n    {\n        \"amount\": \"-9860 to 11100\",\n        \"_count\": 45\n    },\n    {\n        \"amount\": \"-9860 to 32060\",\n        \"_count\": 136\n    },\n    ...\n    \n]\n\n```\n\nPlease Note:\n_fields in Chart API can only take numeric column as its argument.  \n\n## Autochart\n\nIdentifies numeric columns in a table which are not any sort of key and applies chart API as before - \nfeels like magic when there are multiple numeric columns in table while hacking/prototyping and you invoke this API.\n\n```\nhttp://localhost:3000/api/payments/autochart\n\n[\n    {\n        \"column\": \"amount\",\n        \"chart\": [\n                    {\n                        \"amount\": \"-9860 to 11100\",\n                        \"_count\": 45\n                    },\n                    {\n                        \"amount\": \"11101 to 32060\",\n                        \"_count\": 91\n                    },\n                    {\n                        \"amount\": \"32061 to 53020\",\n                        \"_count\": 109\n                    },\n                    {\n                        \"amount\": \"53021 to 73980\",\n                        \"_count\": 16\n                    },\n                    {\n                        \"amount\": \"73981 to 94940\",\n                        \"_count\": 7\n                    },\n                    {\n                        \"amount\": \"94941 to 115900\",\n                        \"_count\": 3\n                    },\n                    {\n                        \"amount\": \"115901 to 130650\",\n                        \"_count\": 2\n                    }\n                ]\n    }\n]\n```\n\n## XJOIN\n\n### Xjoin query params and values:\n\n```\n_join           :   List of tableNames alternated by type of join to be made (_j, _ij,_ lj, _rj)\nalias.tableName :   TableName as alias\n_j              :   Join [ _j =\u003e join, _ij =\u003e ij, _lj =\u003e left join , _rj =\u003e right join)\n_onNumber       :   Number 'n' indicates condition to be applied for 'n'th join between (n-1) and 'n'th table in list  \n``` \n\n#### Simple example of two table join:\n\nSql join query:\n\n```sql\n\nSELECT pl.field1, pr.field2\nFROM productlines as pl\n    JOIN products as pr\n        ON pl.productline = pr.productline\n\n```\n\nEquivalent xjoin query API:\n```\n/api/xjoin?_join=pl.productlines,_j,pr.products\u0026_on1=(pl.productline,eq,pr.productline)\u0026_fields=pl.field1,pr.field2\n```\n\n#### Multiple tables join\n\nSql join query:\n```sql\nSELECT pl.field1, pr.field2, ord.field3\nFROM productlines as pl\n    JOIN products as pr\n        ON pl.productline = pr.productline\n    JOIN orderdetails as ord\n        ON pr.productcode = ord.productcode\n```\n\nEquivalent xjoin query API:\n\n```\n/api/xjoin?_join=pl.productlines,_j,pr.products,_j,ord.orderDetails\u0026_on1=(pl.productline,eq,pr.productline)\u0026_on2=(pr.productcode,eq,ord.productcode)\u0026_fields=pl.field1,pr.field2,ord.field3\n\n```\n\n**Explanation:**\n\u003e pl.productlines =\u003e productlines as pl\n\n\u003e _j =\u003e join\n\n\u003e pr.products =\u003e products as pl\n\n\u003e _on1 =\u003e join condition between productlines and products =\u003e (pl.productline,eq,pr.productline)\n\n\u003e _on2 =\u003e join condition between products and orderdetails =\u003e (pr.productcode,eq,ord.productcode)\n\nExample to use : _fields, _where, _p, _size in query params  \n\n```\n/api/xjoin?_join=pl.productlines,_j,pr.products\u0026_on1=(pl.productline,eq,pr.productline)\u0026_fields=pl.productline,pr.productName\u0026_size=2\u0026_where=(productName,like,1972~)\n```\n\nResponse:\n\n```\n[{\"pl_productline\":\"Classic Cars\",\"pr_productName\":\"1972 Alfa Romeo GTA\"}]\n```\n\nPlease note : \nXjoin response has aliases for fields like below aliasTableName + '_' + columnName.   \neg: pl.productline in _fields query params - returns as pl_productline in response. \n\n## Run dynamic queries\n[:arrow_heading_up:](#api-overview)\n\nDynamic queries on a database can be run by POST method to URL localhost:3000/dynamic \n\nThis is enabled **ONLY when using local mysql server** i.e -h localhost or -h 127.0.0.1 option.\n\nPost body takes two fields : query and params.\n\n\u003equery: SQL query or SQL prepared query (ones with ?? and ?)\n\n\u003eparams : parameters for SQL prepared query\n```\nPOST /dynamic   \n\n    {\n        \"query\": \"select * from ?? limit 1,20\",\n        \"params\": [\"customers\"]\n    }\n```\n\nPOST /dynamic URL can have any suffix to it - which can be helpful in prototyping\n\neg:\n\n``` \nPOST /dynamic/weeklyReport\n```\n\n```\nPOST /dynamic/user/update\n```\n\n\n## Upload single file\n[:arrow_heading_up:](#api-overview)\n\n```\nPOST /upload\n```\nDo POST operation on /upload url with multiform 'field' assigned to local file to be uploaded\n\neg: curl --form file=@/Users/me/Desktop/a.png http://localhost:3000/upload\n\nreturns uploaded file name else 'upload failed'\n\n(Note: POSTMAN has issues with file uploading hence examples with curl) \n\n\n## Upload multiple files\n[:arrow_heading_up:](#api-overview)\n\n```\nPOST /uploads\n```\nDo POST operation on /uploads url with multiform 'fields' assigned to local files to be uploaded\n\n\u003e Notice 's' near /api/upload**s** and file**s** in below example\n\neg: curl --form files=@/Users/me/Desktop/a.png --form files=@/Users/me/Desktop/b.png  http://localhost:3000/uploads\n\nreturns uploaded file names as string\n\n## Download file\n[:arrow_heading_up:](#api-overview)\n\nhttp://localhost:3000/download?name=fileName\n\n\u003e For upload and download of files -\u003e you can specify storage folder using -s option\n\u003e Upload and download apis are available only with local mysql server\n\n## Health \n[:arrow_heading_up:](#api-overview)\n\nhttp://localhost:3000/_health\n\n```\n{\"process_uptime\":3.858,\"mysql_uptime\":\"2595\"}\n```\n\nShows up time of Xmysql process and mysql server\n\n\nhttp://localhost:3000/_health?details=1\n\n```\n{\"process_uptime\":1.151,\"mysql_uptime\":\"2798\",\n\"os_total_memory\":17179869184,\n\"os_free_memory\":2516357120,\n\"os_load_average\":[2.29931640625,2.1845703125,2.13818359375],\n\"v8_heap_statistics\":{\"total_heap_size\":24735744,\n\"total_heap_size_executable\":5242880,\n\"total_physical_size\":23521048,\n\"total_available_size\":1475503064,\n\"used_heap_size\":18149064,\n\"heap_size_limit\":1501560832,\n\"malloced_memory\":8192,\n\"peak_malloced_memory\":11065664,\n\"does_zap_garbage\":0}}\n```\n\nProvides more details on process.\n\nInfact passing any query param gives detailed health output: example below  \n\nhttp://localhost:3000/_health?voila\n```\n{\"process_uptime\":107.793,\"mysql_uptime\":\"2905\",\"os_total_memory\":17179869184,\"os_free_memory\":2573848576,\"os_load_average\":[2.052734375,2.12890625,2.11767578125],\"v8_heap_statistics\":{\"total_heap_size\":24735744,\"total_heap_size_executable\":5242880,\"total_physical_size\":23735016,\"total_available_size\":1475411128,\"used_heap_size\":18454968,\"heap_size_limit\":1501560832,\"malloced_memory\":8192,\"peak_malloced_memory\":11065664,\"does_zap_garbage\":0}}\n```\n\n## Version\n[:arrow_heading_up:](#api-overview)\n\nhttp://localhost:3000/_version\n\n```\n{\"Xmysql\":\"0.4.1\",\"mysql\":\"5.7.15\",\"node\":\"8.2.1\"}\n```\n\n## When to use ?\n[:arrow_heading_up:](#api-overview)\n\n* You need just REST APIs for (ANY) MySql database at blink of an eye (literally).\n* You are learning new frontend frameworks and need REST APIs for your MySql database.\n* You are working on a demo, hacks etc\n\n## When NOT to use ?\n[:arrow_heading_up:](#api-overview)\n\n* If you are in need of a full blown MVC framework, ACL, Validations, Authorisation etc - its early days please watch/star this repo to keep a tab on progress. \n\n\n### Command line options\n[:arrow_heading_up:](#api-overview)\n\n```\n  Options:\n\n    -V, --version            Output the version number\n    -h, --host \u003cn\u003e           Hostname of database -\u003e localhost by default\n    -u, --user \u003cn\u003e           Username of database -\u003e root by default\n    -p, --password \u003cn\u003e       Password of database -\u003e empty by default\n    -d, --database \u003cn\u003e       database schema name\n    -r, --ipAddress \u003cn\u003e      IP interface of your server / localhost by default    \n    -n, --portNumber \u003cn\u003e     Port number for app -\u003e 3000 by default\n    -o, --port \u003cn\u003e           Port number of mysql -\u003e 3306 by default\n    -a, --apiPrefix \u003cn\u003e      Api url prefix -\u003e /api/ by default\n    -s, --storageFolder \u003cn\u003e  Storage folder -\u003e current working dir by default (available only with local)\n    -i, --ignoreTables \u003cn\u003e   Comma separated table names to ignore\n    -c, --useCpuCores \u003cn\u003e    Specify number of cpu cores to use / 1 by default / 0 to use max\n    -y, --readOnly           readonly apis -\u003e false by default    \n    -h, --help               Output usage information\n\n    \n  Examples:\n\n    $ xmysql -u username -p password -d databaseSchema\n```\n\u003c!-- AddToAny BEGIN --\u003e\n\u003cdiv align=\"right\"\u003e\n\u003ch3\u003eBoost Your Hacker Karma By Sharing : \u003c/h3\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/sina_weibo?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/weibo.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/renren?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/renren.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/douban?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/doubon.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/vk?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/vk.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/wykop?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20Database%20\" target=\"_blank\"\u003e\u003cimg src=\"./assets/wykop.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/linkedin.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/reddit?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/reddit.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/facebook.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/twitter?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=One%20command%20to%20generate%20REST%20APIs%20for%20any%20MySql%20database.\" target=\"_blank\"\u003e\u003cimg src=\"./assets/twitter.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.addtoany.com/add_to/hacker_news?linkurl=https%3A%2F%2Fgithub.com%2Fo1lab%2Fxmysql%2F\u0026amp;linkname=Show%20HN:%20REST%20APIs%20for%20Magento%20database%20within%20seconds!\" target=\"_blank\"\u003e\u003cimg src=\"./assets/hn1.png\" width=\"32\" height=\"32\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\u003c!-- AddToAny END --\u003e\n\n\n\n# Docker\n[:arrow_heading_up:](#features)\n\nSimply run with `docker run -p 3000:80 -d markuman/xmysql:0.4.2`\n\nThe best way for testing is to run mysql in a docker container too and create a docker network, so that `xmysql` can access the `mysql` container with a name from docker network.\n\n1. Create network \n    * `docker network create mynet`\n2. Start mysql with docker name `some-mysql` and bind to docker network `mynet`\n    * `docker run --name some-mysql -p 3306:3306 --net mynet -e MYSQL_ROOT_PASSWORD=password -d markuman/mysql`\n3. run xmysql and set env variable for `some-mysql` from step 2\n    * `docker run -p 3000:80 -d -e DATABASE_HOST=some-mysql --net mynet markuman/xmysql`\n\nYou can also pass the environment variables to a file and use them as an option with docker like `docker run --env-file ./env.list -p 3000:80 --net mynet -d markuman/xmysql`\n\nenvironment variables which can be used:\n\n```\nENV DATABASE_HOST 127.0.0.1\nENV DATABASE_USER root\nENV DATABASE_PASSWORD password\nENV DATABASE_NAME sakila\n```\n\nFurthermore, the docker container of xmysql is listen on port 80. You can than request it just with `http://xmysql/api/` in other services running in the same docker network.\n\n## Debugging xmysql in docker.\n\nGiven you've deployed your xmysql docker container like \n\n```shell\ndocker run -d \\\n--network local_dev \\\n--name xmysql \\\n-p 3000:80 \\\n-e DATABASE_HOST=mysql_host \\\n-e DATABASE_USER=root \\\n-e DATABASE_PASSWORD=password \\\n-e DATABASE_NAME=sys \\\nmarkuman/xmysql:0.4.2\n```\n\nbut the response is just\n\n```json\n[\"http://127.0.0.1:3000/api/tables\",\"http://127.0.0.1:3000/api/xjoin\"]\n```\n\nthen obviously the connection to your mysql database failed.  \n\n1. attache to the xmysql image\n    * `docker exec -ti xmysql`\n2. install mysql cli client\n    * `apk --update --no-cache add mysql-client`\n3. try to access your mysql database\n   * `mysql-client -h mysql_host`\n4. profit from the `mysql-client` error output and improve the environment variables for mysql\n\n# Nginx Reverse Proxy Config with Docker\n[:arrow_heading_up:](#features)\n\nThis is a config example when you use nginx as reverse proxy\n\n```\nevents {\n   worker_connections 1024;\n   \n}\nhttp {\n    server {\n        server_name 127.0.0.1;\n        listen 80 ;\n        location / {\n            rewrite ^/(.*) /$1 break;\n            proxy_redirect off;\n            proxy_set_header Host $host;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_pass http://127.0.0.1:3000;\n        }\n    }\n}\n```\n\ne.g.\n\n0. create a docker network `docker network create local_dev`\n1. start a mysql server `docker run -d --name mysql -p 3306:3306 --network local_dev -e MYSQL_ROOT_PASSWORD=password mysql`\n2. start xmysql `docker run -d --network local_dev --name xmyxql -e DATABASE_NAME=sys -e DATABASE_HOST=mysql -p 3000:80 markuman/xmysql:0.4.2`\n3. start nginx on host system with the config above `sudo nginx -g 'daemon off;' -c /tmp/nginx.conf`\n4. profit `curl http://127.0.0.1/api/host_summary_by_file_io_type/describe`\n\nWhen you start your nginx proxy in a docker container too, use as `proxy_pass` the `--name` value of xmysql. E.g. `proxy_pass http://xmysql` (remember, xmysql runs in it's docker container already on port 80).\n\n\n# Tests : setup on local machine\n[:arrow_heading_up:](#api-overview)\n```\ndocker-compose run test\n```\n* Requires `docker-compose` to be installed on your machine.\n","funding_links":[],"categories":["JavaScript","API Frameworks"],"sub_categories":["MySQL"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo1lab%2Fxmysql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fo1lab%2Fxmysql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo1lab%2Fxmysql/lists"}