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

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

タグ:api

こちらの続きです:
Cloudant の便利な API (1) : バルクインサート


NoSQL な DBaaS である IBM Cloudant の便利で特徴的な API を紹介しています。前回は1回の POST API 呼び出しでまとめて複数のドキュメントデータを登録するバルクインサート機能を紹介しました。この登録したドキュメントデータを使って、今回からは Cloudant のユニークな API を紹介すると共に、このドキュメントデータを使った参照アプリケーションを作っていきます。

今回紹介する便利な API は View Design Document API です。Cloudant には Design Document と呼ばれる特殊なドキュメントを格納することができます。一般的なドキュメントはいわば「データとしてのドキュメント」であるのに対し、Design Document は「設計情報としてのドキュメント」です。特に今回紹介する View Design Document は複数のドキュメントの集合である「ビュー」の定義情報を保持するドキュメントです。具体的にはどのような条件を満たすドキュメントがビューに含まれるのか、その条件を満たすドキュメントのどの要素をビューに格納するのか、、といった情報を保持する、(ドキュメントデータとは異なる)特殊なドキュメントです。

なお、Cloudant の Design Document に関する API のリファレンスはこちらを参照ください:
https://docs.cloudant.com/design_documents.html


では前回作った47都道府県ドキュメントデータに View Design Document を使ってビューを作ってみます。今回はこの47ドキュメントから、いわゆる「海無し県(=栃木県、群馬県、埼玉県、山梨県、長野県、岐阜県、滋賀県、奈良県)」だけを抜き出して集めた nosea ビューを定義してみます。

まず海無し県は上述の8県です。海無し県に含まれる条件は各ドキュメントデータ(doc)の code (都道府県コード)の値が「9か、10か、11か、19か、20か、21か、25か、29のいずれかであれば海無し県」ということになります。これを JavaScript で表現すると、以下のようになります:
if( doc.code && [9,10,11,19,20,21,25,29].indexOf( doc.code ) > -1 ){
    //. doc.code が存在していて、かつその値が [9,10,11,19,20,21,25,29] のいずれかであった場合、
        :
}

この条件を満たしたドキュメントデータの各値を nosea ビューに含める、という処理の場合に指定するデータは以下のような内容になります:
{
  "language": "javascript",
  "views": {
    "nosea": {
      "map": "function( doc ){ if( doc.code && [9,10,11,19,20,21,25,29].indexOf( doc.code ) > -1 ){ emit( doc._id, {code:doc.code,prefecture:doc.prefecture,capital:doc.capital} ); } }"
    }
  }
}

JSON 内の views.nosea(ビュー名).map に、このビューへのマッピングの関数を記述します。function のパラメータである doc がデータベース内の各ドキュメントを示しており、全ドキュメントがこの関数によってマッピングされ、条件を満たしたものだけがビューに含まれるよう定義されています。

関数内で使われている emit() 関数は第一パラメータがキー、第二パラメータがデータの値となります。第二パラメータに全データを含める必要はなく、今回は code, prefecture, capital という3つのデータだけを取り出して表示するようにアプリ化するので、これらの値だけを含めるようにしました。なお、上記の定義ファイル nosea_view.json はこちらからダウンロード可能です:
https://raw.githubusercontent.com/dotnsf/samples/master/nosea_view.json


ではこの(ダウンロードした)nosea_view.json と View Design Document API を使って、実際に海無し県ビューを作ってみましょう。前回同様に、nosea_view.json を保存したディレクトリで以下のコマンドを実行します(青字は実行結果、成功した時の例です):
$ curl -u "username:password" -XPUT "https://username.cloudant.com/mydb/_design/nosea" -H "Content-Type: application/json" -d @nosea_view.json

{"ok":true, "id":"_design/nosea", "rev":"XXXX..XXXX"}

前回作成した mydb データベースの中に nosea という名前のビューを、nosea_view.json で定義された内容で作成する、という API を実行しています。username および password は Cloudant に接続するためのユーザー名およびパスワードです。詳しくは前回の記事を参照してください。

このコマンドを実行後、改めてダッシュボードの画面をリロードすると、まずドキュメントデータそのものが1つ増えて 47 データから 48 データになっていることが分かります。つまりこのコマンドでデータベース内のドキュメントが1つ追加されたことが分かります(追加されたドキュメントの id は:"_design/nosea" です):
2017100504
2017100504


また mydb データベースに nosea という Design Document が追加されていることがわかります:
2017100501


nosea を更に展開し、Views の中にある nosea を選択すると、この nosea ビューで選別されたドキュメントデータが一覧できます。想定通りの8つの海無し県が並んでいれば成功です:
2017100502


value の部分が途中で切れてみれなくなっている場合は、その部分にマウスカーソルを置いてみると value の結果がオーバーレイして表示されます。JSON ファイルで指定した通りに3つの値が取得できていることが確認できます:
2017100503


なお、ビューの一覧結果は API からも参照できます:
$ curl -u "username:password" -XGET "https://username.cloudant.com/mydb/_design/nosea/_view/nosea"

{"total_rows":8, "offset":0, "rows":[
 { "id": "aaaa..aaaa", "key": "aaaa..aaaa", "value": { "code":9, "prefecture":"栃木県", "capital": "宇都宮市" } },
 { "id": "bbbb..bbbb", "key": "bbbb..bbbb", "value": { "code":10, "prefecture":"群馬県", "capital": "前橋市" } },
    :
 { "id": "cccc..cccc", "key": "cccc..cccc", "value": { "code":29, "prefecture":"奈良県", "capital": "奈良市" } }
]}


今回は Cloudant の View Design Document を使うことで特定条件を満たすドキュメントデータだけを選別してビューにする例を紹介しました。このようなドキュメント集合体の定義が1つのドキュメントデータとしてデータベース内に格納される、という所が Cloudant のユニークな点であると同時に、その集合体が「ビュー」と呼ばれている点などがなんとなくノーツっぽい※ところもあって、個人的には親和性を感じます。

※ちなみに Cloudant のベースとなっている CouchDB を開発した Damien Katz さんは元 Lotus のエンジニアです。
https://www.linkedin.com/in/damienkatz/


なお、次回は今回紹介した View Design Document を使って定義したビューを「どのような UI で見せるか」という情報を定義するための List Design Document を紹介する予定です。

NoSQL な DBaaS である IBM Cloudant を使うようになり、単に「管理/環境構築の手間がない」とか「クラスタリングされてる」という以上に便利な機能がいくつもあることが分かってきました。そのいくつかを実際のサンプルを使って動かす形で紹介しようと思います。今回はいわゆる「バルクインサート」の API で、複数のドキュメントを1回の API でまとめて作成する方法です。


以下の内容を読み進めるにあたり、「実際に自分でも試してみたい」という人は是非 IBM Cloudant のアカウントを取得して、サービスインスタンスを作って動かしてみてください。まだ環境をお持ちでない場合、IBM Bluemix のアカウントを登録して、"Cloudant NoSQL DB" を選択してサービスを作成してください。加えて API の実行には curl コマンドを使うので、curl の実行環境を用意してください(Windows であればこちら、他はおそらく標準のはず):
2017100401


サービス作成の際に利用プランを選択します。1GB かつ 30 日利用がないと削除されるという条件であれば無料の Lite プランを選択することも可能です。利用用途や目的に合わせて選択してください:
2017100402


IBM Cloudant のサービスインスタンスを作成したら(或いは既にお持ちであれば)、作成済みのサービスインスタンスの「サービス接続情報」から「資格情報の表示」を選択して、IBM Cloudant に接続するための情報を確認します。具体的にはここで表示される username と password の値を後で利用することになるので、メモしておいてください:
2017100403


また(今回はあまり使いませんが)IBM Cloudant はウェブのダッシュボード機能があり、データを確認したり、一部の操作をこのダッシュボードから行ったりすることができます。ダッシュボードにアクセスするにはサービスインスタンスの「管理」から「LAUNCH」ボタンをクリックすることで移行できます(或いは上記の「資格情報の表示」の中に表示されている "url" の値をウェブブラウザで指定して開きます。この場合はユーザー名とパスワードを聞かれるので、上記でメモした username と password を指定して開きます):
2017100404


IBM Cloudant のダッシュボード画面です。左ペインの上から2つ目がデータベース一覧タブになっており、ここから現在作成済みのデータベースを一覧できます(下図ではまだ1つもありません)。この後の作業用に1つデータベースを作っておきます。画面右上の「Create Database」をクリックします:
2017100405


適当な名前(以下例では "mydb")を入力して「Create」ボタンをクリックします:
2017100406


指定した名前(mydb)のデータベースができました。この時点ではまだ1つもドキュメント(データ)が入っていないので空の状態です。再度画面左のデータベースアイコンをクリックして、データベース一覧に戻ります:
2017100407


先程の画面に戻りました。mydb というデータベースが追加されて、現在のサイズやデータ数(# of Docs)などが確認できる状態になっています:
2017100408


ではこのデータベースに対して、バルクインサート API を実行してみます。まずはインサートするドキュメントデータのサンプル(prefs.json)をここからダウンロードします:
https://raw.githubusercontent.com/dotnsf/samples/master/prefs.json


prefs.json の内容は以下のようになっています。"docs" 内に日本の47都道府県のコード(code)と名前(prefecture)、都道府県庁所在地名(capital)、そしてその緯度(lat)経度(lng)が JSON オブジェクトで定義されており、その配列を docs としています:
{
  "docs": [
    { "code": 1, "prefecture": "北海道", "capital": "札幌市", "lat": 43.06417, "lng": 141.34694 },
    { "code": 2, "prefecture": "青森県", "capital": "青森市", "lat": 40.82444, "lng": 140.74 },
    { "code": 3, "prefecture": "岩手県", "capital": "盛岡市", "lat": 39.70361, "lng": 141.1525 },
       :
    { "code": 46, "prefecture": "鹿児島県", "capital": "鹿児島市", "lat": 31.56028, "lng": 130.55806 },
    { "code": 47, "prefecture": "沖縄県", "capital": "那覇市", "lat": 26.2125, "lng": 127.68111 }
  ]
}

これが Cloudant のバルクインサート API で使う場合のデータフォーマットになります。挿入したい複数のドキュメントデータを { "docs": [ .. ] } という形式で、"docs" の配列として定義します。

ではこのドキュメントデータ(prefs.json)を上記で作成した mydb データベースにまとめて格納します。curl を使って以下のように実行します:
$ curl -u "username:password" -XPOST "https://username.cloudant.com/mydb/_bulk_docs" -H "Content-Type: application/json" -d @prefs.json

※↑青字usernamepassword の部分には IBM Cloudant の資格情報で確認した値をそのまま指定します。またデータファイル prefs.json はコマンド実行時のカレントディレクトリに存在しているものとします。


コマンド実行後にダッシュボード画面を(リロードして)確認すると、mydb データベースに 47 件の(47都道府県の)ドキュメントデータが格納されていることが分かります。詳しく見るために mydb を選択します:
2017100401


先程は空だった mydb に 47 件のドキュメントデータが格納されていることが確認できます。個々のドキュメントデータの中身はこの(デフォルトの "Metadata" の)画面だとわかりにくいので、表示形式を "Table" か "JSON" に切り替えてみます(ここでは JSON を選択します):
2017100402


ドキュメントデータが JSON フォーマットで、実際に格納した中身(doc)まで含めて表示されます。画面では北海道の1ドキュメントデータしか表示されていませんが、下にスクロールすると他のドキュメントデータも確認することができます:
2017100403


なお、データベースのドキュメントデータ一覧は curl で以下のコマンドを実行した結果でも確認することができます:
$ curl -u "username:password" -XGET "https://username.cloudant.com/mydb/_all_docs?include_docs=true"

include_docs=true のパラメータを付けて実行すると doc の中身まで、付けずに実行すると id と key の一覧のみ取得します。


今回は1回の API 実行で複数のドキュメントデータをまとめて Cloudant に格納するバルクインサート API を紹介しました。バルクインサート自体は必ずしも Cloudant の特徴というわけではなく、他のデータベースシステムにも存在している機能だと思いますが、今後 Cloudant の特徴でもある Design Document API を紹介していくつもりで、その時には今回作成した都道府県データを使ったサンプルを紹介する予定です。


なお、IBM Cloudant の REST API リフェレンスはこちらを参照ください:
https://console.bluemix.net/docs/services/Cloudant/api/http.html
 

IBM Watson から提供されている Visual Recognition(画像認識) API の1つで、ずっとベータ版として提供されていた Similarity Search (類似画像検索)API が正式公開となる前にサービス終了となりました:
Visual Recognition API – Similarity Search Update


非常に簡単に使うことができて、機能も便利で、ベータ版と知りつつ自分もいくつかのプロダクトの中で使ったり、そのサービスをブログやイベント等で紹介したりもしていました。詳しい経緯はわかりませんが、サービスが終了になったことは非常に残念でした。

実は以前にも同じようなことがありました。いわゆる「トレードオフ分析」を行う機能を API として提供していた Watson Tradeoff Analytics API は 2017/05/11 を以ってサービスの追加ができなくなりました(作成済みのサービスは 2018/04 まで使えます)。この API はちょうど自分がこの分析手法を勉強し始めた頃にサービス終了がアナウンスされ、とても残念でした。

この API に関してはちょうどトレードオフ分析を勉強しはじめた当初だったこともあり、自分でもトレードオフアルゴリズムを理解し始めた頃でもありました。で、こんな互換 API を作って公開したのでした:
Yet Another Watson Tradeoff Analytics API


さて話を元に戻して今回の Similarity Search API のサービス終了です。これも非常に残念なことでした。トレードオフ分析の時と異なるのは自分が画像検索アルゴリズムについて勉強していたわけではなく、互換 API を作るにはちとハードルが高かったということでした。

が、調べてみると画像検索にはいくつかの考え方やアルゴリズム、それらごとの向き/不向きがあって、比較的簡単に実現する方法もないわけではない、ということがわかりました。その1つがカラーヒストグラムを使った方法でした:
類似画像検索とカラーヒストグラム


オリジナルの Similarity Search API がこのアルゴリズムを使っていたかどうかは分からない(おそらく使っていない)のですが、とりあえずこのアルゴリズムによって「画像を学習する」&「学習した画像の中から類似した画像を見つける」という最低限必要な機能は実装できそうだ、と思えるようになりました。というわけで今回も互換 API の開発に挑戦してみたのでした。そしてとりあえず出来上がったものをオープンソース化したのがこちらです:
YASS(Yet Another Similarity Search)

2017092400



実装の対象としたのは Watson API Explorer の Visual Recognition API のページを参考に "Collections" カテゴリと "collection images" カテゴリにある全 12 API 、そしてオリジナルにはなかった「学習画像のバイナリを取得する API 」を合わせた 13 API です。オリジナル API のパラメータについては元のものとほぼ互換性を付けたつもりです。また新しい API のパラメータは URL 部分以外にないので特に説明は不要と思っています。なお「ほぼ互換性」という表現を使いましたが、互換性のない箇所は以下のとおりです:
  • オリジナル API の実行時に指定が必要だった API Key を廃止しました。実行時に API Key の指定は不要です。代わりに(必要であれば)Basic 認証をかけることができるようにしました。
  • オリジナル API の実行時に指定が必要だった version パラメータを廃止しました。実行時に version の指定は不要です。正確には version = '2016-05-20' の仕様に従ったものを実装しています。
  • オリジナル API の制限事項であった「1コレクションに対して 1,000,000 画像まで」という制約はありません。ただし画像バイナリごと Cloudant に格納されるため、Cloudant の容量にはお気をつけください。
  • 学習させた画像のバイナリ(画像そのもの)を取得するための API : GET /v3/collections/{collection_id}/images/{image_id}/binary を新たに追加しました。collection_id と image_id を指定して実行すると Content-Type と合わせて画像バイナリが API サーバーから返されます。
  • API 実行後の HTTP レスポンスには status という属性を含めるようにしました(このため、実行結果のフォーマットには互換性がありません)。status = true の場合は成功、false の場合はなんらかのエラーが発生したことを意味しています。

【前提環境】
この互換 API は Node.js で記述されています。従って API サーバーには Node.js のランタイム(と npm)がインストールされている必要があります。また画像や検索に必要な情報は Cloudant データベースに格納されます。2017/Sep/24 現在の仕様では IBM Bluemix 上の Cloudant を使う前提で記述されているため、IBM Bluemix のアカウントを取得して、Cloudant サービスを1つインスタンス化し、その username と password を用意してください。


【インストール方法】
(1) 上記サイトから git clone するか、zip download &展開して、ソースコードを取得します。
(2) ソースコードの settings.js を編集します(青字はコメント。最低限編集が必要になるのは上2つ):
exports.cloudant_username = '(Cloudant Username)';  // Cloudant の username(必須)
exports.cloudant_password = '(Cloudant Password)';  // Cloudant の password(必須)
exports.cloudant_db_prefix = 'yass_';               // Cloudant に作成するデータベース名の prefix(必須だが変更しなくてもよい)
exports.basic_username = 'username';                // Basic 認証をかける場合の username(''にした場合は Basic 認証なし)
exports.basic_password = 'password';                // Basic 認証をかける場合の password(''にした場合は Basic 認証なし)
exports.api_base_path = '/v3';                      // API の基本パス(''でもよいし、変更してもしなくても良い)
(3) npm install を実行
例) $ npm install

(4) Node.js で app.js を実行
例) $ node app.js

(5) curl やアプリケーションから API を利用
例) $ curl -XGET 'http://localhost:6001/v3/collections'


【システム構成】
Similarity Search API の "Collection" に相当する部分を「Cloudant のデータベース」に、画像データに相当する部分を「Cloudant のドキュメント」にみなして格納するようにしました。ドキュメントには attachment として画像ファイルそのものを格納すると同時に、類似検索ができるよう正規化されたカラーヒストグラム情報や、画像データの metadata を合わせて格納するようにしています:
2017092401


類似検索 API(POST /v3/collections/{collection_id}/find_similar)を実行した時の挙動はまず Collection から全画像を取り出し(つまり Collection に該当する Cloudant データベースから全ドキュメントを取り出し)、カラーヒストグラム情報を1つずつ取り出しては色の類似性を調べて、その上位何件かを返すというアルゴリズムにしています。必ずしも効率のよい検索方法ではないと理解していますが、カラーヒストグラムの比較を効率よく行う方法が思いついていないので、現状はこの方法にしています:
2017092402



【所感】
カラーヒストグラムアルゴリズムを採用したこの互換 API の検索精度はオリジナルのものとは同じではない可能性が高いと思っています(色が重要、どちらかというとイラストよりも写真の類似性に向いている、など)。あまり期待通りでなかったとしてもオープンソース化されているので該当部分のアルゴリズムを変更する、という方法もあると思っています(ちなみに MIT ライセンスで公開してます)。

あと、IBM Watson の互換 API を作ったのは今回が2回目ですが、このように「はじめから仕様が決まっている(仕様が変わらないことも決まっている) API を作る」のは楽です。ある程度、仕様として完成されているが故の安心感もありますし、何度も使っていた API なので動作確認も楽でした。実際、今回の互換 API は休暇を利用して(学習部分も含めて)ほぼ3日で作り上げました(「3日で作れる程度のアルゴリズム実装」と言えなくもないと思います)。


 

実を言うと前回このブログエントリを書いたのは、今日のエントリへの前フリでした:もともと以下で紹介する Swagger Editor を使う様子を紹介したかったのですが、そのためには扱う題材となる API が必要でした。というわけで簡単な仕様で、かつ試験的にクロスオリジン問題を解決することのできる(←ここ大事!)REST API を Node-RED で作ってみる、というのが上記の内容でした。同様に自分で管理可能な API があればそれを使って読み替えていただいてもいいのですが、そうでない場合まずは上記エントリを参照して、この後の紹介で管理する REST API を作っておいてください。


さて本題は「REST API のドキュメントをどのように用意するか」です。REST API の仕様書として最低限必要な情報は HTTP メソッドと URL のパス、実行時に与えるパラメータ、結果、そしてその API が何をするものかをざっと紹介したものでしょうか?気が利いているものだと各パラメータ毎の必須/オプションの情報、エラー時の情報などがあったりしてより便利になります。上記の Node-RED で作った API の場合だと対象の API は1つでこんな感じでしょうか:
メソッドパスパラメータの指定方法パラメータとその意味実行例結果の Content-Type結果
GET/getDateURLパラメータtimestamp : タイムスタンプ値(オプション、未指定時は現在時刻)curl -XGET 'http://xxx.com/getDate?timestamp=1000'text/plain指定した日付時刻の文字列


このドキュメントでもある程度は理解できると思いますが、もう少し便利に、というか、Swagger という標準フォーマットを使ってドキュメントを作ってみます。その際に便利なのが Swagger Editor です。Swagger Editor はここにアクセスしてオンライン版をそのまま使うこともできますし、Docker イメージやソフトウェアをダウンロードして専用環境下で利用することもできます。今回はオンライン版を使って紹介します。

Swagger Editor を開いて、API ドキュメントを yaml と呼ばれるテキストフォーマットで書いていきます。今回の例だとこんな感じでしょうか:
swagger: "2.0"
info:
  description: "俺の API"
  version: "0.0.1"
  title: "俺の API"
host: "**********.mybluemix.net"
basePath: "/"
tags:
- name: "myapi"
  description: "俺のAPI"
schemes:
- "http"
- "https"
paths:
  /getDate:
    get:
      tags:
      - "myapi"
      summary: "時刻を文字列で取得する"
      description: "現在時刻または指定したタイムスタンプ値の日付文字列を返す"
      produces:
      - "text/plain"
      parameters:
      - in: "query"
        name: "timestamp"
type: "number"
format: "integer" description: "タイムスタンプ値" responses: 200: description: "成功"

この内容を Swagger Editor の画面左に入力します。するとこの Swagger で定義した Open API ドキュメントが画面右に表示されます:
2017091001


今回定義したのは GET /getDate という1つの API です。ここをクリックすると展開され、パラメータなどより詳しい情報が表示されます。API ドキュメントとしても便利ですが、この Swagger によるドキュメント最大の特徴は「実行できる」ことです。このページから AJAX によるリクエストを発行して API を実行します。一般的には AJAX でリモートサイトにアクセスするにはクロスドメイン問題を考慮する必要がありますが、今回用意した API は(そのための目的もあって)クロスドメインからも実行できるような HTTP レスポンスヘッダを設定しています。というわけで実行してみましょう。"Try it out" と書かれたボタンをクリックします:
2017090902


するとパラメータ部分が入力可能な状態になります。今回は timestamp という必須ではないパラメータを指定できるようにしていることがわかります。とりあえずはここには何も設定せずにそのまま実行してみます:
2017090903


実行するには "Execute" と書かれたボタンをクリックします。すると実行した時の curl コマンドなどと一緒に実行結果も表示されます。この API はパラメータなしで実行すると現在時刻のテキストを返すようになっており、実際に実行したタイミングの日付時刻が表示されます:
2017090904


次にパラメータを指定した上で実行してみます。timestamp に 1000 と入力してみました。これはタイムスタンプの値が 1000 になる日時(1970年1月1日午前零時から1000ミリ秒後)を指定したことになります:
2017090905


この状態で "Execute" ボタンをクリックすると、実行結果は 1970/01/01 00:00:01 になるはずです。API が正しく動いていることがドキュメントの中から実行して確認することができました(クロスドメイン問題を抱えたままだとここでの実行は失敗します):
2017090906


と、これが Swagger で作った API ドキュメントの魅力です。 最後にここで定義した Swagger ドキュメントをエクスポートして(Swagger Editor 上ではない)別のサーバー上でも動くようにしてみます。今回は Node.js 上で実行できるような形式でエクスポートしてみましょう(サーバーサイド JavaScript である Node.js 上で実行する場合はクロスドメインは意識する必要がありません)。画面メニューの "Generate Server" から "nodejs-server" を選択します。すると自動的にダウンロードが始まり、nodejs-server-server-generate.zip というファイルがダウンロードされます:
2017090907


この zip ファイルを Node.js がインストールされたシステム上に展開し、"npm install" 後に "npm run start" すると起動します:
$ cd nodejs-server-server
$ npm install
$ npm run start

> api@0.0.1 prestart /home/pi/src/nodejs-server-server
> npm install

up to date in 5.819s

> api@0.0.1 start /home/pi/src/nodejs-server-server
> node index.js

Your server is listening on port 8080 (http://localhost:8080)
Swagger-ui is available on http://localhost:8080/docs

起動したドキュメントページ(上記例だと http://localhost:8080/docs)にアクセスすると Swagger Editor の右ペインでプレビューとして見ていた部分が表示されます:
2017091002


実際にパラメータを指定するなどして実行することも可能です:
2017091003


以上、自分で作った API に対する実際に動かせる Swagger ドキュメントを作り、そのドキュメントを自分のサーバー上で動かす、という一連の手順を紹介しました。開発者としては API の仕様書を読み解くだけでなく、実際に動かして返ってくる値やそのフォーマットを確認しながら利用できるので、自分が API を使って作ったアプリがうまく動かなかった時の問題切り分けにも使えるツールになるので非常に便利です。

以前のブログエントリの中で Hyperledger Composer を使うことでブロックチェーンのビジネスネットワークを比較的簡単な定義で動かすことができることを紹介しました:
Hyperledger Composer フレームワークを使ってみる

↑ここで紹介したように Hyperledger Fabric v1.0 と Hyperledger Composer を使うことで、"asset" と呼ばれる取扱データ、"participant" と呼ばれるユーザー、 "transaction" と呼ばれる実行処理、そして "ACL" と呼ばれるアクセス権管理を定義してブロックチェーン環境に簡単にデプロイすることができるようになります。

この方法でデプロイしたブロックチェーンネットワークを外部のプログラムから使う方法も何通りかあるのですが、今回はその中から「Composer の内容を Web API 化」して、外部からは HTTP(S) を使った REST API として使えるように公開する方法を紹介します。以下の手順を実際に試す場合はローカル環境内に Hyperledger Fabric v1.0 および Hyperledger Composer がインストールされている必要があります。その手順は以下を参照して、ローカル環境で Hyperledger Composer が使える状態を作っておいてください:
Hyperledger Composer フレームワークをインストールする


また、実際に REST API として公開する内容のビジネスネットワークを定義した .bna ファイルが必要です。今回は以下のページで紹介されている方法に従って my-network.bna ファイルを作り、それを使うことにします(以下に日本語で解説します):
Developer Tutorial for creating a Hyperledger Composer solution


ではビジネスネットワークの定義ファイルを用意するまでの手順を紹介します。今回は github.com に公開されているサンプルをベースにクローンして用意します。

まず、上記リンク先の手順に従って Hyperledger Fabric v1.0 および Hyperledger Composer が導入された環境を用意して、両方のサービスを有効にします。

次に同環境にログインし、作業ディレクトリ(以下の例では ~/work)を作って、サンプルプロジェクトを git clone します:
$ mkdir ~/work (作業ディレクトリ)
$ cd ~/work
$ git clone https://github.com/hyperledger/composer-sample-networks.git

このサンプルプロジェクト内の basic-sample-network の内容を my-network という名前でコピーします:
$ cp -r ./composer-sample-networks/packages/basic-sample-network/  ./my-network

my-network プロジェクトの package.json ファイルを変更します。変更内容は name と prepublish 内のプロジェクト名を "my-network" にすることと、description の内容を変えることです:
    :
  "name": "my-network",
  "version": "0.1.6",
  "description": "My Commodity Trading network",
  "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg",
  "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg",
  "scripts": {
    "prepublish": "mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/my-network.bna",
    "pretest": "npm run lint",
    :

そして実際のビジネスネットワークの内容を書き換えます。定義する内容は上記ブログエントリの中で紹介したものと同じ定義をこのプロジェクト内にも作成することにします。というわけでまずは models/sample.cto ファイルを開き、以下の内容に書き換えて保存します:
/**
 * My commodity trading network
 */
namespace org.acme.mynetwork
asset Commodity identified by tradingSymbol {
    o String tradingSymbol
    o String description
    o String mainExchange
    o Double quantity
    --> Trader owner
}
participant Trader identified by tradeId {
    o String tradeId
    o String firstName
    o String lastName
}
transaction Trade {
    --> Commodity commodity
    --> Trader newOwner
}

↑ Commodity という asset と、Trader という participant と、Trade という transaction を定義しています。

同様にして lib/sample.js ファイルを開き、以下の内容に書き換えます:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Track the trade of a commodity from one trader to another
 * @param {org.acme.mynetwork.Trade} trade - the trade to be processed
 * @transaction
 */
function tradeCommodity(trade) {
    trade.commodity.owner = trade.newOwner;
    return getAssetRegistry('org.acme.mynetwork.Commodity')
        .then(function (assetRegistry) {
            return assetRegistry.update(trade.commodity);
        });
}

↑tradeCommodity という処理を定義しています。

そして同様にして permissions.acl ファイルも以下の内容に書き換えます:
/**
 * Access control rules for mynetwork
 */
rule Default {
    description: "Allow all participants access to all resources"
    participant: "ANY"
    operation: ALL
    resource: "org.acme.mynetwork.*"
    action: ALLOW
}

rule SystemACL {
  description:  "System ACL to permit all access"
  participant: "org.hyperledger.composer.system.Participant"
  operation: ALL
  resource: "org.hyperledger.composer.system.**"
  action: ALLOW
}

↑デフォルトで全参加者にリソースへのアクセス権を与えるという内容です。


ではここまでに定義した models/sample.cto, lib/sample.js, permissions.acl の内容でビジネスネットワークをビルドします:
$ cd ~/work/my-network
$ npm install

このコマンドが成功すると、 my-network/dist フォルダ内に my-network.bna ファイルが生成されます。このファイルと Hyperledger Composer を使って Hyperledger Fabric v1.0 に同ビジネスネットワークをデプロイします:
$ cd dist
$ composer network deploy -a my-network.bna -p hlfv1 -i PeerAdmin -s randomString

デプロイが成功しているかどうかは以下の ping コマンドで確認できます:
$ composer network ping -n my-network -p hlfv1 -i admin -s adminpw

ここまでの作業でビジネスネットワークを定義し、Hyperledger Fabric v1.0 上にデプロイすることができました。最後にこのビジネスネットワークを Web API 化して HTTP クライアントから REST でアクセスできるようにします。 そのためには composer-rest-server というツールを使います。composer-rest-server は npm を使ってインストールします:
$ sudo npm install -g composer-rest-server

composer-rest-server の使い方は REST API 化したい Hyperledger Composer プロジェクト上でコマンド実行するだけです:
$ cd ~/work/my-network
$ composer-rest-server

すると Hyperledger-Composer ロゴが現れ、知る人ぞ知る Strongloop loopback のようなインターフェースでのプロパティ指定画面になります:
2017081401


質問内容に以下のように答えます:
 Fabric Connection Profile Name: hlfv1
 Business Network Identifier: my-network
 Fabric username: admin
 secret: adminpw
 namespaces: never use namespaces
 (ここから下はデフォルトのまま)
 REST API to be secured: No
 event publication over WebSockets: Yes
 TLS security: No
2017081402


すると上記画面のように http://(IPアドレス):3000/explorer と表示されます。ウェブブラウザでこの URL にアクセスすると、(これも知る人ぞ知る StrongLoop Loopback のような)定義したビジネスネットワークに REST API でアクセスするための Open API ドキュメントが表示されます:
2017081403


この画面からは定義した Commodity や Trader, Trade といった asset, perticipant, transaction を読み書き実行するための各 API を展開したり、
2017081404


実際にパラメータを指定して実行したりすることもできます:
2017081405


この方法であればブロックチェーンにあまり詳しくないデベロッパーでも REST API で利用できるので非常に便利といえます。

 

このページのトップヘ