Db2のテーブルをOData(REST/JSON)で簡単に操作できる! IBM Data Server Gateway for OData を触ってみた


# はじめに

当記事の元ネタは developerWorksの[IBM Data Server Gateway for OData Version 1.0.0](https://www.ibm.com/developerworks/community/blogs/96960515-2ea1-4391-8170-b0515d08e4da/entry/IBM_Data_Server_Gateway_for_OData_Version_1_0_0?lang=en)です。

先日、HTMLのテーブルを使ったデモ(モック）を作っていたのですが、「なんかスタティックなデータをいちいちHTMLで書くの面倒だなー」と思いました。RDBのテーブルの内容をJSONで簡単にHTMLテーブルにロードできるといいんですが、StrongLoopやAPI Connectでは大げさすぎて本末転倒。CloudantもいいけどいちいちJSONでデータ作るの面倒くさいし。。と思っていてDb2のIBM Data Server Gateway for ODataってのを見つけました。ちょうどお手軽でいい感じです。

# IBM Data Server Gateway for ODataとは?
[OData(Open Data Protocol)](http://www.odata.org/)はRESTful APIを作ったり使ったりする際の標準です。V4では[OASIS標準](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=odata)になりました。IBM Data Server Gateway for OData(以下DSG4Oと記載します)は上記**ODataのDb2向け実装で、Db2に付属**しています。(DataServer ClientのコンポーネントとしてFixCentralからダウンロード可能=追加の費用はかかりませんし、無償版のDb2 Express-Cでも使えると思います）詳細は上記[ネタ記事](https://www.ibm.com/developerworks/community/blogs/96960515-2ea1-4391-8170-b0515d08e4da/entry/IBM_Data_Server_Gateway_for_OData_Version_1_0_0?lang=en)をご参照いただくとして、要は「**Db2のテーブルをREST/JSONで簡単に読み書きできるようにするもの**」とお考えください。特長は下記です。

- [Apache Olingo](https://olingo.apache.org/)ベース=Javaでの実装
- 最新のOData V4.0標準に準拠
- WAS Libertyを埋め込んでおり、ダウンロードして起動＆定義ですぐ使える

絵に書くとこんな感じです

- DB2とOData(REST)クライアントの間を仲介
- WAS Libertyの配下のwarとして稼働
- 事前にDB2テーブルのメタデータからODataの定義を生成しておく

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/b25b6a41-6688-c8aa-9f11-419c53c1368c.png)

:warning: Db2にはMongoDB互換でJSONデータをデータベースに格納/照会できる機能がありますが、あれとは別物です。あくまでリレーショナル・データベースのテーブルをOData標準(REST/JSON)で読み書きできるようにするものです。

# 導入して動かす
細かい内容は[IBM Data Server Gateway for OData Version 1.0.0](https://www.ibm.com/developerworks/community/blogs/96960515-2ea1-4391-8170-b0515d08e4da/entry/IBM_Data_Server_Gateway_for_OData_Version_1_0_0?lang=en)に書いてあるのですが、簡単にサマリーします。ダウンロードして実行するだけ、でありメチャ簡単です。
## インストール

#### ダウンロード
[FixCentral](https://www.ibm.com/support/fixcentral/swg/selectFixes?parent=ibm~Information%2BManagement&product=ibm/Information+Management/IBM+Data+Server+Client+Packages&release=11.1.*&platform=Linux&function=fixId&fixids=*odata*FP001*&includeSupersedes=0&source=fc)からダウンロードできます。ダウンロードが2種類ありますが下の方がWAS Libertyも一緒にバンドルされているので楽でオススメです。(85MB)

- WindowsでもLinuxでも動きます
- 「Warのみ」版は自分でお好みのアプリサーバーに入れたい人用です

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/153fab4a-2d6d-9f68-77cb-8a5936244a9c.png)
## 構成
#### UNZIPとちょっとした準備
Linux環境では解凍後に以下の権限設定をしておいてください。( Windowsでは何もしなくても動きました。）

```bash:Linuxではchmod必須
unzip v1.0.0_ibm_gateway_server_for_odata/
cd v1.0.0_ibm_gateway_server_for_odata
chmod 555 start_ibm_gateway_server_odata
chmod 555 stop_ibm_gateway_server_odata
chmod 555 server/bin/server
```
DSG4Oに埋め込まれたWAS Libertyはデフォルトではlocalhost(127.0.0.1)のみをListenします。ブラウザー環境がLocalでない場合はserver.xml(./server/usr/servers/ibmgatewayserverodata/server.xml)を開いて以下のいずれかで外部からの要求を受け付けるようにしておきます。
①　httpEndPointタグに　host="*"を追加する
②　variable　defaultHostNameを明示的に設定する

```xml:httpEndPointタグに　host="*"を追加する
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>webProfile-7.0</feature>
                <feature>servlet-3.1.0</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint"
                  host="*"
                  httpPort="9080"
                  httpsPort="9443" />

    <webApplication contextRoot="ODataOne" location="ibmgatewayserverodata" />
         <httpSession cookieName="JSESSIONID" idLength="28"/>

</server>
```
```xml:variable　defaultHostNameを明示的に設定する
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>webProfile-7.0</feature>
                <feature>servlet-3.1.0</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint"
                  httpPort="9080"
                  httpsPort="9443" />
    <variable name="defaultHostName" value="192.168.118.132" />
    <webApplication contextRoot="ODataOne" location="ibmgatewayserverodata" />
         <httpSession cookieName="JSESSIONID" idLength="28"/>

</server>
```
#### Db2とDSG4Oの開始
1. 普通にDb2を開始
2. 展開先の直下にあるstart_ibm_gateway_server_odata(.bat)を実行
- WAS Libertyが起動してポート9080でListenします

```bash
[root@wex1102 v1.0.0_ibm_gateway_server_for_odata]# ls -al
total 24
drwxr-xr-x   4 root root  212 Dec  9  2016 .
dr-xr-x---. 22 root root 4096 Oct 29 13:15 ..
dr-xr-xr-x   2 root root  258 Dec  8  2016 licenses
-r-xr-xr-x   1 root root  849 Dec  9  2016 Readme.txt
dr-xr-xr-x   9 root root  155 Aug 31  2016 server
-r-xr-xr-x   1 root root   45 Dec  9  2016 start_ibm_gateway_server_odata
-r-xr-xr-x   1 root root   45 Dec  9  2016 start_ibm_gateway_server_odata.bat
-r-xr-xr-x   1 root root   44 Dec  9  2016 stop_ibm_gateway_server_odata
-r-xr-xr-x   1 root root   44 Dec  9  2016 stop_ibm_gateway_server_odata.bat
[root@wex1102 v1.0.0_ibm_gateway_server_for_odata]#
[root@wex1102 v1.0.0_ibm_gateway_server_for_odata]# ./start_ibm_gateway_server_odata
Starting server ibmgatewayserverodata.
Server ibmgatewayserverodata started with process ID 5554.
[root@wex1102 v1.0.0_ibm_gateway_server_for_odata]# netstat -ano|grep 9080
tcp6       0      0 192.168.118.132:9080    :::*                    LISTEN      off (0.00/0/0)
[root@wex1102 v1.0.0_ibm_gateway_server_for_odata]#

```

#### 構成
1. ブラウザーで http://ホスト名:9080/ODataOne を開き、「Create OData Service」ボタン
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/6d2d38ab-d09c-d805-fc11-3b0936440b7a.png)

2. データベース名、ポート、ユーザーなど接続に必要な情報を入力して「Submit」ボタン
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/a8ee7a6a-e26a-758c-ab9e-923188649caf.png)

※ここでDBADM権限を持つIDが必要な点にご注意ください。IBM Cloud上のDb2 Warehouse(旧名dashDB)の無料版は共用環境のためスキーマでユーザーを分離しており、DBADM権限を持つIDは非公開です。ゆえにDSG4Oは残念ながら利用できません。

3.　スキーマを選択して「Submit」ボタン

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/6079c2a0-b1e4-6472-55d7-8ea9e9280437.png)

4.　メタ情報を生成したいテーブルを選びます。今回はSAMPLEデータべースを使っているので　ORG(組織)とSTAFF(社員)を選びました

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/24d4739d-16a0-8eff-6be1-12f36d32752f.png)

5.　サービスのURLが生成されました。メタデータをみることもできます。

- テーブル STAFFがエンティティ名ではSTAFF**S**と複数形になっているのにご注目ください。実際に照会などで使うときはこの(複数系の)エンティティ名の方を使います。

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/0e823766-521d-0b49-f493-c7aa5f15ef74.png)

これで導入から環境設定は終了です。メチャ簡単でしたね？

:warning: この状態でもSSLやDBのセキュリティ機構は利用できますが、WAS Liberty自体にはセキュリティがかかっていません。PC上でのデモ程度ならこれでいいでしょうが、真面目に使う場合は[LibertyのOpenID Connectのマニュアル](https://www.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.wlp.nd.doc/ae/cwlp_openid_connect.html)など見てLibertyのセキュリティ設定をしておきましょう。

# ODataでアクセスしてみる
すでにこの状態でOData V4標準に則ってDb2にREST要求を出せます。（照会も更新もできます）

- 要求を出すクライアントはcurlでもPostmanでもアプリでも、なんでもいいです
- (当然ながら)CORS制約が適用されますので、異なるドメインからロードされたブラウザー上のJSからは呼び出せません。(HTML等をWAS Libertyに置けばOK)
- 以下のCRUD操作が可能です。

| SQL操作| HTTP命令|
|:---|:---|
|SELECT| GET |
|INSERT| POST |
|UPDATE| PUT/MERGE |
|DELETE| DELETE |

以下、生成されたサービスのURLは **BaseURL**と表記します

## 照会(GET)
STAFF表から3件照会してJSON形式でデータを入手
```http
GET　<<BaseURL>>/STAFFS?$top=3&$format=json
```
Postmanで実行した例
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/1a77f9bf-cf7e-5d24-6688-10fec83edb9d.png)

## 挿入(POST)
STAFF表へJSON形式で1件挿入
```http
POST　<<BaseURL>>/STAFFS
```

- HTTPのリクエスト・ヘダーに以下を設定し、BODYでJSONデータを渡します
    Content-Type:application/json; charset=UTF-8
    Accept:application/json
- データはBodyで{JSON}を渡します

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/14a194d7-93b4-3a6d-7bbe-3a5930c9880a.png)

STAFF表に行がINSERTできました
![image](https://qiita-image-store.s3.amazonaws.com/0/108535/e5e554b0-2b24-65e2-5583-4f9895964e6b.png)

# 軽いデモ用にブラウザー上のjsからアクセスしてみる

(本番用にはお勧めしませんが)デモ用途であれば、以下のようにHTMLなどのWebリソースをWAS Liberty配下に置くとjsから直接OData要求を出せます。(=CORS制約回避のためのNode.jsなどのプロキシ―が不要) 

## 環境設定
① 同梱で展開したWAS Libertyのdropins配下にhoge.war(hoge部分は任意）というディレクトリーを作り、HTML/JSなど静的なコンテンツ一式を置く（＝dropins/hoge.warの直下がドキュメント・ルートになります）
② ブラウザーでhttp://yourhost:9080/hoge/index.htmlへアクセス
　( hoge.warのhogeの部分がurlのPATHになります）
③ ブラウザー上のjsでOData要求を出す

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/4f07a315-a779-07a0-b41b-705b88912503.png)

※[How do I display an HTML file using Websphere Liberty?](https://stackoverflow.com/questions/27305207/how-do-i-display-an-html-file-using-websphere-liberty)にありますが、要はWAS Libertyをスタティック・コンテンツをホストするサーバーとして使うわけです。同一ドメインからの要求ですから、CORS制約に抵触しません。

## やってみた

照会だけですが、こんな感じで簡単なツールを作りました。HTMLを1つ、JSを1つの簡単なものですが、githubの[ここ](https://github.com/ishida330/DGW4O)に置いておきますので、よければお試しください。(htmlとjsを前述のようにWAS Liberty配下に置いてください）

![image](https://qiita-image-store.s3.amazonaws.com/0/108535/9b10f077-d672-3562-6922-6a45431d5b9e.png)

## その他
1. OData 4.0でのQueryのオプションは下記のようなものですが、DGW4Oでは一部は未対応のようです。

| Query Options| 例|コメント|
|:---|:---|:---|
|$top|  $top=3 |  |
|$count| $count=true |  |
|$skip| $skip=10 | DGW4Oでは未実装の模様 |
|$select| $select=ID,NAME,JOB |  |
|$category| - | DGW4Oでは未実装の模様  |
|$ordeby| $orderby=SALARY desc, COMM desc |  |
|$filter| $filter=ID eq 30 or contains(JOB,'Sales') |  |

2.Apache Olingoのサイトではクライアント用に[Olingo OData Client for JavaScript](http://olingo.staging.apache.org/doc/javascript/index.html)なるライブラリーも提供されていたので使ってみたんですが、ODataサービスの呼び出しが以下のような感じで、jqueryのajaxで呼び出すのと比べて、あえてこれを使う利点がイマイチわかりませんでした。（文書も不足。一応、動きましたけど。。。）

```js:ODataでの呼び出し部分のみ抜粋
    var serviceRoot = "http://192.168.118.132:9080/ODataOne/ODataService/SAMPLE-1cd7e4e922b14e1dab6820a8167ca4cc/";
    var headers = { "Content-Type": "application/json;", Accept: "application/json;" };

    // odatajsでrequestする
    function queryStaffOdatajs() {
        var qs = $.Deferred();
        var request = {
            requestUri: serviceRoot + "STAFFS?$top=5&$format=json",
            method: "GET",
            headers: headers,
            data: null
        };

        odatajs.oData.request(
            request,
            function(data, response) {
                qs.resolve(data);
            },
            function(err) {
                qs.reject(err);
            }
        );
        return qs.promise();
    }

```

# 参考文献（OData仕様など）

[OData Version 4.0 Part 2: URL Conventions](http://docs.oasis-open.org/odata/odata/v4.0/csprd02/part2-url-conventions/odata-v4.0-csprd02-part2-url-conventions.html)
[Documentation OData 4.0 Java Library](http://olingo.staging.apache.org/doc/odata4/index.html)のTutorial

以上です。