« Rails勉強会@東京 第5回 | メイン | 888.com World Snooker Championship »

2006年04月17日 (月)

Controller#respond_toはWeb ApplicationとWeb Serviceの垣根をなくす!? [テクニカル]

昨日のRails勉強会のポジションペーパーの内容を起こしてみた。内容はほとんどヽ( ・∀・)ノくまくまーからのインスパイヤなんですが。なので詳しくは元記事を見てください。このblogの記事の流れとしてはずいぶん前の「RESTful Web Applicationの可能性」からの続きの内容という感じです。

Rails 1.1からの新機能として、Controller#respond_toというメソッドができた。どういうものかというと、

  1. HTTP/1.1リクエストヘッダ中のAcceptフィールドを見る
  2. Content-Typeに応じてリクエストのデータ形式を自動変換してくれる
  3. 従って、コントローラは同じロジック(action)で対応できる
  4. Acceptの種類(mimeタイプ)に応じて、実行する描画処理を指定できる
  5. "*/*"が指定された場合はrespond_toの最初の定義を実行する
respond_to do |type|
  type.html { render }
  type.yaml { render :text => @resource.to_yaml }
  type.xml { render :text => @resource.to_xml }
end

さらにREST的インターフェイスを実現するために自前でコントローラを実装する。

class RestController < AbstractRestController
  def resource
  model_name = params[:model].camelize
  model = eval(model_name) # *超危険*
  if params[:id] # idがあればMember URI
    id = params[:id]
    @resource = model.find(id)
    case request.method
    when :get
      # Retrieving a Resource
      respond_to do |type|
      type.xml { render :text => @resource.to_xml }
      type.yaml { render :text => @resource.to_yaml }
      #type.json { render :text => @resource.to_json }
      #残念ながらtype.jsonはまだ対応していない
    end
    when :put
      # Updating a Resource (省略)
    when :delete
      # Deleting a Resource (省略)
    end
  else # idがなければCollection URI
    case request.method
    when :get
      # Listing Collection Members (省略)
    when :post
      # Creating a Resource
      new_resource = model.new(params[params[:model].to_sym])
      if new_resource.save
        render_post_success(:id => new_resource.id)
      else
        render :text => new_resource.errors.full_messages.join("\n"), :status => 406
      end
    end
  end
end

さらにroutes.rbをこんな感じに設定。

map.connect 'rest/:model/:id',
            :controller => 'rest', :action => 'resource', :id => nil

/rest/<モデル名>/<ID> という統一されたURI(Atom ProtocolでいうMember URI)でリソースにアクセスでき、さらに"Accept: application/xml"をつけるとXMLで取得、"Accept: application/x-yaml"をつけるとYAMLで取得したりできる。(JSONのMIMEタイプにまだ対応していないのが惜しいが、application/javascriptでもいいかな)

さらに取得だけではなく、/rest/<モデル名>というURI(Collection URI)に"Content-Type: application/xml"をつけてXMLをPOSTすれば、通常のFORM形式に変換してデータをCREATEしてくれる(くまくまーでは「うまく動きませんでした」って書いてあるけど、Rails 1.1.2で動作を確認。ただしContent-Lengthヘッダが必要)。

アプリケーションのすべてがRESTである必要はないが(というか無理)、Ajaxで使われるインターフェイスなどはとくにこんな感じで簡単にRESTが使えると、Webアプリケーションが即Webサービスとしても使えるようになるのでうれしい。

参考:

投稿者 4bit : 2006年04月17日 11:21 このエントリーを含むはてなブックマーク

トラックバック

このエントリーのトラックバックURL:
http://www.4bit.net/x/mt/mt-tb.cgi/113

コメント

さっぱり何言ってるかわかんなかったよ!w
あ。
Ajaxがオランダのサッカーチームなのは知ってる。

投稿者 アイダ : 2006年04月18日 09:45

あいださん、どうも~。
またスヌーカー連れてってくださいね!

投稿者 4bit : 2006年04月18日 21:16

コメントしてください




保存しますか?