前置き
RailsではRESTfulなインターフェースが基本です。
RESTfulの設計思想では、以下のように処理によってhttpのメソッドの使い分けをすることとされています。
- データを参照したいときは、GET
- データを新規登録したいときは、POST
- データを更新したいときは、PUT
- データを削除したいときは、DELETE
しかし、現状では、ブラウザはPUT、DELETEメソッドを実装していません。
つまり、現在のWeb環境では、純粋なRESTfulインターフェースを使うことはできないのです。
仕方ないので、Railsでは、
PUT/DELETEをしたいときは、httpのメソッド的にはPOSTを使いながらも、
これはPUTです、これはDELETEです、というフラグを合わせることで、
RESTfulっぽいインターフェースを実現しています。
これが擬似REST方式です。
このあたりはRailsのフレームワークが隠蔽してくれるので、
アプリのプログラマは普段はあまり意識する必要はありません。
ただし、先日、これを強く意識する必要に迫られることがあったので、メモ。
RailsアプリのクライアントがWebブラウザである場合は、何も意識する必要はありません。Web画面のsubmitボタンを押せば、それがPutなのか、Deleteなのか分かるように、Railsがhtmlを作ってくれているからです。大抵のRailsアプリのクライアントはWebブラウザですね。
そうではなくて、Railsアプリのクライアントを自作する場合が問題となります。
例えばどこか外部のWebAPI(Amazonの本屋のWebAPIとか)を利用する場合、そのサービスの使い方(インターフェース)を知る必要がありますよね?
その外部のWebAPIがRailsで作られたWebサービスなのであれば、RailsアプリのAPIを知らなければいけません。そのRailsアプリのAPIが擬似REST方式だとしたら、擬似RESTへのリクエストの投げ方を知らないといけないのです。
(Railsは基本、擬似RESTですが、Routingを自分で定義すれば擬似RESTでないAPIも自由に作れます。以下に説明するように、ブラウザ以外からGET/POST以外の擬似RESTを使うのは少し面倒なので、ブラウザ以外から利用することを主としたWebAPIで、PUT/DELETEを実装したいなら、無理して擬似RESTにしない方がいいと思います。)
Railsの擬似RESTにリクエストを投げる方法
前置きが長くなってしまった、、ここから本題です。
GET/POSTメソッドのリクエストを投げたいときは、そのままGET/POSTのhttpリクエストを投げればいいだけなので、省略します。以下、Railsの擬似RESTインターフェースに、PUT/DELETEメソッドのリクエストを投げる方法について説明します。
方法1:_methodパラメータを指定する。
clnt = HTTPClient.new
body = {
'param1'=>'hoge',
'_method'=>'put',
}
res = clnt.post(SERVER_URI, body)
方法2:X-Http-Method-Overrideを指定する。
req = Net::HTTP::Post.new(path, initheader = {'Content-Type' =>'application/json'})
res = Net::HTTP.new(HOST, PORT).start {|http|
req["X-Http-Method-Override"] = "put"
http.request(req)
}
Content-TypeにJsonを指定すると、なぜか方法1が使えなかった。
方法2ならいけました。