半空洞男女関係

思ったこととかプログラミングしてるときのメモとか色々かいてます。メールはidそのままgmail

Web API: The Good Partsを読んだ

仕事でWeb APIを作ることが多くなったので読んだ。体系的にまとまっていてよかった。ヘッダ周りなど曖昧だった部分が明確に説明されていて助かった。

ちょっとAPIの例が古かったような気もするけれど、今でも特に変わっていないように思う。キャッシュ周りはISUCONとかで役に立ちそうだなと思いながら読んでいた。

Web API: The Good Parts

Web API: The Good Parts

メモ

APIの設計

  • LSUDs(large set of unknown developers)
  • SSKDs(small set of known developers)

URIの設計

  • 開発者はドキュメントを読まない
    • 覚えやすく、どんな機能を持つURIなのかがひと目で分かるのがよい
    • 短く入力しやすいURIがよい(DRY)
    • Hackable
  • PUTとPATCH
    • PUTは全部上書き
    • PATCHは書き換えたい部分を送る
  • 単語をつなげるのは-か_か
    • アンダースコアは歴史的にタイプライターで河川をj引くためのものだから目的にそぐわない
    • なるほど…。

ページネーション

  • per_page/pageとlimit/offsetどちらがよいか
    • limit/offsetの方が柔軟だけどper_page/pageのほうがキャッシュが効く
    • 状況によりますね
  • TwitterAPImax_idを定めていて、そこから手前というページングができる
    • 絶対位置指定
    • YoutubeAPIpublishedBeforeというのがある

ドメイン

  • api.example.netとかにしたほうが良いのではないか
    • DNSレベルで分割できて管理がし易い
    • www.googleapis.com とかでも良いが、サービスのサブドメインの方が何にアクセスするかが明確で良い

スクリーンとAPI

  • 1スクリーン1APIコール、1セーブ1APIコール
    • なんどもAPI叩かないほうが早いし、整合性が取れて便利
    • SSKDs用のエンドポイントを作って、名前空間切っても良いのではという気もした
    • すごい雑だけど: /internal/screen/top

REST

  • アクセスしたデータがどんなデータなのかを知るためにメディアタイプがある
    • application/vnd.companyname.user.detail.v1+json とかメディアタイプが有るとおしゃれ
      • GitHubはこんな感じのことをしている
      • クライアントが微妙だとメディアタイプが application/json でないと動かないので、application/json にしておきましょうと書いてあったけど、それでいいのか、という気持ちもした

レスポンスデータの設計

  • ArrayでなくてObjectで返したほうが良い
    • JSとして抜き取られた場合にArrayだとvalidなJSコードになってしまうけど、ObjectだとinvalidなJSコードになる(Blockとして判断される)
  • タイムゾーン+00:00 がおすすめ
    • インターネットに提供しているサービスは全世界から使えるので、基本はタイムゾーンいじらない方が良い
  • APIは内部で持っているDBのテーブル構造をむき出しにするものではない
    • IDと返すだけではなくて、そのIDの情報を返してあげたほうが良いかもよ、など

エラー

  • メンテナンス時には、メンテナンス用のエラーコードとメッセージを返すだけでなく、Retry-After ヘッダを付けてあげると親切
  • エラーは配列で返して、できるだけ多くの情報を返してあげると親切

ステータスコード

  • PUTやPATCHの場合は200と共に操作した後のデータを返したほうが良い
    • わかる

キャッシュ

  • キャッシュが使える状態: fresh, キャッシュが期限切れ: stale
  • ExpiresCache-Control を同時に使うと、 Cache-Control が優先される
  • Cache-Controlmax-ageの計算にはDateヘッダを使っている
  • HTTPヘッダの日付にはRFC1123を使う
  • 条件付きリクエス
    • レスポンス: 最終更新日付(Last-Modified)か、ETag(ETag)
    • リクエスト: If-Modified-SinceIf-None-Match
    • データを取ってくることがそれなりのコストじゃないとあまりメリットがない
      • Hueristic Expiration(発見的期限切れ): クライアントがキャッシュの期限を判断する
  • Cache-Controlno-cache はキャッシュをしないのではなく、検証モデルを使って必ず検証してくれということ
    • 中継するプロキシサーバーとかにcacheしてほしくない場合は、 no-store (機密情報があるとか)
  • Vary でどのHTTPヘッダがCacheに影響するかを示すことができる
    • 例えば、Accept-Language で返す言語を変えているとか
  • RFC5861では、 stale-while-revalidatestate-if-error というディレクティブがある
    • staleなデータをキャッシュサーバが持っていた場合に、どうするかを指定できる
    • stale-while-revalidate: max-age で指定された秒数後もcacheを返して良い秒数
      • しばらく古いのを返すけど、その間に新しいcacheを取ってくる
    • stale-if-error: オリジンサーバーが死んだ場合に、どれくらいcacheを返していても良いか

メディアタイプ

  • text/xmlapplication/xml どちらを使うべきか
    • text/xmlXMLを知らないユーザー(casual user)が読んでも理解できる場合に使う
    • Web APIの場合はapplication/xml で良い
  • text/javascript は廃止されている
  • GitHubのrawなコードは、text/plain で配信されているので <script src=で読み込んでも使えない
  • 自分でメディアタイプをつくるときは、RFC 6838のRegistration treeにしたがう
    • application/vnd.companyname.awesomeformat と言った感じ。
    • Excel: application/vnd.ms-excel
    • 実際は難しいので、 application/json で返して、適当なヘッダに入れたい情報を詰め込む
  • Content-Typeはきちんと設定しないとセキュリティリスクになる

APIの運用

  • Netflixでは、サーバーの汎用的なAPIとクライアントの間に “Client Adapter Code” を挟んで、様々なデバイスに対応するAPIを作るようにしている
    • BFFっぽくもある

セキュリティ

  • HTTPSを使う
  • Content-Type をきちんと指定する。
    • Content Sniffering対策に X-Content-Type-Options: nosniffをつける
  • XSRF
    • formのPOSTリクエストは、CORSの影響を受けないので、XSRFトークンを入れる必要がある
  • JSONハイジャック
    • Content-Typeを指定する
    • ArrayではなくObjectで返す
    • XMLHTTPRequestの場合はヘッダにX-Request-Withを付けて、<script> からは読み込めないようにする
  • 支払いの偽装
    • レシートをちゃんとチェックする
  • X-Frame-Options: deny
    • iframeで読み込んでよいか
  • Content-Security-Policy
    • <img><script><link>の読み込み先として何処を許可するのか
  • Strict-Transport-Security
    • HSTSを実現するためのヘッダ
    • HTTPでアクセスしようとしても、このヘッダを受け取った以降はHTTPSで訪れるようにする
  • Set-Cookie
    • Secure(HTTPSのときのみやり取りする)
    • HttpOnly(JSでは使わない)

レートリミット

  • 429
  • ヘッダに残りのリミットを入れてあげると親切