Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Breeze入門

Breeze入門

データ管理JavaScriptライブラリ「Breeze」とは

2013年10月31日

クライアントサイドのJavaScriptでのデータ処理を簡単にするライブラリ「Breeze」を紹介。JSONデータをキャッシュしたり、ODataのクエリ文字列などを利用したデータのソートやページング処理をしたりできる。

日本マイクロソフト株式会社 エバンジェリスト 井上 章 (ブログ: THE TRUTH IS OUT THERE
  • このエントリーをはてなブックマークに追加

 最近のWebアプリケーション開発のトレンドの1つとして、クライアントサイドにおけるJavaScriptの重要度が増していることは、特にHTML5やマルチデバイスといったキーワードが飛び交う中で最新のWeb開発に携わる開発者であれば周知の事実であろう。また、多種多様なJavaScriptライブラリが登場する中で、jQueryはもはやデファクト・スタンダードとしてその地位を確固たるものにしており、そのプラグインとして動作するJavaScriptライブラリも非常に多い。もはや、JavaScriptというよりは、jQueryでコードを書くといっても過言ではない状況でもある。

 このように、今や欠かすことのできない各種JavaScriptライブラリだが、サーバーサイドとのデータ通信において、REST(RESTful)APIなどのさまざまなHTTPサービスから取得するJSONデータをそのままクライアントサイドのJavaScriptで利用するケースも多く、そのデータをクライアントでキャッシュしたり、例えばODataのクエリ文字列などを利用したソートやページング処理などを効率よく実装したりする場合など、JavaScriptコーディングのハードルが高くなることになる。

 このようなクライアントサイドでのデータ・アクセスやデータ管理に対してのプログラミング負荷を低減するために登場したのが、本記事で紹介する「Breeze(ブリーズ、Breeze.js)」と呼ばれるJavaScriptライブラリだ。

Breezeとは

 Breezeとは、一言でいえば「JavaScriptで高機能なデータ管理機能を提供するライブラリ」だ。代表的な機能は下記が挙げられる。

  • シンプルなデータ・アクセスとクエリ
  • クライアント・キャッシング
  • 自己追跡エンティティ
  • データ・バインディング(Knockout.jsAngularJS*1
  • Promise非同期パターン
  • *1本稿およびBreezeでは、「Konckout」や「Angular」と表記している。

 BreezeのWebサイトでは、各種チュートリアルやサンプルコード、APIリファレンスなどが用意されている。また、もちろんオープンソースとしてGitHubのIdeaBlade / Breezeでソースコードが公開されている(MITライセンス)。

 加えて、BreezeのWebサイトにあるLearn Breezeページでは、Webブラウザー上でBreezeの機能とそのコードを一通り確認できるようになっている(次の画面)。

Learn Breezeページ

 現時点では、ページ上部中央のボタンから下記4種類のチュートリアルを選択できる。

  • Tutorial 1 - Queries - w/Knockout
  • Tutorial 1 - Queries - w/Angular
  • Tutorial 2 - More advanced queries - w/Knockout
  • Tutorial 3 - Executing queries locally - w/Knockout
  • Tutorial 4は「Coming soon」となっている
チュートリアルの選択

 まずはこのLearn Breezeページを使って、Breezeの基本機能を紹介する。

Breezeの基本機能 ~ データ・アクセスとクエリ ~

 1つ目のチュートリアル“Tutorial 1 - Queries - w/Knockout”では、6ステップでBreezeとKnockoutを使ったデータ・アクセスとクエリの基本を学べるようになっている。

 まず始めに4分割されたウィンドウの[JavaScript]ペインに表示されるコードが、Breezeの基本的なコードになる(次のコード)。

JavaScript
var manager = new breeze.EntityManager('api/northwind');  …… 1

var query = new breeze.EntityQuery()  …… 2
  .from("Employees");

manager.executeQuery(query).then(function(data){  …… 3
  ko.applyBindings(data);

}).fail(function(e) {
  alert(e);
});
Breezeを使ったデータ・アクセスとクエリの基本コード(Tutorial 1より)
  • 1Breezeの中核となるEntityManagerクラス・オブジェクト。ここではHTTPサービスのルートURL“api/northwind”でインスタンスを生成している。
  • 2データ・ソースへのクエリを行うEntityQueryクラス・オブジェクト。リソース名 “Employees”(ここでは “Employee”アイテムを返すHTTPサービス・メソッド名)を指定している。
  • 3クエリを実行し、Knockoutを用いて結果をHTMLソース内の要素へバインド。Promise非同期パターンに沿った記述が可能。

 EntityManagerはBreezeのクライアント処理の中核となるクラスだ。このEntityManagerオブジェクトを通してデータのクエリや保存、クライアント側でのデータ・キャッシングなどが行われる。データ・クエリの実行においては、EntityQueryクラス・オブジェクトを利用する。

 チュートリアルでは、ページの左下の[Output]ペインにある[Run]ボタンを押すと実際にデータ・クエリが実行されて、その結果がブラウザー上で確認できる(次の画面)。

「Tutorial 1: Step 1」の実行結果
「Tutorial 1: Step 1」の実行結果

 続いて、チュートリアル・ページの左上の[Step 1 to 6]ペインにある記述のとおり、orderByメソッドを使って “LastName”でソートを行ってみよう。下記のとおり、「.orderBy(“LastName”);」の1行を追加するだけだ(メソッドチェーンでの記述が可能)。

JavaScript
var query = new breeze.EntityQuery()
  .from("Employees")
  .orderBy("LastName");
orderByメソッドによるデータのソート

 このコードの実行結果は下の画面のとおりとなる。“LastName”でソートされていることが確認できるだろう。

Tutorial 1: orderByメソッドによるソート結果
Tutorial 1: orderByメソッドによるソート結果

 なお、ここでのソートはクライアントサイドで行われるのではなく、HTTPサービスAPIの呼び出しを通してサーバーサイドで行われていることに注目していただきたい。上記コードの実行時のHTTPリクエストをFiddlerなどのツールを使って確認すると、下記のようなHTTP GETリクエストURIが使われていることが分かる。

http://learn.breezejs.com/api/northwind/Employees?$orderby=LastName
Breezeによって生成されたHTTP GETリクエストURI

 このURIを見て気付いた方も少なくないだろうが、Breezeのデータ・クエリにはODataプロトコルURIクエリ文字列が使われている。つまり、サーバー側のHTTPサービスではODataのクエリ形式に対応したメソッドを用意する必要があることに注意が必要だ。

 チュートリアルTutorial 1のStep 4などでは、もう少し詳しいクエリの利用方法を見ることができる(次のコード)。

JavaScript
var manager = new breeze.EntityManager('api/northwind');

var query = new breeze.EntityQuery()
  .from("Employees")
  .orderBy("LastName")
  .where("BirthDate", "lt", new Date(50, 9, 12));
manager.executeQuery(query).then(function(data){
  ko.applyBindings(data);

}).fail(function(e) {
  alert(e);
});
「Tutorial 1: Step 4」のサンプルコード

 このコードを使ったクエリで使われる実際のHTTPリクエストURIは下記のとおりとなる。

JavaScript
http://learn.breezejs.com/api/northwind/Employees?$filter=BirthDate%20lt%20datetime'1950-10-11T15%3A00%3A00.000Z'&$orderby=LastName
Breezeによって生成されたHTTP GETリクエストURI

 BreezeなどのJavaScriptライブラリを使用せずに、このようなクエリ文字列を組み立てるのは大変だろう。これだけを見ても、Breezeを使う意味が十分あるのではないだろうか。

ローカル・キャッシュへのクエリ

 前述のBreezeを使ったデータ・アクセスの例では、データのソートやフィルタリングが必要になった場合に、その都度サーバーサイドからデータを取得することになる。もちろん、その頻度が少ない場合や、ネットワーク帯域やHTTPペイロード、加えてアプリケーションのレスポンスなどを気にしなくてもよい場合はこのままでもよいだろう。

 しかしながら、より効率よいデータ・アクセスを実現するために、Breezeではサーバーサイドから取得したエンティティ・データをキャッシュし、それに対してローカルでクエリを行えるようになっている。

 Breezeのチュートリアル“Tutorial 3 - Executing queries locally - w/Knockout”では、そのローカル・キャッシュを使ったデータ・クエリ方法を学ぶことができる。下記がこのチュートリアルで挙げられている1つ目のサンプルコードだ。

JavaScript
var manager = new breeze.EntityManager('api/northwind');

var query = new breeze.EntityQuery()
  .from("Customers");
manager.executeQuery(query).then(function(data) {  …… 1

  var query2 = query.where("CompanyName", "startsWith", "C");  …… 2
  var customers = manager.executeQueryLocally(query2);  …… 3

  var localQueryData = { results: customers };
  ko.applyBindings(localQueryData);

}).fail(function(e) {
  alert(e);
});
Breezeを使ったデータ・アクセスとローカル・キャッシュへのクエリの例(その1)
  • 1サーバーサイドへクエリを実行し、比較的まとまったエンティティ・データを取得。
  • 2会社名がアルファベットの大文字“C”で始まるエンティティを抽出するためのクエリ・オブジェクトを生成。
  • 3executeQueryLocallyメソッドを使い、ローカル・キャッシュに対してクエリを実行。

 executeQueryLocallyメソッドを使用することで、ローカル・キャッシュに対してクエリを行えるため、クライアントサイドでのエンティティ・データのソートやフィルタリングなどの実装が容易に行える。ただし、このexecuteQueryLocalyメソッドの実装は現時点では同期処理となるため、Promise非同期パターンを使った記述ができないことに注意が必要だ。

 一方で、このローカル・キャッシュを使ったクエリにはもう1つの方法が用意されている。これが、Tutorial 3のStep 3に示されているサンプルコードだ。

JavaScript
var manager = new breeze.EntityManager('api/northwind');

var query = new breeze.EntityQuery()
  .from("Customers");
manager.executeQuery(query).then(function(data) {

  var query2 = query.where("CompanyName", "startsWith", "C")
             .using(breeze.FetchStrategy.FromLocalCache);  …… 1

  manager.executeQuery(query2).then(function(dataSubset) {  …… 2
     ko.applyBindings(dataSubset);
  });

}).fail(function(e) {
  alert(e);
});
Breezeを使ったデータ・アクセスとローカル・キャッシュへのクエリの例(その2)
  • 1FetchStrategy.FromLocalCacheクエリ・オプションを使い、ローカル・キャッシュを対象としたクエリ・オブジェクトを生成。
  • 2サーバーサイドへのクエリと同じexecuteQueryメソッドを使い、Promise非同期パターンで記述可能。

 クエリ・オブジェクトに対して、FetchStrategy.FromLocalCacheクエリ・オプションを指定することで、ローカル・キャッシュへのクエリとして設定でき、executeQueryメソッドをそのまま使用して、Promise非同期パターンで記述できる。サーバーサイドへのクエリとする場合にも、FetchStrategy.FromServerに変更するだけで済むため、こちらの方が利用しやすいのではないだろうか。しかし、コード上ではPromise非同期パターンで処理されているように見えるものの、現時点ではローカル・キャッシュへのクエリに関しては同期処理となることに注意したい。

メタデータ

 Breezeでは、エンティティの型やエンティティ間のリレーションなどの情報として、エンティティ・データ・モデルのメタデータを使用するため、サーバーサイドへのクエリやエンティティの追加・更新時などに、前もってサーバーサイドからメタデータの取得を行っている。前述のチュートリアルのサンプルコードなどでも、例えばexecuteQueryメソッドでクエリを実行したときに、メタデータの取得とデータの取得の2つのAPI呼び出しが行われている。

 下記は、チュートリアルのサンプル実行時のHTTPリクエストをInternet Explorer 11の「F12 開発者ツール」でキャプチャした様子だ。

Breezeによるメタデータの取得とデータのクエリのHTTPリクエストの様子

 最初に“/api/northwind/Metadata”のリクエストでメタデータの取得を行い、その後に“/api/northwind/Customers” のリクエストで、Customersエンティティ・データのリストをJSON形式で取得していることが分かる。

Breezeで利用可能なHTTPサービス(Web API)

 Breezeのドキュメントにも書かれているが、Breezeのクライアントサイド実装では、サーバーサイドのプラットフォームやデータ処理の実装などには依存しない設計になっている。しかし、Breezeとともに使用するHTTPサービスでは、JSON APIとしてメタデータの提供やODataクエリ文字列への対応などが条件となってくる。

 現状、BreezeはASP.NET Web APIフレームワークODataプロトコルをサポートしたHTTPサービスをサポートしており、ASP.NET Web APIを使用する際には、Entity Frameworkを通してBreeze向けのメタデータを生成するためのサーバーサイドの.NETコンポーネントも用意されている。

Breezeの入手とセットアップ

 先に紹介したBreezeサイトのダウンロードページから、その最新版(本記事執筆時点では1.4.2が最新)をダウンロードできる。現在は、Breezeライブラリと共に下記の3種類のサンプルコードも公開されている。

  • Breeze 1.4.2 + .NET Samples
  • Node.js/MongoDB Samples
  • Ruby Samples

 また、NuGetパッケージとしてもいくつか公開されているので、Visual Studio 2012/2013のASP.NET Web APIプロジェクトなどで容易に利用できるようになっている(次の画面)。

NuGetで公開されているBreeze関連パッケージ

 今回は、Breezeのデータ・アクセスとクエリ関連の機能を中心に紹介したが、これら以外にも自己追跡エンティティとデータ保存など、クライアントサイドでのデータ管理において非常に便利な機能を持っている。BreezeとKnockout.js/AngularJSなどを組み合わせて、例えばオフライン実行に対応したWebアプリケーションなど、よりリッチな機能を持ったシングル・ページ・アプリケーション(SPA)の実装も容易になるに違いない。

サイトからのお知らせ

Twitterでつぶやこう!