気になる開発プロダクツ

第3回 Restlet 1.0.1-RESTアプリケーションを手軽に実現するフレームワーク

この記事を読むのに必要な時間:およそ 5 分

POSTメソッドの実行

これまでは,HTTPのGETメソッドしか実行していませんでした。Web APIがGoogleやYahooなどからリリースされ始めた当初は,彼らが蓄えているデータベースを参照する機能が主に提供されていましたが,最近ではBlogger Data APITwitter APIのように,投稿機能が提供されるようになってきています。

そこで,RESTアプリケーションが投稿を受け付けられるようにするために,ここからはRestletでPOSTメソッドを実行する方法を説明していきます。

リスト4はクライアントアプリケーションの例です。投稿するデータは,生成したFormインスタンスにパラメータとして設定します。同じ名称のパラメータを複数設定することもできます。次に前述したようにClientインスタンスを準備します。ここでもアクセスするURLがサーバの設定と一致していることを確認しましょう。

POSTメソッドの実行は,このクラスのpost()メソッドで行いますが,引数にはFormをWeb上で送受信できる形式(RestletではRepresentationと呼ぶ)に変換したオブジェクトを設定する必要があります。

リスト4 POSTメソッドを実行するクライアントアプリケーションの例

// 投稿するデータ(パラメータ)をフォームに追加
Form form = new Form();
form.add( "a", "パラメータ1" );
form.add( "b", "パラメータ2" );
// クライアントを準備する
Client         client = new Client( Protocol.HTTP );
String         url    = "http://localhost:8888/";
Representation rep    = form.getWebRepresentation();
// 文字コードを指定する場合
// Representation rep = form.getWebRepresentation( new CharacterSet( "Shift_JIS" ) );
// サーバにアクセス
Response res = client.post( url, rep );

リスト5はPOSTメソッドを実行するRestletの例です。クライアントからのリクエストはFormで送信されましたので,RestletではRequest#getEntityAsForm()メソッドを実行して,リクエストからFormを取得します。

この例では,パラメータ名称とデータとが1対1になっていますので,クライアントから送信されたデータはParameter#getFirst()メソッドでそのまま取得できますが,リクエスト中に同じ名称のデータが複数存在する場合は,subList()メソッドを実行するなどして個別にデータを取得するようにします。

リスト5 POSTメソッドによるアクセスを受け付けるRestletの例

Restlet restlet = new Restlet()  {
  @Override
  public void handle( Request request, Response response )  {
    // リクエストからFormを取得する
    Form form = request.getEntityAsForm();
    // パラメータの取得
    Parameter a = form.getFirst( "a" );
    Parameter b = form.getFirst( "b" );
    // 直接データを取得する場合
    // String a1 = form.getFirstValue( "a" );
    // String b1 = form.getFirstValue( "b" );
    // 複数のデータを個別に取得する場合
    // String a2 = form.subList( "a" ).get(1).getValue();
    // String b2 = form.subList( "b" ).get(1).getValue();
    // .......... その他の処理 .....
  }
};

BASIC認証を行う

データベースの参照は,アクセス負荷を考慮する必要がある程度で,あとはそれほど大きな問題はないでしょうが,投稿や更新を行う場合は,アクセスするユーザをある程度制限するのは,セキュリティ上あるいは投稿の内容の問題などがあり,どうしても必要になります。そのときWeb APIではBASIC認証でアクセスを制限することが一般的になっています。

WebブラウザでBASIC認証が必要なWebサイトにアクセスすると,閲覧の直前にユーザ名とパスワードの入力が求められます。しかし,クライアントアプリケーションの場合は人間のユーザがいちいちこれらの入力をすることができませんので,クライアントアプリケーションにあらかじめユーザ名とパスワードを設定してサーバにアクセスします。

リスト6がその例です。BASIC認証に関係するのはChallengeSchemeとChallengeResponseです。サーバにアクセスする前にこれらをRequestに設定した上でアクセスします。認証されたかどうかはStatusで判断します。

リスト6 BASIC認証を要求するサーバにアクセスするクライアントアプリケーションの例

// BASIC認証用のリクエストを設定(ユーザ名とパスワード)
ChallengeResponse basicAuth = new ChallengeResponse(
    ChallengeScheme.HTTP_BASIC, "username", "password" );
Request request = new Request( Method.GET, "http://localhost:8888/" );
request.setChallengeResponse( basicAuth );

// サーバにアクセス
Client client = new Client( Protocol.HTTP );
Response response = client.handle( request );

// アクセスできたかどうかを確認
Status status = response.getStatus();
if ( status.isSuccess() ) {
  // ..... 認証された場合の処理 .....
} else if ( status.equals( Status.CLIENT_ERROR_UNAUTHORIZED ) ) {
  // ..... 認証されなかった場合の処理(Status.CLIENT_ERROR_FORBIDDENが返される場合もある) .....
} else {
  // ..... その他のエラーでアクセスできない場合の処理 .....
}

一方,RestletにもBASSIC認証を設定できます。この場合はリスト7のように,サーバの設定にComponentインスタンスを使用します。これはBASIC認証の設定を行うGuardインスタンスに実行環境の状態を設定する必要があるためです。Webブラウザからこれにアクセスすると,図2のように認証用のダイアログが表示されます。

リスト7 BASIC認証を必要とするRestletの例

// RESTアプリケーション
Restlet restlet = new Restlet()  {
  @Override
  public void handle( Request request, Response response )  {
    // ..... RESTアプリケーションの処理 .....
  }
};

// サーバの設定
Component component = new Component();
component.getServers().add( Protocol.HTTP, 8888 );
// BASIC認証の設定
Guard guard = new Guard( component.getContext(), ChallengeScheme.HTTP_BASIC, "An Interest Products" );

// ユーザ名とパスワード
guard.getSecrets().put( "username", "password".toCharArray() );
guard.setNext( restlet );

// サーバにアプリケーションを設定
component.getDefaultHost().attach( "", guard );

// サーバ起動
component.start();

図2 認証用の入力ダイアログが表示された

図2 認証用の入力ダイアログが表示された

XMLデータの取得

Web APIの実行結果はXMLデータとなる場合が多いので,それをアプリケーション内で処理しやすいオブジェクトで取得できると便利です。そこで,最後にレスポンスのXMLデータをDOMオブジェクトで取得するクライアントアプリケーションを紹介します。

リスト8は,いまこの記事をお読みいただいているgihyo.jpのRSSデータを取得して,記事タイトルを出力する例です。ここではサーバへのアクセス時にClient#getEntityAsDom()メソッドを実行して,レスポンスをDomRepresentationインスタンスで取得しています。

こうすると,getNodes()メソッドで必要なデータをXPath式で取得できます。また,getDocument()メソッドでDocumentインスタンスを取得すれば,XSLTによってデータを変換することもできますし,レスポンスのすべてのデータにいつでもアクセスできます。

リスト8 gihyo.jpのRSSデータを取得し,記事のタイトルを出力

Client client = new Client( Protocol.HTTP );
DomRepresentation rss = client.get( "http://www.pheedo.jp/f/gihyo_rss2" ).getEntityAsDom();
for( Node n : rss.getNodes( "//item/title" ) )  {
  System.out.println( "タイトル = " + n.getTextContent() );
}

図3 出力結果(例)

タイトル = 2007年6月8日 《注目》Metisse追加,開発版Video LAN更新,Wackamole/Abraca/Lens追加,PHP5更新,ほか
タイトル = 第2回 Prologをご存じですか?
タイトル = 第2回 対話を促進する学び場の運営ノウハウ[中編] 勉強会当日の進め方

.......... ほかにもいろいろなタイトルが出力される .....

Restletは,RESTアプリケーションをシンプルに構築するための手段を用意しています。Web APIの実行結果がJSONだったらどうすればよいでしょうか。その場合は拡張ライブラリのJsonRepresentationクラスを用いることができます。他にもJDBCやSpring Frameworkと連携するクラスもあります。

紹介しきれないクラスはまだいろいろありますので,Web APIに興味がある読者は,Restletを試してみてください。

著者プロフィール

沖林正紀(おきばやしまさのり)

SE/プログラマを経て,WebアプリケーションやXMLなどについて雑誌記事や書籍の執筆活動を始める。大手メーカで製品資料の作成や,セミナーの講師を担当したこともある。現在は,取材記事や製品レビューなどに執筆活動の幅を広げる一方,プログラミング教材の開発も手がけている。

著書