5分で組み上げる DB ドリブン REST API コール

#5分で組み上げる DB ドリブン REST API コール
##はじめに
API を呼び出す際、下記のように DB 中のデータとパラメータ設定を連動させるようなロジックを組み上げることよくあると思います。

1. DB へクエリを投げる
2. DB から取得した値を RESTful API のパラメータにセットして呼び出す

最近、API を使うことが多々あり、どうしても冗長化してしまう同ロジックをなんとか簡潔にできないかと
調べていたところ、[RapidQL](http://www.rapidql.com/) なる DB のクエリと RESTful API の呼び出しをチェーンできるライブラリを見つけました。
使ってみたら確かに DB, RESTful API 呼び出しの連動を楽にしてくれました。
今回はこれを使って遊んでみた結果を記事共有したいと思います。
ある程度試行錯誤して慣れた後ではありますが、本当に５分くらいでコーディングできました！

##RapidQL とは
[こちら](https://docs.rapidql.com/docs)の公式サイトを見ますとデータベースや RESTful Web API のクエリを１つにまとめることができるクエリ言語のようです。
REST API コールにおいては GraphQL のように任意のフィールドのみ取得するよう指定もできます。
SQL のようなクエリ言語ですので、基本的にはそれ単体で言語にはなっており、埋め込み SQL 文のようにアプリケーションの処理を行う親プログラム中に埋め込んで使用します。
現行は、Node.js のみのサポートになりますが、今後は Python 等、他の言語へも埋め込めるようにするようです。
RapidQL で書かれたクエリは親の Node.js の実行時に RapidQL の実装が RapidQL のクエリをハンドルするという仕組みのようです。
埋め込み SQL でプリコンパイル --> コンパイルとやるところを内部で全て実行してくれているようなイメージだと思います。

##RapidQL で DB 連動 API 呼び出しロジックを組み上げてみる
###シナリオ
顧客 DB に登録された Email アドレスを API のパラメータにセットし、API 呼び出しをする。ここでは、ZeroBounce というベンダーのメールバウンスチェック（メールアドレスの生存状態をチェックする API）を呼び出してみます。（無料枠を利用）
この一連の流れを１クエリで簡潔に書いてみます。
イメージとしては下図のような感じです。
![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180295/e97d94a4-f426-a82e-5010-b6958c86d97b.png)

###事前準備
1. API をサブスクライブ
 1. [Rakuten RapidAPI](https://api.rakuten.net/signup) へ登録(無料)
 2. [Zerobounce](https://api.rakuten.net/leeann/api/zerobounce1/pricing) の BASIC プランをサブスクライブ(月100コールまで無料で使用可)
 
2. RapidQL をインストール

    ```bash
    $ npm install rapidql
             :
    + rapidql@0.0.6
    added 514 packages in 8.628s
    $
    ```
3. DB を用意
今回は Posgresql を利用。RapidQL としては、Posgresql 以外に MySQL や Redis もサポートしているもようです。
DB がインストールされていない場合は、[こちら](https://qiita.com/_daisuke/items/13996621cf51f835494b)等を参考。
今回用意した postgres 環境はこちらです。
DB 名：postgres
Scheme 名: public
ここに下記のような DDL で customers テーブルを作成し上図のようなデータを入れ込みました。
（桁数や中身は基本的には何でも構いません。）

    ```
    CREATE TABLE public.customers
    (
        customer_id integer NOT NULL,
        customer_name character varying(50),
        email character varying(255)"
    )
    ```

###DB呼び出しロジックを組み上げる
####プログラムを用意

```javascript:rapidqltest.js
const RapidQL = require('RapidQL');

//RapidQL のインスタンス化と同時にDB 接続情報を指定
const rql = new RapidQL({
    PostgreSQL: {
    	postgres: {
    	    user: 'postgres',
    	    database: 'postgres',
    	    password: 'postgres',
    	    host: 'localhost',
    	    port: '5432'
       	}
    }
});

//WHERE 句で渡す顧客ID
const wkCustId = 2222;

//RapidQL 
rql.query(
    `{
        PostgreSQL.postgres.public.customers.find(customer_id: {"=": customerId}){
            email
        }
    }`,
    {
    "customerId": wkCustId
    }
)
.then((res) => console.log(JSON.stringify(res)))
.catch((err) => console.log(err));
```
####実行してみる

```bash
$ node rapidqltest.js
{"PostgreSQL.postgres.public.users.find":[{"email":"muto@moonsault.com"}]}
$ 
```

###API呼び出しロジック取得する
1. [ZeroBounce API](https://api.rakuten.net/leeann/api/zerobounce1) のページへ移動
2. アカウントに紐づいた自分の API キーを確認
3. email 欄に何か入れて API の挙動を確認
3. 「コードスニペット」から「RapidQL」を確認
    イメージとしてはこんな感じです。
    <img width="1312" alt="zerobounce_image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180295/f11d5217-fa57-a1b9-e125-9fe55768f9ce.png">

###API呼び出しロジックを加えてみる
前のステップで確認したコードスニペットを DB クエリした RapidQL クエリにチェーンしてみます。
チェーンは下記のように親のクエリ（ここでは postgresql へのクエリ）から取得する項目にハイフンを付けてクエリを追加するようです。

```javascript
        <中略>
   PostgreSQL.postgres.public.customers.find(customer_id: {"=": customerId){   
   email,
   - Http.get(
       url:"https://zerobounce1.p.rapidapi.com/v2/validate",
       headers : {
        <中略>
```

クエリパラメータを動的に埋め込みたいは下記のように param セクションを追加して指定できるようです。

```javascript
        <中略>
    - Http.get(
        url:"https://zerobounce1.p.rapidapi.com/v2/validate",
        headers : {
            "X-RapidAPI-Host": "zerobounce1.p.rapidapi.com",
            "X-RapidAPI-Key": rapidKey
        },
        params:{
            'ip_address' : 'dummy',
            'email' : email
        }
        <中略>
```

この要領でチェーンしてみた最終形がこちらです。
ZeroBounce からは status, sub_status, free_email, smtp_provider のフィールドのみ取得します。

```javascript:rapidqltest.js
const RapidQL = require('RapidQL');

//RapidQL のインスタンス化と同時にDB 接続情報を指定
const rql = new RapidQL({
    PostgreSQL: {
    	postgres: {
    	    user: 'postgres',
    	    database: 'postgres',
    	    password: 'postgres',
    	    host: 'localhost',
    	    port: '5432'
       	}
    }
});

//WHERE 句に渡す顧客ID
const wkCustId = 2222;

//API のキー
const rakutenRapidAPIKey = '<上で確認した API キー>';

//RapidQL 
rql.query(
    `{
        PostgreSQL.postgres.public.customers.find(customer_id: {"=": customerId}){
            email,
          - Http.get(
                 url:"https://zerobounce1.p.rapidapi.com/v2/validate",
                 headers : {
                   "X-RapidAPI-Host": "zerobounce1.p.rapidapi.com",
                   "X-RapidAPI-Key": rapidKey
                 },
                 params:{
                     'ip_address' : 'dummy',
                     'email' : email
                 }
            ) {
                status, sub_status, free_email, smtp_provider
             }
        }
    }`,
    {
    "rapidKey": rakutenRapidAPIKey,
    "customerId": wkCustId
    }
)
.then((res) => console.log(JSON.stringify(res)))
.catch((err) => console.log(err));
```

###実行結果

```bash
$ node rapidqltest.js
{"PostgreSQL.postgres.public.users.find":[{"email":"muto@moonsault.com","status":"invalid","sub_status":"does_not_accept_mail","free_email":false,"smtp_provider":""}]}
$ 
```

今回は DB からクエリしたのが適当なメールアドレスでしたのでちゃんと invalid と判定してくれています。
ちゃんと生きてるアドレスを入れたら staus=valid と判定してくれました。

##さいごに
今回やってみて思ったこととしては、もともと GraphQL に詳しいわけではないので記法は少しとっつきにくかったです。
ただ、一般的に複数のメソッドを用意して処理する DB と API のクエリをまとめて１文で書けるのは個人的には画期的でした。
また、いずれのクエリもある程度抽象化でき、慣れてきたら可読性も上がるのかという印象でした。

RESTful API 同士のチェーンもこれを使えばできるようなので、次回はそれを試してみたいと思います。