『Web API: The Good Parts』学習メモ

Ch01 what's Web API

  • Web API: HTTP protocolを利用してnetwork越しに呼び出すAPI
  • API: Application Protocol Interface
    • target: XML over HTTP, JSON over HTTP
    • developerにAPIを公開することで,サービスに付加価値がつく
    • eco systemに参加
    • ProgrammableWeb: API directory service
    • third party JSのためのAPI
  • APIのpattern
    • 使用例
  • APIで公開するもの
    • serviceのcoreの価値のある部分すべてを利用可能にする
    • riskについて.
      • 公開しなくてもriskはある.
    • 利用規約で問題行動への対応を表明
    • APIを小売向けのような形で公開する
  • Web APIを美しく設計する重要性
    • 使いやすさ,変更しやすさ,頑強さ,魅力
  • Web APIを美しくするには
    • 仕様が決まっているものは仕様に従う
    • 仕様がないものはdefacto standardに従う
  • RESTとWeb API
    • RESTの本来の意味に合っていない使われ方がされている
    • RESTの考えを適用する場面は多いが,すべてがRESTではない
  • target developerの数とAPIの設計思想
    • LSUDs(Large Set of Unknown Developers)とSSKDs(Small Set of Known Developers)
    • SSKDs向けは,RESTを基本にしたAPIでは不十分
      • → Orchestration layer
  • まとめ
    • [Good] Web APIが未公開なら,すぐ公開を検討
    • [Good] Web APIを美しく設計する
    • [Good] RESTという言葉にこだわり過ぎない

Ch02 endpointのdesignとrequestの形式

  • APIとして公開する機能をdesign
    • UCを考える
  • API endpointの考え方
    • endpoint: APIにアクセスするためのURI
    • 覚えやすく,どんな機能を持つURIか一目でわかる
      • 短く入力しやすい
      • 人間が読んで理解できる
        • ProgrammableWebで正しい英単語を確認
      • 大文字小文字が混在していない
      • 改造しやすい(Hackable)
      • server側のarchitectureが反映されていない
      • ruleが統一
  • HTTP methodとendpoint
    • URI: 操作するもの.method: 操作方法.
    • 1つのURIのendpointに異なるmethodでアクセス
      • resourceと扱いの分離 ← HTTPの本来の考え方に合致
    • POSTは指定したURIに従属,PUTはURIそのもの
    • PATCH: 一部のみ変更
    • GET, POSTしか使えないとき
      • X-HTTP-Method-Override
      • _method
        • Railsが使っている
      • X-HTTP-Method-Overrideの方が利用しやすい
        • 固有の形式となることや,メタ情報が増えてしまうため.
  • APIのendpoint design
    • Web APIの基本: あるデータの集合と個々のデータをendpointとして表現し,それに対してHTTPのmethodで操作を表す.
    • Foreigh keyをそのままidとして使うのが良い
    • resourceにaccessするためのendpoint designの注意点
      • 複数形の名詞を使う
      • 利用する単語に気を付ける
      • spaceやencodeを必要とする文字を使わない
      • 単語をつなげる必要がある場合はハイフン
        • 基本は,単語のつなぎ合わせではなく,パスで区切る/query parameterとする/なるべく短い表現にするのがよい
  • 検索とquery parameterのdesign
    • pagination: 取得数と取得位置を指定
      • per_page + page, or limit + offset
    • 相対位置の問題
    • → 絶対位置での取得
    • 絞り込みのためのparameter
      • qは部分一致〇
      • URIにSearchを入れるのは,検索という意味を強調するために有用である
      • 検索に主体があるserviceのAPIの場合
    • query parameterとpathの使い分け
      • 一意なresourceを表すために必要な情報で,省略不可能な場合はpath, そうでなければquery parameter.
  • loginとOAuth 2.0
    • 認証のAPIとして,Authが真っ先に検討できる標準仕様
    • 自社開発のClient Applicationにおいて,ユーザ名とパスワードをapplication内に入力して認証を行う場合
      • OAuthのGrant Typeのうち,Resource Owner Password Credentialsを使う
        • 扱い方
    • access tokenの有効期限と更新
    • other Grant Type
      • Client Credentials: User name, Password不要な認証.Clientの認証のみ行う.
    • 自分の情報へのalias
      • me, self
      • ほかのユーザの情報の処理とは,処理自体を分岐することでバグを防げる
  • hostnameとendpointの共通部分
  • SSKDsとAPI design
    • LSUDsに比べて,end userにとってのuser experienceがより重要になる.
    • 汎用的という点では美しくなくてもよいケースがある.
      • 1 screen 1 API call, 1 save 1 API call
  • HATEOASとREST LEVEL3 API
    • HATEOAS: Hypermedia As The Engine Of Application State
      • Hypermedia @ Web API: APIのresource
    • media typeで,アクセスしたデータがどんなデータか指示
    • merit
      • URIの変更が容易になる
      • Hackableでなくてもよくなる
    • SSKDs向けのAPIには〇.LSUDsにはまだ△.
    • Client, Serverともに自分で開発するようなsituationでは,検討できる
  • まとめ
    • [Good] 覚えやすく,どんな機能を持つか一目でわかるendpointにする
    • [Good] 適切なHTTP methodを利用する
    • [Good] 適切な英単語を利用.単複にも注意.
    • [Good] 認証はOAuth 2.0

Ch03 response dataの design

  • data format
    • APIが返す構造化データの表現. JSON, XMLなど.
      • JSONがdefault. XMLは必要があれば.
      • JSONの方がsimple, 同じデータを表すのにサイズが小さくて済む, JSとの相性〇
    • data formatの指定方法
      • query parameter ← 最も使われている
      • 拡張子
      • request header
  • JSONPの取り扱い
    • JSON with Padding
    • domainを超えたaccessのため
    • 作法
      • callback function nameのquery parameterでの指定
      • jQueryのe.g.
      • JSONPはJSなので,media typeはapplication/javascriptになる
    • error handling
      • 200を返し,response bodyでerrorの内容を示す
    • 不要ならJSONPは使わない
      • 同一生成元policyを回避してしまうため
  • dataの内部構造の考え方
    • response data: APIのアクセス回数がなるべく減るようにする
      • APIのUCを考える必要
      • Web APIは,DBのinterfaceではなくapplicationのinterface
      • × Chatty(おしゃべりな) API
    • すべてのAPIでできるだけ多くのデータを返す準備をしておき,利用者が取得する項目を選択する
      • response group
    • envelope: 冗長.HTTPがやっているため十分.
      • JSONPのときだけは使うと便利
    • 同じ構造なら階層構造,そうでなければできるだけflatにする.
    • response全体をObjectにして,中に配列を入れるのが〇
      • response dataが何を示しているかわかりやすい
      • response dataをObjectに統一できる
      • security
    • 配列の件数,続きがあるかどうかの取り方
      • 指定の件数+1件を取れているかどうかなどでよい.
      • HackableでないAPIでよければ,HATEOAS的な考えで,次のURIなどを返すのも〇
  • 各dataのformat
    • 名前
      • endpointのdesignと同じ.
      • JSONではcamel case ← JSと同じ
      • snake caseの場合もあり.snake caseの方が読みやすいらしい
      • 配列の場合は複数,それ以外は単数
    • 性別
      • genderで文字列
      • 生物学的な使い方ならsex
        • sexなら1/2もあり
    • 日付
      • RFC 3339形式が〇
      • SSKDs向けならUnix timestampも〇
      • HTTP日付はformatが異なる
    • 大きな整数とJSON
      • 大きな整数は文字列で返す
  • response dataのdesign
    • あるデータを返すときは同じ構造になるよう,それぞれのデータの構造を定義してしまうとsimpleで〇
  • errorの表現
    • proper status code
    • detail
      • bodyで〇.headerに入れるのも悪くはなさそう
      • detail code, detail information link
    • HTMLで返らないようにする
    • @maintenance
      • 503
      • Retry-After
    • 意図的に不正確な情報を返す
  • まとめ
    • [Good] JSON,あるいは目的に応じたdata formatを使用
    • [Good] dataを不要なenvelopeで包まない
    • [Good] responseをできる限りflatな構造にする
    • [Good] 各dataの名前が簡潔で理解しやすく,適切な単複が用いられている
    • [Good] errorのformatを統一し,Client側でerror detailを機械的に理解可能にする

Ch04 HTTPの仕様を最大限利用する

  • 意義
    • 不本意に独自仕様をいれてしまう危険性を下げる
    • HTTP protocolがenvelopeの役割という例
  • status codeを正しく使う
    • APIで使うcode一覧
    • 2xx: success
      • 204: No Contentは,是非あり
        • PUT, PATCHは,200とともに操作したデータを返す(POSTは201)
        • DELETEは204
    • 3xx: 追加で処理が必要
      • redirect: 301, 302, 303, 307
        • Locationを伴う
      • POSTによるデータ送信 → GETで別のページを表示のケースが多い
        • 302, 301はmethodの変更を許可
        • 308, 307は不許可
      • APIではできるだけredirectを避ける
      • 300: Multiple Choices
      • 304: Not Modified
    • 4xx: Clientのrequestに問題があった場合
      • 400: Bad Request
        • ほかのcodeでは表せない「その他」
      • 401: Unauthorized. Authentication(認証) error. ← 誰ですか?
      • 403: Forbidden. Authorization(認可) error. ← 許可がないよ.
      • ほかにも色々ある
    • 5xx: Serverに問題があった場合
  • cacheとHTTPの仕様
    • cacheのmerit. → 可能な限り利用するべき
    • proxy serverへの考慮必要
    • reverse proxy
    • Expiration Model
      • fresh ←→ stale
      • Expires
        • 特定の日時に更新されることがあらかじめわかっているdataに使う
      • Cache-Control
        • max-age
          • HTTP時間
            • RFC1123を使う
    • Validation Model
      • 条件付きrequest
        • Last-Modified, ETag (Entity Tag)
        • If-Modified-Since, If-None-Match
      • e.g. MurmurHash3
      • strong/weak Validation
        • weakなら,広告などの違いは無視できる
    • Heuristic Expiration(発見的期限切れ)
      • ClientがCacheの期限を自分で決める
    • Cache-Control: no-cache
    • VaryでCacheの単位を指定
      • Server Driven Content Negotiation
      • Accept-Encoding, User Agent, Accept-Language, Authorization, Cookie
    • Cache-Control header
      • stale-while-revalidate
        • asyncでcacheの検証をしている間はcacheを返してよい → 速度〇
      • stale-if-error
        • origin serverに接続できなかったときに,stale cacheを返してよい秒数
  • media typeの指定
    • media type: data format
    • Content-Type @response
      • MIME: Multipurpose Internet Mail Extensions
        • top level type name/ sub type name [; parameter]
          • top level type: text/image/video/applicationなど
          • sub type: 具体的なdata format
      • 前提知識なくても読めればtext, そうでなければapplication
    • 正しいmedia typeをContent-Typeで返す
    • x-で始まるmedia type
    • 自分でmedia typeを定義する
      • Registration treeで接頭辞が決まっている
        • vnd.を使うことが多い
    • JSONXMLを用いた新しいdata形式を定義する場合
      • 独自に別のHTTP headerを用意するのが折衷案として〇
    • media typeが正しくないと,security riskあり
    • media type @request
      • Content-Type
        • 複数dataのPOSTは,multipart/form-data
      • Accept
        • どんなmedia typeを受け入れ可能か
        • q: Quality Value. そのtypeの優先度.
        • → serverが配信するdata formatを決定: Server Driven Content Negotiation
        • ServerのresponseではVaryにAcceptを指定する必要
        • URIで形式を指定する方が手軽といえば手軽だが,HTTPの仕様に即しているのはAccept
  • 同一生成元policy(Same Origin Policy)とCross-Origin Resource Sharing
    • CORSはJSONPより安全で公式の仕様
    • ClientからOriginというrequest headerを送る
    • ServerはAccess-Control-Allow-Originというresponse headerを返す
    • pre flight request
    • Access-Control-Allow-Credentials
  • 独自のHTTP headerを定義する
    • 接頭辞: X-
    • X-は不要という論もある
  • まとめ
    • [Good] HTTPの仕様を最大限利用し,独自仕様の利用を最低限に止める
    • [Good] 適切なstatus codeを用いる
    • [Good] 適切な,なるべく一般的なmedia typeを返す
    • [Good] Clientが適切なcacheを行えるように情報を返す

Ch05 設計変更をしやすいWeb APIを作る

  • 設計変更のしやすさのimportance
    • 影響が分かりづらい
    • 外部/mobile/web serviceいずれの場合も問題あり
      • web service,自分のserviceで使っているAPIであれば,問題は小さいが,cacheの問題はある
  • APIをversionで管理する
    • 新しいAPIを別のendpoint, または別のparameterをつけたURIなど,新しいaccess形式で公開が〇
    • 方法①: URIにversionを埋め込む
      • 最も一般的でわかりやすく,おすすめ
      • vを付けた方が分かりやすい
      • semantic versioning
        • APIではmajor versionのみパスに含めるのが一般的
      • path以外での指定
        • query parameter
          • 省略可能
          • 冗長だったり,省略したときに分かりづらいので,パスの方が〇
        • media type
          • HTTPの文法に則っており,パスのようにpresentation levelの指定がURIに含まれずに済む
          • Client libraryの解釈で問題がある可能性あり
          • → 独自のHTTP headerを定義して指定する方法がある
  • versionを変えるときの指針
    • security, authorityにアップデートは,後方互換なしで〇
    • 以降のバージョンアップの影響を小さくするために実施する
    • 常に最新版を返すaliasは不要
  • APIの提供を終了する
    • 終了日時の周知
    • Blackout Test
    • 予め提供終了時の仕様を盛り込む
      • 強制アップデート,ユーザのOSの調査
    • 利用規約にサポート期限を明記
      • applicationの性質による
  • Orchestration layer
    • LSUDs: one-size-fits-all(OSFA)
    • OSFAではなく,それぞれのClientに対応するために,ServerとClientの間にOrchestration layerを挟むようにする.
  • まとめ
    • [Good] APIのversionの更新は最低限にとどめ,後方互換性にも注意
    • [Good] APIのversionはmajor versionをURIに含める
    • [Good] APIの提供終了時は,すぐ終了するのではなく最低6か月は公開を続ける

Ch06 堅牢なWeb APIを作る

  • 安全性と安定性
  • Web APIを安全にする
    • riskのe.g.
  • Server-Client間での情報の不正入手
    • risk
    • HTTPS by TLS
      • URIのpath, query 文字列, header, bodyを暗号化
        • ↑やり取りに使われるほぼすべての情報
      • HTTP Strict Transport Security(HSTS)により,HTTPSの強制〇
      • HTTPSでもriskあり
        • Man-In-The-Middle attack(MITM): 不正な証明書を使用 ← 証明書の検証で回避
        • Clientでも対応が必要
      • 速度の問題
    • 認証局への攻撃
      • Certificate and Public Key Pinningで回避
        • OWASPに実装方法あり
  • browserでアクセスするAPIの問題
    • browserは汎用的で機能が豊富
    • XSS
      • JSON injection: 特にJSONについては,必ずJSONとしてbrowserに判断させる必要がある
        • Content-Typeの指定
        • Content Snifferingへの対応
          • X-Content-Type-Options: nosniff
            • JSONでデータを返す際には必ずつける
          • 追加のrequest headerのチェック
            • X-Requested-With: XMLHttpRequest
            • 追加のpre flight requestが必要になってしまうので,明示が必要
          • JSON文字列のescape
    • XSRF: Cross Site Request Forgery
      • Forgery: 偽造,捏造
      • 回避方法
        • methodを正しく使う
        • XSRF tokenを使う
        • X-Request-With
    • JSON hijack
      • 回避方法
        • JSONをSCRIPT要素では読み込めないようにする
          • X-Requested-With
            • XMLHttpRequest, browser以外からのClientからのアクセスのみを想定の場合は,必ずやる
        • JSONをbrowserが必ずJSONと認識するようにする
          • 正しいmedia typeを返す
        • JSONJavaScriptとして解釈不能,または実行時にデータを読み込めないようにする
          • JSONの配列ではなくObjectを返すようにする
          • 無限ループを仕込む e.g. Facebook
    • browserからのアクセスを想定しないAPIでは,browserからのSCRIPT要素を使ったアクセスを防ぐのが〇
  • 悪意あるaccessへの対策
    • どんなデータがやり取りされているか知られても,不正を働けないようにしておく必要がある
    • parameterの改ざん
      • 本来accessできない情報はServerでcheck → access禁止
      • rate limit
      • Server側でデータの整合性をチェック
        • minusのチェックなど(アイテムやポイントの数などの不正操作を防ぐ)
    • requestの再送信
      • stateを管理
      • 支払いの偽装
        • Consumable/Non-Consumable
  • security関係のHTTP header
    • X-Content-Type-Options
      • JSONJSON以外として解釈することを防ぐ
      • JSONAPIを配信する場合は必須
    • X-XSS-Protection
      • browserのXSSへの防御機能の有効化
    • X-Frame-Options
      • dataがFrame内で読み込まれるのを阻止
    • Content-Security-Policy
      • default-src 'none'
    • Strict-Transport-Security
      • HSTSのためのheader
      • HTTPSのみに限定
    • Public-Key-Pins
      • HPKPのためのheader
      • SSL証明書が偽造されたものでないかcheck
    • Set-Cookie headerとsecurity
      • Secure, HttpOnly
    • 実例
  • 大量accessへの対策
    • userごとのaccessを制限 ← 最も現実的
    • rate limit: 単位時間あたりの最大access回数
    • 決めること
      • ユーザの識別要素
      • limit value
      • limit valueの単位
        • UseCaseの考慮
        • APIのgroupごとに設定など
        • 1時間単位くらいが多い
      • limitのreset
        • rolling window
    • access制限緩和
      • 特定のapplicationや開発者
      • 課金
    • 制限値を超えたときの対応
      • 429 Too Many Request
      • 429以外のstatus codeが使われていることも多い
    • rate limitをuserに伝える
      • document + API利用者向けのdashboard
      • HTTPのresponseのheaderでrate limitを渡す
        • X-RateLimit-Limit
        • X-Rate-Limit-Resetは,resetまでの秒数をデルタ秒で表すのが〇
    • rate limitの実装
      • 実際は,RedisのKVSなどを使って記録する
      • そのほか,API公開をサポートするサービスにも機能がある
  • まとめ
    • [Good] 個人情報など特定のuser以外に漏洩したくない情報がある場合はHTTPSを使う
    • [Good] XSS, XSRFなど通常のWebと同様のSecurityだけでなく,JSON hijackなどAPI特有の脆弱性にも配慮する
    • [Good] Security強化につながるHTTP headerをちゃんとつける
    • [Good] rate limitを設けることで一部のuserの過度なaccessによる負荷を防ぐ

Appendix

  • Web APIを公開する際にできること
    • API documentの提供
      • 常に最新にしておく
      • API Blueprint
        • document公開補助tools: RSpec Api Blueprint, iglo, API Mock, apiary
    • sandbox APIの提供
      • e.g. PayPal, Gengo
      • hostnameのみ変えているcaseが多い
    • API Console
      • browser上で実際にAPIを操作して試せるtool
      • e.g. Graph API Explorer
      • 生成補助tools: Apigee
    • SDKの提供
      • maintenance cost大
  • Web API check list