mysqlをrestでアクセスできてもいいじゃない

## RDB v.s KVS
KVS触っていて、「RESTAPIがあるのっていいなー」とは思う。複雑なクエリは出せないけど、curlコマンド一発でアクセスできる。だったら複雑ではないクエリなら、mysqlにそういうRESTのかぶせものがあってもいい。

## mysql-to-restは nodeで使える、mysqlにREST をかぶせるライブラリ

https://www.npmjs.com/package/mysql-to-rest

以下、mysql-to-restを使ったサンプルソース。依存モジュールはmysql-to-restのREADMEにしたがって入れてください。手元にポケモンGOのポケモンの出現情報をためたテーブルがあるのでそれを取得してみた。

```sample.js
var mysql      = require('mysql');
var connection = mysql.createConnection({
    host     : 'localhost',
    user     : 'root',
    password : '', 
    database : 'sample',
    timezone : 'Asia/Tokyo' //これいれないとUTCで出ちゃう
});

connection.connect();

var express = require('express');
var mysqltorest  = require('mysql-to-rest');
var app = express();

app.set('trust proxy', 'loopback'); // 同一セグメントからのみの接続を許可
// app.set('trust proxy', 'loopback,192.168.0.1'); // 同一セグメントプラス特定IPのみ許可 

var api = mysqltorest(app,connection);
app.listen(8000);
~                
```

実行

```lang:sh
> node sample.js
```

テスト

appearances というテーブルの、主キーが、１１，１２，１３というレコードを取得

```
curl http://localhost:8000/api/appearances/11,12,13
```

レスポンス

```lang:json
{
  "result": "success",
  "json": [
    {
      "id": 11,
      "pokemon_id": 69,
      "pokemon_name": "マダツボミ",
      "lat": 35.64469,
      "lon": 139.687588,
      "distance": 588.94278,
      "expired": "2016-07-30 12:40:18",
      "query_lat": 35.644393,
      "query_lon": 139.681088,
      "landmark": "世田谷公園",
      "created_at": "2016-07-30 12:34:54",
      "updated_at": "2016-07-30 12:34:54"
    },
    {
      "id": 12,
      "pokemon_id": 74,
      "pokemon_name": "イシツブテ",
      "lat": 35.646162,
      "lon": 139.68679,
      "distance": 552.19259,
      "expired": "2016-07-30 12:37:13",
      "query_lat": 35.644393,
      "query_lon": 139.681088,
      "landmark": "世田谷公園",
      "created_at": "2016-07-30 12:34:54",
      "updated_at": "2016-07-30 12:34:54"
    },
    {
      "id": 13,
      "pokemon_id": 23,
      "pokemon_name": "アーボ",
      "lat": 35.649789,
      "lon": 139.68368,
      "distance": 644.8466,
      "expired": "2016-07-30 12:36:55",
      "query_lat": 35.644393,
      "query_lon": 139.681088,
      "landmark": "世田谷公園",
      "created_at": "2016-07-30 12:34:54",
      "updated_at": "2016-07-30 12:34:54"
    }
  ],
  "table": "appearances",
  "length": 3
}
```

## 他にもいろんなクエリのサンプル

- ポケモンIDが１１より小さいレコードを取得
 - http://localhost:8000/api/appearances/?pokemon_id[SMALL]=11
- idというフィールド名の降順に並べて１００件取得
 - http://localhost:8000/api/appearances/?_limit=100&_order[id]=desc
- 作成日が2016-07-30 15:58:00 以降のレコード
 - http://localhost:8000/api/appearances/?_limit=1000&_order[id]=desc&created_at[GREAT]=2016-07-30 15:58:00
 - 時刻もそのままの表記で渡せてる

## 実行パフォーマンス

先ほどのキーダイレクトで３件取得するというサンプルで負荷テスト。MBA 1.6 GHz Intel Core i5 のメモリ４G というなんてことのないマシン。

``` 
ab -n 1000 -c 10 http://localhost:8000/api/appearances/11,12,13
```

```
Requests per second:    473.91 [#/sec] (mean)
Time per request:       21.101 [ms] (mean)
Time per request:       2.110 [ms] (mean, across all concurrent requests)
Transfer rate:          606.28 [Kbytes/sec] received
```

同じクエリを流し続けているので、クエリキャッシュがきいてるはずだけど、十分早い。ちょっと重めのSQLになれば、ほとんどDB側の時間になるはず。

## 複雑なSQLは流せない

### JOINをしたかったら？
- 画面の一覧に出すレコードはどうせlimit ２０とかそんなもん
- 取得したあとに、20のレコードにある外部キーで、改めてキーダイレクトで取得
- 取得したあとにプログラム側で結合
ドン臭いけど、JOINはある日突然パフォーマンスが落ちることがある。集十件のレコードを主キー取得するのはいつも一瞬。

もしくは参照頻度があまりに大きかったら、正規化崩してJOIN済みのデーブルを作っちゃっててもいい。


## そこまでやるならとっととKSVを使えばいいじゃない

確かにそうなんだけど、phpmyadmin に相当するいいものがなかったり、SequelProに相当するいいツールがなかったり、オンプレミスとクラウドとローカル開発環境とを同じアーキテクチャでやろうとすると、ちょうどいいのがなかったりとか。そしてやっぱり「表」は楽ちんで、CSVに吐き出してエクセルで見るという導線はやっぱり便利。

そしていざって時に、遅くてもいいからフィールドをLIKE検索したり、groupやcountしたりする。そんなわけでまだまだmysql使っていそうな気がする。