2011年2月16日

datajs を使って JavaScript で OData

OData を扱うための JavaScript ライブラリである datajs のアルファ版がリリースされました。 OData は Atom を拡張したもので、すでにいくつかの OData SDK がありましたが、 クライアントサイドのライブラリに新しく JavaScript が仲間入りした、という感じです。

ざっくりしたインターフェイスは New JavaScript library for OData and beyond (英語) および OData などに対応した軽量な JavaScript ライブラリ提供 (日本語) で紹介されている通りです。 これがどのブラウザでもサクッと動作してくれればそれでお終いなのですが、 残念ながらクロスドメインの制限がありますので、実際の動作を確認するためにはひと手間必要になります。 解決への選択肢は Cross-Domain Requests に記載されているものが挙げられます。

最初は (シリーズ化するつもりもないけど) 無難に localhost で全てのコンテンツをホストする方法で試してみます。 OData に沿った形式の XML ファイルを保存しておき、クライアントがそれを読み込んで、内容を表示することにします。

準備

まずは datajs が必要なので、プロジェクトのサイトからダウンロードします。 datajs.min.js として保存します。 次に、定番なので jQuery を使います。Google の CDN を使っても構いませんし、ローカルにダウンロードしてもどちらでも。 同様に、表示用に jQuery Template も使います。 簡単に導入できますし、JavaScript のコードも読みやすいと思いますので。

ということで、適当なディレクトリを作成し、これらを static ディレクトリに置きます (jQuery および jQuery Template の両方をダウンロードしたと仮定)。 ディレクトリの名前は odata-sample とでもしておきましょう。 さらに、適当な HTML と JavaScript のファイルを用意します。

$ tree odata-sample
odata-sample/
|-- odata-sample.html
|-- odata-sample.js
`-- static
    |-- datajs.min.js
    |-- jquery.min.js
    `-- jquery.tmpl.min.js

初期動作の確認

ベースとなる HTML ファイル (odata-sample.html) を記述します。 まずは先ほどのライブラリと、これから記述する JavaScript (odata-sample.js) を読み込みます。

<!DOCTYPE HTML>
<html lang="ja"><head>
<meta charset="utf-8">
<title>OData sample using datajs</title>
</head><body>
<div id="main">
<form method="get" action="#">
<input type="text" name="url" size="100" value="" placeholder="URL for your OData" />
<input type="submit" value="Load" />
</form>
<ul id="contents"></ul>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script>!window.jQuery && document.write('<script src="/static/jquery.min.js"><\/script>')</script>
<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
<script>!jQuery.tmpl && document.write('<script src="/static/jquery.tmpl.min.js"><\/script>')</script>
<script src="/static/datajs.min.js"></script>
<script src="/odata-sample.js"></script>
</body></html>

ファイルの配置が間違っていないことを確認するために、JavaScript ファイルでは alert で何かを表示させます。

$(function() {
    alert($.template);
});

続いて、Python でHTTP サーバを起動させます (HTTP サーバは好みで)。 次のコマンドで、8080番ポートでカレントディレクトリのコンテンツを配信します。

$ cd odata-sample
$ python -m SimpleHTTPServer 8080

ブラウザで http://localhost:8080/odata-sample.html にアクセスすると、ダイアログが表示されるはずです。

OData でリクエスト

HTML に簡単な <form/> を用意しましたので、その submit イベントにハンドラを設定します。

JavaScript (odata-sample.js)

$(function() {
    $('form').submit(function() {
        try {
            var url = $(this).find('input[name=url]').val();
            OData.read(url, function (data, response) {
                console.log(data);
                console.log(response);
            });
        } catch (e) {
            console.log(e);
        }
        return false;
    });
});

実際に次のいずれかの URL を入力してフォームを送信すると、リクエストが発行されます。 しかし、クロスドメインの制限に引っかかりますので、そこでエラーになります。

これは嬉しくありませんので、取得先のコンテンツをダウンロードしておきます。 これなら先ほどの制限には引っかかりません。

$ wget -O odata-sample.atom http://odata.netflix.com/v1/Catalog/Genres

テキストボックスに /odata-sample.atom と入力してフォームを送信すると、開発者コンソールにログが出力されます。 Firebug などの開発ツールを有効にしていない場合には有効にしておきましょう。

OData を表示

開発者ツールを使って JSON の構造を見ていきます。

一見して分かるのは、レスポンスの data には results という配列が含まれることです。 Atom の <entry/> に当たります。 atom:entry<title/> を持ちますが、OData では Name になります。きっと。

つまり、

  1. data.results に対して繰り返し処理を適用し、
  2. その Name 属性を表示させると、
  3. 何かの一覧っぽく見える。

JavaScript で表現すると次のようになります。 リストアイテムを HTML っぽく記述するために jQuery Template を使っています。

$(function() {
    $.template('template', "<li>${Name}</li>");
    $('form').submit(function() {
        try {
            var url = $(this).find('input[name=url]').val();
            OData.read(url, function (data, response) {
                var dt = [];
                for (num in data.results) {
                    var entry = data.results[num];
                    dt.push({Name: entry.Name});
                }
                $.tmpl('template', dt).appendTo('#contents');
            });
        } catch (e) {
            console.log(e);
        }
        return false;
    });
});

ブラウザで実行してみると次のように音楽のジャンル一覧が表示されます。

つらつらと書いてきましたが、ここまでの内容では datajs を使う必要性はありません。 Atom もしくは Atom 拡張ならば XML ですので、普通に DOM 操作を続けていけば良いだけですね。。

__deferred

開発者コンソールの JSON をもう一度確認してみると、 Titles__deferred 属性があります。 これは OData Protocol JSON Format - Deferred Content に記述されているもので、 とても大事なものです。たぶん。

Atom にも <link/> 要素がありますので、どこかを示す、という意味ではそれで十分ですが、 関連するデータの遅延読み込みをうまく表現できません (頑張れば可能でしょうが、多くの人はそこを頑張りたくないはず)。 たとえば、あるアーティストのアルバム一覧を表現し、個別のアルバムを指定したらアルバムに含まれる曲の一覧を表現する場合などです (リソースとリソースのコレクションをドリルダウン)。 システムを実装する中では、関係データベースでの参照や外部キーなどが近しい関係とも言えます。 「今すぐはいらないけど後で必要になるかもしれないから、取得方法だけ教えて」というものですね。

さて、 __deferred 属性を見てみると url があります。 この URL のコンテンツをダウンロードしてみると、これもやはり OData 形式になっています。 つまり、 __deferred 属性を順番に辿っていくことで、ドリルダウンを続けることが可能になります。

とはいえ、そのまま読み込もうとすると、先ほどと同様にクロスドメインの制限に引っかかります。 これを解決しないと先に進めないのが難点ですが、関連するコレクションへのアクセス方法を簡単化する、という意味では datajs を使うことで 一歩前進できるのではないでしょうか。

終わりに

OData 用の JavaScript ライブラリである datajs を使ってみました。 クロスドメインの制限は大きな壁となりますが、解決方法が存在しないわけでもありませんので、何となく使えそうな気がします。 ここでは扱っていませんが、 OData.request() を使うとデータの送信もできます。

OData 自体が広く普及しているわけではありませんが、複数のサービスが共通のデータフォーマットを利用することで、 データ交換、データ統合などが進んでいくと思います。 それぞれのサービスが、自分のサービスが提供している機能を記述するサービスドキュメントも用意しないといけない気がしますが、 少しずつ前進しているのは間違いないはずです。

クラウドという雲をつかむような話が多くなってきましたが、データ構造とアルゴリズムを分離する、という前提は変わりません。 データ自体はどこかに預けておき、操作したいデータだけを手元に持ってくる、というアプローチは今後も加速していくでしょう。 その一助として OData がどれくらいの影響力を持つか。 Microsoft 次第である部分も大きいですが、たまには見ておくと良いのかな、と思いました。


NOTE:
コメントを投稿