今さらなまとめです。
HTTPメソッド と RESTful(RESTful設計、RESTful Webサービス)
HTTPメソッド(概要)
- 「HTTPの仕様」では8つしかない(HTTP1.1)
HTTPメソッド(と PATCHメソッド)の具体例
GET
- リソースの取得
- 読み込み(READ from CRUD)
- べき等である
- 安全である
POST
- 子リソースの取得、リソースへのデータ追加、そのほかの処理
- 作成(CREATE from CRUD)
- べき等ではない
- 安全ではない
PUT
- リソースの更新、リソースの作成
- 更新(UPDATE from CRUD)
- べき等である
- 安全ではない
DELETE
- リソースの削除
- 削除(DELETE from CRUD)
- べき等である
- 安全ではない
HEAD
- リソースのヘッダ(メタデータ)の取得
OPTIONS
- リソースがサポートしているメソッドの取得
TRACE
- 自分宛にリクエストメッセージを返す試験(ループバック試験)
CONNECT
- プロキシ動作のトンネル接続への変更
PATCH
- リソースの更新
- 更新(UPDATE from CRUD)
- べき等ではない
- 安全ではない
- Rails の設計上、Rails 4 以降は更新を行うメソッドは PUT ではなく PATCH になった
主要5メソッドを表形式で見てみる
メソッド名 | 目的 | CRUD | べき等性 | 安全性 |
---|---|---|---|---|
GET | リソースの取得 | READ | べき等である | 安全である |
POST | 子リソースの取得、リソースへのデータ追加、そのほかの処理 | CREATE | べき等ではない | 安全ではない |
PUT | リソースの更新、リソースの作成 | UPDATE | べき等である | 安全ではない |
DELETE | リソースの削除 | DELETE | べき等である | 安全ではない |
PATCH | リソースの更新 | UPDATE | べき等ではない | 安全ではない |
POST メソッドで他のメソッドを代替する方法
特に GET と POST しか使えない Webブラウザ(の時代)での方法
1. X-HTTP-Method-Override を用いる方法
単純にリクエストヘッダに以下のように X-HTTP-Method-Override: PUT
などと含めるだけ。
POST /foobar HTTP/1.1 Host: foo.bar Content-Type: application/xml; charset=utf-8 X-HTTP-Method-Override: PUT <body>hogehoge</body>
2. form に _method パラメータ を用いる方法
POST メソッドで送るフォームの中に、以下の HTML を忍び込ませる。具体的な挙動は送信されるリクエストヘッダを見ると分かる。しかしこの方法はリクエストヘッダの特性上、Content-Type: application/x-www-form-urlencoded
がヘッダに含まれないと使えない。
<input type="hidden" id="_method" name="_method" value="PUT>
PATCHメソッドは「HTTPの仕様」ではない
- Wikipedia より
HTTPの仕様以外で定義しているメソッドは、IANAのHypertext Transfer Protocol (HTTP) Method Registry[4]で管理されている。WebDavで使用するものや、 RFC 5789 のPATCHメソッドなどがある。
「安全ではない」とはどういうことか
「操作対象のリソースを変化させない」ということ。
「べき等性」と「安全性」はメソッドで保証されるものではない
「べき等性」と「安全性」は、その HTTPメソッド を用いたときにそういう設計をするべき、ということであり、その HTTPメソッド を使えば必ずそうなるというものではない。
リソースの作成に POST を使うか PUT を使うか
原則として POST を使う方向で設計をする。
Webブラウザ実装状況
- (追記予定)
Ruby on Rails 5 のアクションにおける HTTPメソッド や RESTful
7つのアクション とその HTTPメソッド
- index
- GET
- show
- GET
- new
- GET
- edit
- GET
- create
- POST
- update
- PATCH (PUT)
- destroy
- DELETE
7つのアクションのコントローラ例(Scaffold による)
class FriendsController < ApplicationController # GET /friends # GET /friends.json def index @friends = Friend.all respond_to do |format| format.html # index.html.erb format.json { render json: @friends } end end # GET /friends/1 # GET /friends/1.json def show @friend = Friend.find(params[:id]) respond_to do |format| format.html # show.html.erb format.json { render json: @friend } end end # GET /friends/new # GET /friends/new.json def new @friend = Friend.new respond_to do |format| format.html # new.html.erb format.json { render json: @friend } end end # GET /friends/1/edit def edit @friend = Friend.find(params[:id]) end # POST /friends # POST /friends.json def create @friend = Friend.new(params[:friend]) respond_to do |format| if @friend.save format.html { redirect_to @friend, notice: 'Friend was successfully created.' } format.json { render json: @friend, status: :created, location: @friend } else format.html { render action: "new" } format.json { render json: @friend.errors, status: :unprocessable_entity } end end end # PUT /friends/1 # PUT /friends/1.json def update @friend = Friend.find(params[:id]) respond_to do |format| if @friend.update_attributes(params[:friend]) format.html { redirect_to @friend, notice: 'Friend was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @friend.errors, status: :unprocessable_entity } end end end # DELETE /friends/1 # DELETE /friends/1.json def destroy @friend = Friend.find(params[:id]) @friend.destroy respond_to do |format| format.html { redirect_to friends_url } format.json { head :no_content } end end end