PR

Webサービスの引数にXMLを使わないREST

 XMLRPCはエンベロープなどがない分だけSOAPよりも簡易な方法だが,引数をXML化する処理はなくならず,サーバー側ではXMLのパース処理が必要になる。そこで代案として考えられるのが,引数をテキストのまま送信する「REST方式」である。

 REST方式では,GETメソッドのURLクエリー部分(URLの「?」以降)やPOSTメソッドのボディ部に,「引数名=値&引数名=値…」という形式で,引数を渡す。これは,Webアプリケーションが入力フォーム(<form>)を使ってSUBMITするときと同じデータ形式である。REST方式は呼び出し方法が簡単なので,Ajaxに限らず多くのWebサービスで使われている。

 REST方式の最大の利点は,Webサービスを呼び出す際の引数にXML形式を使わない点だ。呼び出し側は,引数を「=」や「&」でつなぎ合わせるだけでよい。呼び出されるサーバー側では,Webアプリケーションのフレームワークが提供する一般的な方法を使って引数を取得できる。例えばPHPなら,「$_GET」や「$_POST」,ASP.NETなら「Requestオブジェクト」といったように,Webアプリケーションのフォームに入力された値を取得するのと同じ方法で引数を得られる。

 またデバッグが容易であるという点も,メリットとして挙げられる。REST方式はWebフォームを使って呼び出すのと同じ形式なので,デバッグ時には,

<form method="GET" action="WebサービスのURL">
<input type="text" name="引数名">

<input type="submit">
</form>

のようなテスト用のフォームを用意し,それをSUBMITすれば,Webサービスの動作を簡単に調べられる。

 AjaxでREST方式のWebサービスを呼び出すにはリスト1のように記述する。GETメソッドの場合には,呼び出す際のURLの後ろに,引数をURLクエリーとして指定すればよい。

httpreq = new XMLHttpRequest(); 
query = "引数名1=値1&引数名=値2…";

【GETメソッドの場合】
// URLの後ろにクエリーを渡す
httpreq.open("GET", "http://www.example.co.jp/myrestsvc.cgi?"
 + query);
httpreq.send(null);

【POSTメソッドの場合】
httpreq.open("POST", "http://www.example.co.jp/myrestsvc.cgi");
// Content-Typeの設定が必要
httpreq.setRequestHeader("Content-Type",
 "application/x-www-form-urlencoded");
// ボディ部として引数を渡す
httpreq.send(query);
リスト1●REST形式のWebサービスを呼び出すコードの例
POSTメソッドの場合には,setRequestHeaderの呼び出しが必要

 POSTメソッドの場合には,sendメソッドでボディ部として引き渡すことになるが,setRequestHeaderを使ってヘッダーのContent-Typeを「application/x-www-form-urlencoded」に設定しておくのがポイントである。この設定を忘れると,サーバー側で,$_POSTやRequestオブジェクトなどを使って引数を取得できなくなるので注意したい。

JavaScriptの関数で展開できるJSON

 REST方式を使うと,Webサービスの引数の引き渡しが簡単になる。残る問題は,Webサービスからの戻り値の形式である。

 もしWebサービスから部分的なHTMLを返し,それを現在表示しているHTMLの特定の要素に流し込むだけなら話は簡単だ。その場合には,戻り値として得たHTML(もしくはXML)を,DOMを使って流し込めばよいだけだからだ。

 そうではなく,Webサービスの戻り値で得た数値や文字列を取り出して加工したい場合,XML形式だとパース処理が必要になる。

 そこで,XMLの代わりに検討したいのが,簡易なテキスト形式としてデータ構造を表現できる「JSON(JavaScript Object Notation)」である。JSONは軽量なデータ交換フォーマットであり,JavaScript(ECMA-262)をベースに作られている。JSONの最大の特徴は,JavaScriptの文法を利用しているので,eval関数を用いて展開できる点だ(図3)。JSON形式のデータを読み書きするライブラリは,C,C#,Java,Perl,PHPなど,多数の言語用のものが存在する。そのため,サーバー側でJSON形式の戻り値を生成するのも複雑ではない。

図3●戻り値をJSON形式にする場合の例&lt;br&gt;Webサービスの戻り値から利用者に表示する値などを取り出す場合,JavaScriptのeval関数を使うことができる。XMLのパースは不要になる
図3●戻り値をJSON形式にする場合の例
Webサービスの戻り値から利用者に表示する値などを取り出す場合,JavaScriptのeval関数を使うことができる。XMLのパースは不要になる
[画像のクリックで拡大表示]

 Ajaxでは,Webサービスとのデータのやり取りをできるだけ簡略化するため,「引数はREST方式で,戻り値はJSON形式で」という構成をとることが多い。しかしこれは一例にすぎず,規則というわけではない。効率面から見れば,引数はREST方式が一般的と思われるが,戻り値をJSON形式にする必然性はない。例えば単純なデータ列なら,カンマ区切りのテキストを返すといった方法でもよいだろう。要は,パースの手間さえなくなればよく,どのような形式が望ましいかは,扱うデータの種類によって違ってくる。

●異なるサーバーでも呼び出し可能に
クロスドメインでも通信できるJSONP

 XMLHttpRequestオブジェクトを使った送受信では,セキュリティ上の理由から,HTMLコンテンツを送り出したサーバーと同じサーバーとしか通信できないという制限がある。

 このようなドメインの異なるサーバーとの通信――クロスドメインでの通信――の制限を解決するのが「JSONP(JSON with Padding)」という仕組みだ。

 JSONPでは,XMLHttpRequestオブジェクトではクロスドメインでの通信ができないけれども,<script>要素のsrc属性では,どのドメインからでもJavaScriptのソースを読み込んで実行できるという事実を利用する。

 JSONPを使ったWebサービスの呼び出しは,図4のようになる。

図4●JSONPを使ったWebサービスの呼び出し
図4●JSONPを使ったWebサービスの呼び出し
[画像のクリックで拡大表示]

 JSONPのポイントは,XMLHttpRequestオブジェクトを使ってWebサービスを呼び出すのではなく,「<script src="呼び出し先のWebサービスのURL">」という要素を動的に作り出すことで呼び出すという点だ。

 しかしこれだけでは,「読み込みの完了」を知ることができない。そこで,Webサービスの呼び出し時に,適当な関数名を渡し,Webサービス側のプログラムの出力に,その関数の呼び出す文を付け加えてもらうようにする。

 そうすることで,受信が完了したときに該当の関数がコールバックされ,呼び出しの完了を知ることができる。

 JSONPは,Ajaxを使って呼び出して欲しいサービスを幅広く提供する場面で使われ始めている。たとえば,米ヤフーの「Yahoo! Web Services」では,JSONPサービスを使ってキーワード検索ができる機能を提供している。

 この検索サービスは,api.search.yahoo.comドメインで提供されているが,JSONP形式であるため,呼び出し側のHTMLコンテンツが,どのドメインにあっても通信できる。