こんにちわ。ばたっちです。
Rails 2.0の REST対応はは、RESTアプリのサーバ側の機能と、クライアント側の機能が入ってるんですね。
- サーバ側 : ActionController::Resourcesとか
- クライアント側 : ActiveResource
サーバ側では config/routes.rbに「map.resource :entry」のように書くだけで、CRUDな URLを生成してくれます。
例えば、コントローラで、
とすれば、Entryオブジェクト(ActiveRecord)を自動で XMLに変換して返します。
(ActiveRecordの to_xmlの結果をそのまま返すみたい。だからテンプレート不要。)
一方 ActiveResourceは、クライアント側で RESTで提供されているリソースを、まるで ActiveRecordのオブジェクトのように扱えるようにしてくれるクラス。
例えば、上記の showアクションのレスポンスとして、
のようなXMLを返す RESTアプリがあって、それを ActiveResourceで扱うと、
こんなカンジでアクセスできます。find()の裏では「GET /entries/1.xml」のように HTTP GETしてるんですね。
うーん、すごい。
さて、Railsが自動で作ってくれる CRUDなインターフェースがそのまま使えれば、とても便利なのですが、実際に RESTアプリを作ると考えると、少し工夫が必要になりそうです。
例えば、
- クライアントの認証が必要な場合は?
- ActiveRecordの idをプライマリキーにしない場合は?
という場合はどうするんだろといったカンジ。
まず、認証については、アカウント名+パスワードで認証するのであれば、URLにアカウント名、パスワードを含めてBASIC認証にするみたい。
なるほど。
ちなみに RESTの定義としてセッションなどにログイン情報を持たず、毎回のリクエストでリソースの参照を完結すべきだそうで、認証が必要な場合は認証情報も毎回送る形になるようです。
それから、APIキーを発行するだけのような場合、URLの後ろに「api_key=key1」のようにクエリパラメータをつけるのは RESTっぽくない気がするので、
http://api.example.com/api/key1/entries/1.xml
のように、URLのプレフィクスに入れる方法を考えてみました。
この場合では、ActiveResourceの siteにプレフィクスまでを含めた URLを設定すればできるようです。
次に、idをそのままプライマリキーに使えない場合。
例えば、外部の固定リソース(郵便番号情報とか)の上に RESTアプリをかぶせたりする場合、idをキーにすると外部リソースとの連携がしづらい。
例の Entryを日付をキーにしてとるような URLを考えてみる。
/api/key1/entries/20080415_001.xml
サーバ側では、config/routes.rbには以下のように設定します。
(ただし、Routing::RouteBuilderには、先日のエントリの修正をいれています。see. [Rails] routingの namespace。)
EntriesController#showには、{ :key => "key1", :action => "show", :date => "20080415_001" } のようなパラメータが渡されるので、うまく検索できるように実装します。(^^;
クライアント側では、この URLだと ActiveResourceの find(1)のような方法では取得できないのですが、ActiveRecordの findと同様、いろいろできちゃうのが find()メソッド。(^^)v
ActiveResource::Base#findメソッドには、:fromというパラメータで URLを直接指定することができるようです。
したがって、
のようにアクセスすることができます。
ちなみに、:fromパラメータには Request-URIを先頭から指定しないといけないようで、self.site に設定したプレフィクスには続けてくれないようです。
のようなメソッドを作るとよさそうですね。
他にも、element_pathという URLを作成するメソッド?があるので、そちらも使えそう。
Request-URIのプレフィクスが有効になるようです。
(こちらは逆に .xmlが勝手についてしまうので、外す方法が分かりません。A^^;)
以下はサーバとクライアントのログ。
サーバ側
クライアント側
プロセス間通信の実験みたい(プロセス間通信だけど)で面白い♪
でも、まだまだ試行錯誤ですねぇ~ (^^)/~