バックエンド

Web API設計指針を考えた

MMM Corporation
shimo

こんにちは、下條です。

弊社ではWebサービスをSPA(シングルページアプリケーション)にすることが増えてきた。その場合にはサーバーサイドではWeb APIの提供が増えることになる。ただ、APIがサービスごとに違ったリクエスト・レスポンス形式になっているといろいろと勘違いが起きやすいので、ある程度設計指針を決めておくことにした。簡単にご紹介したい。

URL設計

  • リソースのCRUD操作については基本的にはRESTfulな設計とする。
    • 動詞ではなく名詞。
    • リソースを名詞で表す。
    • リソースの操作をHTTPメソッドで表す。

例:

目的 エンドポイント メソッド
ユーザ一覧取得 http://api.example.com/v1/users GET
ユーザ新規登録 http://api.example.com/v1/users POST
特定のユーザ情報取得 http://api.example.com/v1/users/:id GET
ユーザ情報更新 http://api.example.com/v1/users/:id PUT
ユーザ情報削除 http://api.example.com/v1/users/:id DELETE
  • 小文字のみを使用する。
  • 単語をつなげる必要がある場合はダッシュを利用する。
  • 単数形よりも複数形をつかう。なお、実装がRailsの場合でテーブルの複数形が誤っている場合には、URLは正しい複数形としてRails側を修正する。(APIに実装を反映させるべきではない。)
  • スペルミスをしない。
  • URLの階層は浅く保ち、複雑さはクエリパラメーターに押しこむ。
  • クエリパラメータ名は配列で複数渡すものについては複数形、一つだけ渡すものについては単数形とする。
  • ページングにはper_page、pageというパラメータ名を使用する。

と書いてきたが、ただし、RESTには必ずしもこだわらず、あくまで利用側の利便性を重要視した設計とする。
1つの作業を完結するために複数回のアクセスを必要とするようなAPIの設計はChatty APIと呼ばれる。これはネットワークのトラフィックを増加させ、クライアントの処理の手間を増やす。したがってAPIがどのように使われるかを想像し、少しでも利用しやすいAPI設計を心がけることが重要である。もちろん、想定外の使われ方をされることはあるのであるが。

RESTに適さないAPIについて

  • 例えば検索といった、リソース操作でないAPIの場合、名詞でなく動詞を使う。
    例: /search?first_name=masatsugu&last_name=shimojo

  • クエリが非常に複雑になってくると、GETメソッドではIEなどブラウザでのURL長制限に引っかかる可能性がある。したがって、そういった自体が予想される場合にはPOSTメソッドでの同じ機能のAPIも提供する。ブラウザからの確認をしやすくするためGETメソッドも残しておくとよいかもしれない。

Microsoft Internet Explorer では、URL (Uniform Resource Locator) に使用できる最大文字数は 2,083 文字です。また、Internet Explorer のパスに使用できる最大文字数は 2,048 文字です。この制限は、POST 要求と GET 要求両方の URL に適用されます。

出典:http://support2.microsoft.com/?id=208427

レスポンス

  • レスポンスデータフォーマットはJSONのみを原則とする。
  • データ名の単数形/複数形に気をつける。
  • 単語の連結にはキャメルケース(userIdなど)を用いる。JSON がベースとしている JavaScript の命名規約において、キャメルケースの利用がルール付けされているケースが多いため。
  • 日付データの形式にはRFC 3339を用いる。また、時差対応しやすくするため、UTCで返すことを原則とする。

例:2014-08-30T20:00:00Z

エラーの返し方

リソースが見つからない場合のレスポンス例(エラーではない場合と同じJSON形式にする。):

{
   "users": [],
   "status": 404,
   "message": "not found"
}

JSON内のstatusは基本的にはHTTPステータスコードに倣って以下とする。

  • 200番台:成功
  • 300番台:追加で処理が必要
  • 400番台:クライアントのリクエストに問題がある場合
  • 500番台:サーバに問題があった場合

どのようにエラーを返すかという話についてはWebAPIでエラーをどう表現すべき?15のサービスを調査してみたに既存の有名サービスのAPIサンプルが載っているが、この記事に記載されていないものとして、HTTPのステータスコードをどうするかというポイントもある。
結論としては、ドメインレベルのエラーについては、HTTPステータスコードは200とした上でJSONレスポンスで表現する。

HTTPステータスコードでエラーを表現するやり方も考えられるが、以下の理由により採用しないことにした。

  • HTTPステータスコードで表現できないアプリ的なエラーがあること。
  • サービスの運用する際にはHTTPのステータスコードを監視することがある。APIのエラーをHTTPステータスコードで表現した場合に運用者にとってのノイズになる可能性がある。要するにアプリケーションが正しくハンドリングしてレスポンスを返している場合は正常系としておいて本当に問題があった時だけ異常系のHTTPステータスコードにするという方針。

わりとちゃんとしてるサービスの運用をしている人達は全ての HTTP status code を監視して 50x が多く出たら何かの障害がある? 40x が出たらリンク先が切れてておかしいんじゃね?みたいな格闘を日々しています。もし、あなたが書いた JSON API のエラーコードを HTTP status code で表現した場合に運用者にとってのノイズになるかもしれません。ようするにアプリケーションが正しくハンドリングしてレスポンスを返している場合は正常系としておいて本当に問題があった時だけ異常系の status code にする!とかですね。

2014年に向けた JSON API の実装の方向性と X-JSON-Status 改め X-API-Status header のご提案から引用。

  • HTTPステータスコードでエラーを表現した方がRESTチックではあるが、HTTPベースのWebアプリでは、クライアント側からの入力データの不備などでもHTTPステータスコードは200を返した上でエラーの状態をHTMLの中に記載して返している。APIも同じ発想でもよいという考え方。

バージョニング

非互換問題は、SPAではあまり発生しない(サーバーサイドとクライアントサイドを同時に更新すればよい場合が多い)とはずだが、スマートフォンアプリなどの場合には大きな問題となり得る。

  • APIにはバージョンをつける。
  • vと整数のバージョン番号をURLにつける。
  • バージョンは整数。マイナーバージョンは作らない。

例) http://api.example.com/v1/users

API実装について

  • APIサーバでは、リクエストの型チェックを行う(特にJSONを受け取る場合)。これは誤った型でリクエストが渡ってきた場合に一見動いているように見えるという状況を防ぐためである。型チェックの方法については今度弊社前田がブログに掲載するかもしれない。

  • Railsの場合は、Rails APIを使用する。なお、メジャーなAPI用のgemとしてGrapeがあるが、RESTfulでないAPIを実装するとソースが汚くなりがちになるため使用しない。

参考資料

以下の書籍・サイトを参考にさせていただいた。

以上、参考になる部分があれば幸いです。

Web-APIを活用したビジネスアプリケーションやサービス開発をご検討の企業様は、是非MMMにご相談下さいませ!

AUTHOR
shimo
shimo
記事URLをコピーしました