まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2016/02

先日、Bluemix 上で使えるようになった WebSphere Application Server (以下 WAS for Bluemix)についてこちらで紹介しました:

上記記事では OpenVPN を使って WAS for Bluemix のサーバー 仮想マシンと VPN 接続をして、WAS のウェブコンソールにアクセスする、という手順を紹介しました:

 

WAS for Bluemix 環境では、上記のウェブコンソールにアクセスするだけでなく、サーバー仮想マシンに ssh 経由でログインしたり、そこから root になって管理者権限で OS を利用することも可能です。今日はそちらの手順を紹介します。

まずは準備として WAS for Bluemix の仮想マシンに対して OpenVPN を使った VPN 接続までは済ませておいてください。具体的な手順は上記リンク先を参照してください。

次に Bluemix 内に定義した WAS for Bluemix のサービスを開いて、VPN 構成ファイルをダウンロードしたこのページを開き、仮想マシンの左横にある下向きの矢印部分(数の赤枠部分)をクリックします:
2016021201


すると隠れていた部分が展開されて、この仮想マシンに SSH 接続するために必要な情報が表示されます:
2016021202


WAS for Bluemix の仮想マシンに SSH 接続するには RSA の秘密鍵が必要です。「鍵の保存」でダウンロードするか、または「鍵を表示」で確認した内容と同じテキストファイルを SSH を実行するクライアント機上にファイルとして用意します(用意したファイルのパーミッションを 600 などにして、他人がアクセスできないようにしておきます):
2016021203


これで SSH 接続のための準備が整いました。以下のコマンドで SSH 接続します(WAS 仮想マシンへの SSH 接続時のユーザーは virtuser を指定します):
$ ssh virtuser@(WAS for Bluemix の仮想マシンのIPアドレス) -i (保存した鍵ファイルのファイルパス)

自分が確認した限りですが、正しい鍵ファイルが指定されていればパスワードなしでログインできます。ユーザー名は上記で指定した virtuser になっていますが、sudo 権限があるようなので、ログイン後に root に切り替えて操作することも可能です:
2016021204


root でログインできる SSH サーバーが提供された、ともいえます。ディレクトリ構成とかを見る限り、ベースはどうも RedHat Enterprise Linux っぽいようにも見えますが、まあその辺りに興味ある方はいろいろ調べてみてください。


IBM Bluemix だけの環境を使って、Web API を作り、公開して、更に API Management 機能を使って管理/監視する、というシステムを作ってみます。

これまでこのブログでも個別の機能を個別に紹介したりしていましたが、全てまとめたシステムを Bluemix 提供サービスだけを使って(外部サービスに頼らずに)行う、という前提条件で紹介します。もちろん実際には外部との連携も可能です、データベースは既存のものを使う、とかも可能、という意味です。


システム概要としての完成図は下図のような感じを想定します。まず格納するデータのデータベース(MySQL)と、その管理ツールとして phpMyAdmin(PHP ランタイム)を用意します。次にデータベース内のモデルを API として公開する LoopBack(Node.js ランタイム)。ここまでで CRUD の REST API ができますが、このサーバーは直接公開しません。加えてこの API を管理するため、API Management サービスでラッピングし、カスタム API を作って、これを利用者向けに公開します。それぞれ Bluemix 上のサービスアイコンと併せてのシステム図になっています:
2016020701


ではそれぞれのパーツを順に Bluemix 上に作っていきます。全部で3段階あります:

(1) MySQL と phpMyAdmin でデータベース環境を準備
2016020801

Bluemix 環境内に MySQL のデータベースサーバーを用意し、この中に API として管理するデータのモデル(テーブル)を作成します。MySQL の選択肢として ClearDB を使うこともできる(その場合は外部の MySQL コマンドラインクライアントから直接参照できる)のですが、今回はオープンソース版を使うことにします。オープンソース版では外部の MySQL コマンドラインクライアントからは参照できないので、テーブル定義のために PHP ランタイムと、そこで実行する phpMyAdmin の環境を構築します。そして phpMyAdmin から create table の SQL を実行して、モデルを作成します。

この Bluemix 環境内に MySQL データベースサーバーと phpMyAdmin アプリケーション環境を構築する際の手順についてはこちらで詳しく紹介しているので参照ください:
Bluemix で phpMyAdmin を動かす


(2) StrongLoop LoopBack で REST API 化

2016020802

StrongLoop LoopBack インスタンスを作り、先程作成した MySQL データベースをバインドして、モデルを CRUD 可能な REST API 化します。

StrongLoop 環境の構築方法や Bluemix ランタイムへのプッシュ方法、そしてデータベースとして MySQL を指定する場合の手順などは以下を参照ください:


ただし、この REST API はこのまま公開はしません。あくまでプライベートな REST API として作成し、公開する時は参照系 API のみ(GET リクエストの API のみ)を公開するようにします。


(3) API Management で公開する API を絞り、カスタム API 化して管理
2016020701

LoopBack で作成した REST API の参照系 API のみをプロキシー URL とするようなカスタム API を API Management サービスを使って作成し、このカスタム API を Bluemix ユーザー向けに公開します。

API Management サービスでカスタム API を作って公開する手順はこちらを参照ください。(2) で作成した LoopBack の REST API を、ここで公開するカスタム API のプロキシーとして利用するための手順です:
IBM Bluemix の API Management サービス



と、こんな感じ。特別に目新しい情報ではないのですが、Bluemix のランタイムやサービスを組み合わせるだけで負荷に合わせてオートスケールする API を生成し、かつその API の制御管理を行う、という仕組みが構築できました。





 

かなり以前に Bluemix 環境で phpMyAdmin を動かす場合の流れを紹介したことがあります:
BlueMix 上で PHP アプリを動かす


が、ここで紹介している内容は Bluemix がまだベータ版だった 2014 年頃のもので、今となっては内容が古くなってしまいました。改めて 2016/Feb/08 時点での手順を紹介します。

まず、何はともあれ Bluemix 環境内に PHP ランタイムを作成し、MySQL サービスをバインドします。MySQL サービスはオープンソース版ClearDB 版の2つの選択肢がありますが、どちらでも構いません。以下はオープンソース版を使っているものとして説明しています:
2016020803


PHP プロジェクトのメニューから「環境変数」を選択し、バインドされた MySQL サービスに関する接続情報を確認します。この中の credentials 内から hostname, port, name(データベース名), username, password の内容を確認してメモしておきます(後で使います):
2016020804


次に phpMyAdmin のページ上部から最新版の phpMyAdmin をダウンロードします。この記事を書いている 2016/Feb/08 時点での最新バージョンは 4.5.4.1 であり、ダウンロードファイルの名前は phpMyAdmin-4.5.4.1-all-languages.zip でした。以下、この環境を前提として記述しますが、最新バージョンが変更になった場合は適宜読み替えてください:
2016020801


ダウンロードした zip ファイルを展開して、適当なフォルダに格納します。以下の例では C:\tmp\phpmyadmin\ というフォルダの中に phpMyAdmin というサブフォルダ名で展開しています:
2016020802


展開結果のファイルの中から config.sample.inc.php ファイルを config.inc.php にリネームします。更にこのファイルをテキストエディタで開き、$cfg['Servers'][$i]['host'] 変数の値を先程環境変数で確認した hostname:port となるように書き換えて保存します。例えば hostname が 159.8.128.49、port が 3307 であった場合は以下のように指定して保存します:
  :
  :
$cfg['Servers'][$i]['host'] = '159.8.128.49:3307';
  :
  :

更に、phpMyAdmin を展開したフォルダ(この例であれば c:\tmp\phpmyadmin)に composer.json というファイルを以下の内容で作ります:
{}

また、同じフォルダ内に .bp-config という名前のフォルダを作り、更にその下に options.json というファイルを以下の内容で作ります:
{ "PHP_EXTENSIONS": [ "bz2", "zlib", "curl", "mcrypt", "mbstring", "mysql", "mysqli", "pdo", "pdo_mysql" ] }

この時点で phpMyAdmin を展開したフォルダ(c:\tmp\phpmyadmin\)はこのような感じになっています(.bp-config フォルダの下に options.json が保存されてます:
2016020801


これで phpMyAdmin を Bluemix で動かすための準備は整いました。cf ツールを使って、このフォルダ(c:\tmp\phpmyadmin\)以下をまとめて最初に作った PHP ランタイムにプッシュします:
2016020803


プッシュが成功したら、ウェブブラウザで PHP ランタイムの /phpMyAdmin/ フォルダにアクセスします。phpMyAdmin のログインページが表示され、ユーザー名とパスワードには環境変数から取得した username および password の値をそれぞれ入力して「実行」をクリックします:
2016020801


正しく入力されていれば、phpMyAdmin の初期画面になり、指定した MySQL サーバー内のデータベースが指定したユーザーの権限内で操作できるようになります。ここからテーブルを作成したり、クエリーを発行したりすることも可能です:
2016020802


Bluemix で phpMyAdmin を動かす場合の参考にしてください。

 

IBM Bluemix から SaaS で提供されている API Management サービスを使うと、普通に提供されている Web API に対して、その提供範囲を一部だけに限定(例えば GET/POST で提供されている API のうち、POST のものだけを公開)したり、認証機能を追加したり、(利用頻度や回数などの)アクセス制限をかけたり、API 利用状況をモニタリングする機能をラッピングする形で提供できるようになります。この辺りに関してはこちらのブログエントリにまとめているので参照ください:
IBM Bluemix の API Management サービス


この API Management サービスを使って既存の API をラッピングした場合、既存の Web API で指定していたURL パラメータやパスパラメータを、ラッピング後にどのように指定すればよいか?という疑問が生じます。その辺りについて調べてまとめてみました。結論としては「あまり意識せずに使える」ことになります。


例えば、既にこのような Web API が存在していたとします:{item_id} の部分に ID を指定して GET リクエストすることで、指定した ID のレコードを取得できる、というものです:
http://xx.xx.xx.xx/abc/items/{item_id}

実際にウェブブラウザでリクエストした例がこちらです。この例では 1 という {item_id} を指定して目的のレコードを取得していますが、この 1 の部分を適宜変えることで目的のレコードを変更することができるような API になっている、という前提です:
2016020701


このような Web API を API Management でラッピングする場合、この {item_id} というパスパラメータの存在をどのように指定すればよいか? というのが本ブログエントリの目的です。

結論はかなり簡単で、API を定義する際のパスにパラメータを {xxx} 形式で指定します。またその実装においてもプロキシー URL を指定する際に同じパラメータを使って指定します。

具体的には以下のような /get 関数を定義します。公開する API の形式を /get/{item_id} のように指定し、その実装のプロキシーURL において、 http://xx.xx.xx.xx/abc/items/{item_id} のようにそのまま指定するようにします。これで /get/ の後に1つパラメータを受け取って動くような挙動になっていることを指定したことになります:
2016020703



また、URL パラメータはラッピング API を作成する際には特に宣言しなくても、そのまま使えます。例えば以下の URL を GET リクエストすると、レコードの一覧が取得できるような API が存在していて、limit=XX の部分で取得レコード数を指定できるような仕様になっていると仮定します:
http://xx.xx.xx.xx/abc/items?limit=100

この Web API を API Management でラッピングする場合は、URL パラメータのことは意識せずに、そのまま API を定義できます。下の例では公開 API に /list というパスを指定し、その実装のプロキシー URL は http://xx.xx.xx.xx/abc/items (URL パラメータ部分を省略したもの)までをそのまま指定します。これで /list 関数も定義できました:
2016020704


このような指定方法で作成/公開したラッピングの API で、パスパラメータや URL パラメータを指定するには以下のようにします。まずは公開したラッピング API は Bluemix 内では「カスタム API 」として利用可能になっています(API Management で公開後に再ログインする必要があります)。まずはこのカスタム API を自分のランタイムにバインドしておきます:
2016020705


バインドが成功すると、ランタイム内のサービスにカスタム API が追加できているはずです:
2016020706


次にこの API を利用する際に必要な client_id と client_secret を確認します。メニューから「環境変数」を選び、このカスタム API を利用するための credentials 情報を確認します。そして url, client_id, client_secret の3つの値を確認してメモしておきます(この値はランタイムの環境変数 VCAP_SERVICES から参照できるので、アプリケーション内で動的に取得も可能です):
2016020707


では実際に API Management を使って公開された API をパラメータを付けて利用してみましょう。まずレコードの ID をパス内で指定してレコードを取得する API の場合は、その ID をそのまま URL の最後に指定してブラウザでアクセスします。なお API Management 管理下の API にアクセスするには client_id と client_secret の値が必要なので、上記の環境変数から取得したそれぞれの値をそれぞれ指定して、以下のようなアドレスにウェブブラウザでアクセスします(以下は {item_id} に 1 を指定した例です):
(環境変数の url の値)/get/1?client_id=(環境変数 client_id の値)&client_secret=(環境変数 client_secret の値)

すると、上記のラッピング前の Web API で実行した時と同じ結果を確認することができます。{item_id} の値を変更しても、正しい値が得られるはずです。これでパスパラメータについては API Management で管理できることがわかりました:
2016020708


もう1つの、URL パラメータを指定する例も確認してみます。今度も client_id と client_secret と、更に limit の値も含めて URL パラメータに指定して、以下の様なアドレスにアクセスします(以下は limit に 10 を指定した例です):
(環境変数の url の値)/list?client_id=(環境変数 client_id の値)&client_secret=(環境変数 client_secret の値)&limit=2

この場合もラッピング前の Web API で実行した時と同じ結果が確認できるはずです(limit の値を変更すると、指定した数を上限とする結果セットが得られるはずです)。URL パラメータについては特に何もしなくても API Management に引き継いで管理できることが確認できました:
2016020709


結論として、API Management でパラメータを使う場合は、以下の様な指定が必要です:
(1) URL パラメータの場合は、特に指定不要でそのまま
(2) パスパラメータの場合は、指定するパラメータを { } で括ったものを API 定義とプロキシー URL の両方に指定する





StrongLoopLoopBack を使うと、データベースのモデルを定義するだけで CRUD の REST API を生成し、OpenAPI(Swagger) スタイルのドキュメントと併せて簡単に公開できます。この辺りについては以前のブログエントリを参照してください:
CentOS に StrongLoop をインストールする


ところで、LoopBack を使って公開された API にはパラメータで挙動を指定できるものもあります。例えばモデルの一覧を取得する GET リクエストでは一覧を絞り込むためのクエリーを指定したり、取得結果の数やオフセットを指定することも可能です:
2016020601


そのための方法を紹介します。例えば items というテーブルに対して LoopBack で CRUD の API を作成したと仮定します。items の一覧を取得するには以下の様な URL に対する HTTP リクエストを GET で実行することになります(XX.XX.XX.XX は LoopBack が動いているサーバー):
http://XX.XX.XX.XX/api/items/

さて、一覧の検索条件(例えば id < 100)を指定する場合、SQL ではこのように指定することになります:
> select * from items where id < 100;

この条件を指定して上記の HTTP GET リクエストを実行するには、つまり id < 100 のものだけの一覧を API で取得するには、以下の様なパラメータを指定して実行します:
http://XX.XX.XX.XX/api/items?filter[where][id][lt]=100

filter という名前に [where] 句が指定され、更に条件である [id] が [lt] (Less Than) で 100 である、という条件が指定されていることになります。


一方、一覧の検索結果の取得数(例えば10件)を指定する場合、SQL(MySQL) ではこのように指定します:
> select * from items limit 10;

この条件を指定して HTTP GET リクエストを実行するには、以下の様なパラメータを指定して実行します:
http://XX.XX.XX.XX/api/items?filter[limit]=10

filter という名前に [limit] 句が指定され、その値が 10 である、という条件が指定されていることになります。なんとなくコツが分かってきましたか?

ちなみに一覧の検索結果の取得数を 50 件目からの 10 件、とするには SQL(MySQL) ではこのように指定します:
> select * from items limit 50, 10;

limit 句を指定し、オフセットが 0 以外の場合は limit 数の前にオフセット数を指定します。これを API のパラメータで指定するには以下のようにします:
http://XX.XX.XX.XX/api/items?filter[limit]=10&filter[offset]=50

クエリーや結果取得の条件は同時に指定することができます。例えば「 id < 100 のものをオフセット 50 で10 件取得」するのであれば、API ではこのように指定します:
http://XX.XX.XX.XX/api/items?filter[where][id][lt]=100&filter[limit]=10&filter[offset]=50

filter の使い方、なんとなくコツがわかってきましたか? 使っているデータベースの種類は何で、そのデータベースでは SQL ではどういった指定になるか、をイメージできるとわかりやすいです。


このパラメータに関する API ドキュメントはこちら:
https://docs.strongloop.com/display/public/LB/Where+filter
 

このページのトップヘ