WebAPI
読書
まとめ
技術書

今さらだけど「Web API: The Good Parts」 を読んだので自分なりにまとめてみる

More than 1 year has passed since last update.

今さらですが、「Web API: The Good Parts」を読みました。

せっかくなので自分なりにまとめてみます。


1. URLについて


  • 短く入力しやすいURL

      ×:http://sample.com/search-api/service/api/search

      ○:http://sample.com/api/search



  • 人間が読んで理解できるURL

     ×:http://sample.com/api/u

     ○:http://sample.com/api/user

      略すのもだめ products -> prod



  • 大文字小文字が混在していないURL

      ×:http://sample.com/api/getUserInfo

      ○:http://sample.com/api/user

      基本はすべて小文字



  • 改造しやすい(Hackable)なURL

      ×:http://sample.com/api/item/a/12345

      ×:http://sample.com/api/item/b/67890

      ○:http://sample.com/api/item/12345

      ○:http://sample.com/api/item/67890 


  • サーバ側のアーキテクチャが反映されていないURL

      ×:http://sample.com/cgi-bin/get_user.php?user=100

      ○:http://sample.com/api/user?id=100



  • ルールが統一されたURL

      userはidを指定するのに、itemはクエリを使うなどの不統一はだめ



2. HTTPメソッドについて


  • GET

    リソースの取得

  • POST

    リソースの新規登録

  • PUT

    既存リソースの更新

  • DELETE

    リソースの削除


  • PATCH

    リソースの一部変更



  • HEAD

    リソースのメタ情報の取得

    ※ 基本的には、GET/POST/PUT/DELETEの4つをサポートする

    GET,POSTしか使えない場合

    リクエストヘッダX-HTTP-Method-Overrideを使う

    POST /X/XX HTTP/1.1
    
    Host XXX.com
    X-HTTP-Method-Override: DELETE



3. ネーミング選定指針について


  • 複数形の名詞を利用する

      複数だとわかりにくい単語は単数形にしてもよい



  • 極力動詞は使用しない


  • 利用する単語に気を付ける

      迷ったらProgrammableWebというサイトなどで探す


  • スペースやエンコーディングを必要とする文字を使わない



  • 単語をつなげる必要がある場合はハイフンを利用する

      URIのドメイン名のルールと合っているため


4. エンドポイント設計について


  • ひとつの画面を表示するためにコールするのが1つのAPIで済むようにする


  • なんらかのデータをサーバに保存する場合にも1回のコールで済むようにAPIを用意する



5. レスポンスデータの設計について


  • データフォーマットはJSONをデフォルトとし、必要がある場合のみXMLに対応する



  • 様々なユースケースを考慮し、一度に返すデータはなるべく詳細にする

    例)ユーザ情報を返す

    ID、名前、写真、住所など



  • ただし、データが大きすぎる場合、クライアント側で選択できるようにする

    例えば、パラメータにsmall, medium, largeをつけると取得する項目を変えるようにする


  • 不要な階層化はせず、なるべくフラットにする



  • もちろん階層化したほうが良い場合もある

    例えば、メッセージの送信者と受信者があり、その下にユーザデータをつける場合など

    sender_id:12345,
    
    sender_name:aaaaa,
    receiver_id:67890,
    receiver_name:bbbbb

    sender: {
    id:12345,
    name:aaaaa
    },
    receiver:{
    id:67890,
    name:bbbbb
    }




  • JSONのトップレベルを配列にしない

    JSONインジェクションという脆弱性に対するリスクが大きくなる

    ※ JSONインジェクション

    → ScriptタグでJSONを読み込む手法。トップレベルが配列だと、JavaScript構文エラーにならずに、データが取得できてしまう。



  • 日付のフォーマット

    RFC3339を推奨

    → インターネット上で用いる標準形式として決められたもののため

    例)2015-10-12T11:30:22+09:00


  • 巨大な数字は文字列にして返す

    18桁などの整数は、JavaScriptが64bit浮動小数として扱うため誤差がでる



  • エラーの表現


    • 適切なステータスコードを返すこと

      エラーメッセージを返していてもステータスコードが200だとクライアント側に負担をかけることになる

    • エラーの際にHTMLが返らないようにする


    • メンテナンスなどでサービスを止める場合


      • ステータスコードは503を返す


      • HTTPヘッダのRetry-Afterを使って、メンテナンスが終わる時刻を返す







6. HTTPの仕様について


  • ステータスコード


    • 100番台

      情報

    • 200番台

      成功

    • 300番台

      リダイレクト


    • 400番台

      クライアントサイドに起因するエラー

    • 500番台

      サーバサイドに起因するエラー





  • データ更新時のベストプラクティス


    • PUTやPATCHは200(OK)とともに操作したデータを返却

    • DELETEは204(No Contents)を返す





  • クライアントエラーについて


    • 401(Unauthorized)は認証エラー

    • 403(Forbidden)は認可エラー

      認証とは、「アクセスしてきたのが誰であるのかを識別すること」

      認可とは、「特定のユーザに対してある操作の権限を許可すること」

      → つまり、401は「あなたが誰だかわからないよ」、403は「あなたが誰だかはわかったけど、この操作はあなたには許可されていないよ」





  • サーバエラーについて

    500(Internal Server Error)はログをきちんと監視して、管理者に通知が行くように設定しておくこと


  • クロスドメイン問題について

    CORSの利用


  • 独自HTTPヘッダの定義について


    • 「X-」という接頭辞をつける


    • その後はサービス・アプリ名や組織名、そしてハイフンを挟んでIDを付ける

      例)X-abc-original-id





7. バージョンについて


  • APIのバージョン

    URIにバージョン情報を含める方法が最もよく利用されている

    例)http://api.abc.co.jp/v2/users/


  • モバイルアプリのアップデートについて

    アプリ起動時に、現在のバージョンとサーバ側で配信するサポートバージョンを比較し、利用者にアップデートを案内する仕組みを仕込んでおく


8. セキュリティについて


  • セッションハイジャック対策


    • HTTPSにする





  • XSS(クロスサイトスクリプティング)対策



    • 以下のレスポンスヘッダを使用する(JSONインジェクション対策にも有効)

      X-Content-Type-Options: nosniff     
      


    • JSON文字列のエスケープを行う(SCRIPTタグを無効にする)





  • XSRF(クロスサイトリクエストフォージェリ)対策


    • サーバのデータ更新を行うようなアクセスに関しては、GETメソッドを利用せずPOST, PUT, DELETEを用いること


    • 正規のフォームにワンタイムトークン(少なくともセッションごとにユニークなトークン)を埋め込んでおき、そのトークンのないアクセスは拒否する





  • JSONインジェクション対策



    • メディアタイプをクライアントに返す

      Content-Type: application/json
      


    • JSONデータのトップレベルを配列にしない。必ずオブジェクトにする





9. 大量アクセス対策


  • ユーザごとにアクセス制限する


    • 何を使ってユーザを識別するか

    • リミット値をいくつにするか

    • どういう単位でリミット値を設定するか

    • リミットのリセットをどういうタイミングで行うか


      • たとえば1分間に60回をアクセスの上限とした場合、1分間の間に61回アクセスがあった場合はエラーを返し、また1分が経過したらアクセスができるようになる、といった具合


      • 一般的には1時間が多い






  • 制限値を超えた場合の対応


    • 429 Too Many Requests を返すべき

    • エラーの詳細をレスポンスに含めるべき

    • Retry-Afterヘッダを使って次のリクエストまでの待ち時間を指定してもよい




  • レスポンスにレートリミットを含める場合

    以下はヘッダに格納する場合のデファクトスタンダード


    • X-RateLimit-Limit

      単位時間あたりのアクセス上限

    • X-RateLimit-Remaining

      アクセスできる残り回数

    • X-RateLimit-Reset

      アクセス数がリセットされるタイミング