Web apiを広く使ってもらうために
最近、会社でweb api(REST)を作ったのですが、HTTPメソッドを沢山使うようになりました。PUTとか、DELETEとか、PATCH、その他…。以前にjspとかで画面を作っているころ=GETとPOSTだけの時代から比べると、隔世の感がありますね…年をとりました…
一方で、書籍等では、『クライアントが、GET/POSTしか使えない環境であるときのために、POSTでも実行できる手段を提供すること』という下りもあり、PUTとかDELETEというメソッドの使用を強いるというのも宜しくないようです。
IBMの解説サイトのあるページでは、FirewallがPUT/DELETEなどを通過させないことがある、と述べています。なんと!
Spring MVCでの実現方法は?
どうやら2種類あるようです。
- formにhiddenの項目(_method)を作り、methodを指定する
- HTTPヘッダにx-http-method-overrideを設定する
1番の方法では、HiddenHttpMethodFilterという実装を使うことが知られています。このクラスはフィルターとして動作し、HttpServletRequestに格納されたHTTPメソッド名を差し替える働きがあるようです。
今回は紹介する方法は、2番の方法になります。理由は、今回のAPIでは、formデータ(application/x-www-form-urlencoded)ではなく、JSONデータ(application/json)を送信するためです。
#json={"xxxx":"yyyy"}などのように、formデータとしてJSONを送信することも可能だとは思いますが、今回はストレートにJSONです。
[追記-2017/02/15] bodyでは無くても、urlの末尾に_methodを付けても動作するよ!(=Content-Typeは自由だよ)とのご指摘を頂きました。そうですね!今回はURL末尾につける"_command"のような書式を、オプション的な位置付けの独自コマンドに温存したいこともあり、HTTPメソッドのoverrideをヘッダで指定する方式を選択しました。
X-HTTP-Method-Overrideを使う
調べてやってみると、意外にシンプルでした。Spring MVCのRequestMapping機能は、もともとHTTPヘッダの値を使ってマッピングを絞り込むことができたのでした。
ですので、POSTメソッドをマップするcontrollerのメソッドのRequestMapping定義に、headers=を加えれば良かったのでした。
下記が実際に動作したソースのサンプルです。
@RequestMapping(value = "/method/{param}",method = RequestMethod.POST,
headers={"X-HTTP-Method-Override=DELETE"})
public ResponseEntity<?> delete2(
@PathVariable String param,
){
// 本来のdeleteメソッド
return this.delete(param);
}
POSTかつheadersで絞り込んでリクエストを受け、本来の処理に流せば完了です。
参考資料はこちら
(おわり)