API設計においてURLの最大長問題を回避する方法3つ
イルカ21号です。
たとえばRESTfulなサーバAPIを作るときに、複数のリソースをいっぺんに取得するようなAPIをHTTP GETメソッドを使って作ることがあるかと思います。
そういうとき、1度のHTTPリクエストですべてのリソースが取得できることがパフォーマンス上望ましいですよね。
また、複数のリソースのソートを行うケースなども想定すると、10000個を超えるようなリソースのIDを指定してHTTPコールを行いたいケースが出てきます。
そういうときに問題となるのが
「URL(クエリストリング)は何文字まで使っていいのか」
という問題。
たとえば特定の名前がついた犬の情報を取得するAPIを考えてみます。
[URL] GET http://example.com/api/v1/dogs?name=takashi,taro,yuta,john
この長さなら問題はありませんが、これが名前が10000個を超えるようなケースがあった場合、URLが30000文字を超えてしまうことも考えられます。
ブラウザやHTTPサーバの実装にはよりますが、一般に2000文字を超えるURLはサポートされない可能性があるというデファクトスタンダードがあるようです。
そういったリクエストとして送った場合、サーバに414 (Request-URI Too Long) というエラーを返されてもおかしくありません。
*1
もちろんサーバの実装を変更してURLの最大長の制限を取っ払ってしまうこともできるでしょうが、
ブラウザから確認ができなくなったりすることを考えると、テスト性も下がってしまうので避けたいところです。
こういったとき、どのような対策が考えられるでしょうか。
これまで3つほど例を見てきたので、それぞれ紹介したいと思います。
1. POSTメソッドを利用する
クエリストリングに入れる予定だった文字列を、リクエストボディに詰め込んでPOSTメソッドでコールします。
[URL] POST http://example.com/api/v1/getDogs [request body] {"name" : ["takashi", "taro", "yuta", "john"] }
API pathは完全にREST思想から外れたものになってしまいますが、
やはりHTTPで何かしら大きなデータを送るときはPOSTメソッドとともにリクエストボディを利用すべきというのも事実です。
また、RESTは思想であってプロトコル、規約ではないので守ることは必須ではありません。
ここは割り切ってPOSTに頼ってしまうという方法です。
2. HTTP ヘッダを利用する
長すぎるURLがだめなら長すぎるヘッダを送ればいいじゃない、ということで、
リクエストに当たる情報をHTTPヘッダに詰めるという案です。
[URL] GET http://example.com/api/v1/dogs [HTTP header] X-DOG-NAMES: takashi,taro,yuta,john
しかしよく使われるHTTPサーバではヘッダの最大長も8Kbytesに設定されていることが多いので、これでも長さには十分気をつける必要があります。
また、API仕様がやや複雑で説明が面倒にもなるので、注意が必要です。
しかし「2KByteでは足りないけど8KByteなら足りる」くらいのデータを送りたいときは、便利かもしれません。
3. クエリストリングを圧縮してBase64で表現する
クエリ文字列が長すぎて困っているならクエリストリングを圧縮して、
最大長に当たらないようにしてしまえばいいじゃない、という方法です。
クエリ文字列をZIPなどで圧縮してからBase64エンコードで文字列表現します。
[URL] GET http://example.com/api/v1/dogs?name=eNrtjEEKwCAMBD+UT61UiAZcUEPp7xvtsbeee9lsJmEqtclEZ4RhaInZosnAfJhuan4ioUNAW9tBQfFMUVz7gebrmrLUX/lS2kflDVGZnEw=
しかしAPI仕様も実装も厄介になりますし、圧縮した後のクエリストリングが何文字になるか予測できないのでバグの元にもなります。
どうしてもURLだけで表現しきらねばいけない制約があるときに限って使用することをおすすめします。
まとめ
いかがでしょうか?
下記の理由から、個人的にはやはり 1. POSTメソッドを使用する が一番おすすめですね…。
- API仕様が理解しやすい
- APIを使用しやすい
- 最大で100kbyteを超えるような場合でも問題なくリクエストできる
- 「getDogs Requestというリソースを新たに発行する」という解釈をすればRESTfulであると言えなくもない
みなさんもサーバAPI設計の際の参考にしてみてください。
では!
*1:http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
*2:http://stackoverflow.com/questions/4203686/how-can-i-deal-with-http-get-query-string-length-limitations-and-still-want-to-b
*3: http://stackoverflow.com/questions/686217/maximum-on-http-header-values