rails3 + backbone.jsでデータのやり取りをするために。
RailsでWEB APIサーバを作るときのアーキテクチャをどうするか考える
RESTful APIとWebサイトを1つのアプリケーションで作る
で、この時はAndroidアプリしかAPIを使うクライアントはいなかったんだけど、等々HTMLから使うときが来ました!
この時のために、いろいろ考えて自分なりのRESTfulなAPIを作ってきたつもりだった。
で、ここまでの積み重ねを活かせると思い、backbone.jsも採用したのでなんかもう自分的には伏線回収フェーズが来ました的な。
上記リンクのとおり、APIはサブドメインを切って受け付けることにしたけど、backbone.jsはデフォルトだと同一ドメインに対してリクエストを飛ばすので(あたりまえ)これを変更する。
backbone.jsでajaxのリクエスト先を別のHostにする方法
すると問題になるのがsame-originポリシー。これはCORSな対応で回避する。
具体的には、ApplicationControllerあたりにAllow-Originなどを設定してやる。
before_filter :set_format, :allow_cross_domain_access private def allow_cross_domain_access response.headers["Access-Control-Allow-Origin"] = Settings.allow_origin response.headers["Access-Control-Allow-Methods"] = Settings.allow_methods response.headers["Access-Control-Allow-Headers"] = Settings.allow_headers end
Setting.hogehogeはRailsで環境ごとの設定値を定数的に扱えるSettingslogicね。
で、これでとりあえず指定のOriginからリクエストを発行したブラウザはレスポンスを受け付けてくれるようになる。
が、backbone.jsは各リクエストの前にOPTIONSメソッドを発行してくるので、これの対応が必要。
OPTIONSメソッドについては、この辺。http://www.studyinghttp.net/method#OPTIONS
ざっくりいうと、APIサーバに対して、「おまえんとこは、どんなメソッドとかヘッダに対応してるの?」という問い合わせを本チャンのリクエストの前に送ってくる仕組みらしい。
で、これにRailsで対応するには、
routingで、こんな感じ。
match '/hoges', to: 'hoges#options', constraints: {method: 'OPTIONS'} match '/hoges/:id', to: 'hoges#options', constraints: {method: 'OPTIONS'}
この書き方だと、リソースごとどころか、URLパターンごとにいちいちroutingを定義しなきゃいけないので、ちょっと考えなきゃいけないな、と思ってる。どうしたらいいんだろ??
hoges_controller.rb
def options head :no_content end
メソッド名は別になんでもいい。返却するのも、さっき設定したヘッダが重要なのであって、ここはなんとなく204かなぁ、と思って決めた。っていうかどこを探してもOPTIONSメソッドに対してはこのレスポンスコードを返すべき、的な情報がなかった。
rspecでroutingのテストもできた。
it "routes to #options" do expect(options: "http://api.example.com/v1/hoges").to route_to(action: "options", controller: "v1/hoges") expect(options: "http://api.example.com/v1/hoges/1").to route_to(action: "options", controller: "v1/hoges", id: "1") end
optionsで通るのね・・・。
最後にけっこうハマったのがこれ。
backbone.jsでfetch()でもsave()でもとにかくエラーハンドラが発火してしまう。
あと、別個で認証をどうにかしなきゃいけないけど、それはなんとなくヒミツ。
とりあえず、こんな感じでbackbone.jsからのリクエストがさばけるはず。