Memorandum.

備忘録をかねたアウトプットの場

「Web API: The Good Parts」読書メモ ~ その 2 ~

tl;dr

どうも私です。

前回に引き続き「Web API: The Good Parts」についてのアウトプットその 2 です。

2 章から具体的な「美しい設計」の方法について触れられていきます。

目次

Web API: The Good Parts

2 章 : エンドポイントの設計とリクエストの形式

用語

  • エンドポイント
    • API にアクセスするための URI の意
    • ※ リクエストメソッドは含まない

要点

API として公開する機能を設計する

設計のポイントは以下の通り。

公開した API がどのように使われるのか、そのユースケースをきちんと考える

その際に注意しなければならない点がある。

  • SQL 文をただ包んだだけの設計では決して使いやすい API とはならない
    • データごとの内部仕様やリレーションを理解していないと利用できない
    • 内部仕様やリレーションを外部公開することはセキュリティリスクとなる

API の設計は SQL を単純にラップしたではなく、
少し高い次元での機能を表現するように設計する。

API エンドポイントの基本的な設計

良い URI 設計における非常に重要な原則は以下の通り。

覚えやすく、どんな機能を持つ URI なのかがひと目でわかる

「覚えやすく」をさらに細かく言語化すると次のようになる。

  1. 短く入力しやすいURI
  2. 人間が読んで理解できる URI
  3. 大文字小文字が混在していない URI
  4. 改造しやすい (Hackable な) URI
  5. サーバ側のアーキテクチャが反映されていない URI
  6. ルールが統一された URI

1. 短く入力しやすいURI

  • 「短く入力しやすい」ことは「シンプルで覚えやすい」ことに繋がる

2. 人間が読んで理解できる URI

  • その URI を見れば何を目的とした API かある程度わかること
    • e.g. (bad) https://api.example.com/sv/u/
      • 「sv」も「u」も使用者にとっては意味がわからない
      • 短くを目指した結果、かえってわかりづらくなっている

そのためのには以下の 3 点に気を配る。

  1. むやみに省略形は使わない
    • 標準化されているものは例外 (e.g. 国コード)
  2. API での頻出英単語を利用する
    • 世界的な共通言語である英語を使うのが適切である
      • e.g. 製品 (products, productos, seihin)
    • 頻出英単語は共通認識があることが多い
      • e.g. 探すという意味を持つ「search」など
      • c.f. ProgrammableWeb
    • URL だけを見て意味を理解することの手助けとなる
  3. スペルミスをしないこと

3. 大文字小文字が混在していない URI

  • 基本はすべて小文字を使用する
    • 大文字小文字の混在は URI をわかりづらく、間違えやすくする
    • 標準的に選択されているのが「小文字」である

4. 改造しやすい (Hackable な) URI

  • Hackable とは?
    • URI を修正して別の URI にするのが容易であること
    • e.g. https://domain/v1/items/12345
      • 「12345」がアイテムの ID であると直感的に理解できる
      • 他のアイテムにアクセスする際は ID を変えると予測できる
  • 開発の際にいちいちドキュメントを参照するような作りは NG
    • 利用者の開発速度やストレスに影響が出る
    • ドキュメントの見落としによるバグが発生しやすくなる

5. サーバ側のアーキテクチャが反映されていない URI

6. ルールが統一された URI

HTTP メソッドとエンドポイント

URI とメソッドの関係は「操作するもの」と「操作方法」の関係である。

Web API では以下のメソッドを利用するケースが多い。

メソッド名 説明 備考
GET リソースの取得 原則、リソースの変更は発生しない
POST リソースの新規作成 -
PUT 既存リソースの更新 リソースを完全に上書きする
DELETE リソースの削除 -
PATCH リソースの一部更新 リソースの一部を変更する
HEAD リソースのメタ情報取得 -

1 つの URI エンドボイントに異なるメソッドでアクセスすることで、
リソースをどう扱う(取得、更新、削除、etc...)のかを分離して扱うことができる。

エンドポイント設計の注意点

注意点は以下の 4 つである。

  1. 複数形の名詞を利用する
  2. 利用する単語に気をつける
  3. スペースやエンコードを必要とする文字を使わない
  4. 単語をつなげる必要がある場合はハイフンを利用する

1. 複数形の名詞を利用する

  • HTTP の URI はリソースを表すものである
  • HTTP の メソッドは動詞を表すものである
  • その上でリソースの「集合」をどう操作するのかを表現する

2. 利用する単語に気をつける

  • 「探す」を例に挙げても 2 つの単語がある
    • search : 探す場所を目的語にとる
    • find : 探すものを目的語にとる
  • 迷った場合は他の類似の API を調べてみる

3. スペースやエンコードを必要とする文字を使わない

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

  • 単語をつなげる方法はいくつか存在する
    • チェインケース (ハイフンでつなぐ)
    • スネークケース (アンスコでつなぐ)
    • キャメルケース(単語の先頭を大文字としてつなぐ)
    • その他ケース (ドットでつなぐなど)
  • APIURI 設計について実は決定的なものはない
    • Google としてはハイフンを推奨している(SEO 的観点)
    • ある程度は好みで決めてしまっても良い
    • ケースの混在は避けること
  • もっともベターなのは...
    • 単語のつなぎ合わせを極力避けてパスとして区切ること

クエリパラメータとパスの使い分け

判断基準は以下の通り。

  1. 一意なリソースを表すのに必要な情報かどうか
  2. 省略可能かどうか

1 を満たす場合には「パス」に情報を入れる。
2 を満たす場合には「クエリパラメータ」に情報を入れる。

SSKDs と API デザイン

今までの検討はどちらかといえば LSUDs 向けである。

SSKDs 向けにおいても重要ではあるが、
エンドユーザにとってのユーザ体験がより重要になる。

ブログアプリのホーム画面を例に挙げる。
ホーム画面には以下の情報が表示されている。

  • 新着記事
  • 人気の記事
  • おすすめ記事
  • ユーザランキング様々な

今まで検討した内容で API を組み立てると、
情報ごとに 4 つの API を作成するかもしれない。

しかし、アプリ側からすると 1 つの画面を表示するだけで、
4 つの API をリクエストする必要があり、非効率である。
また、画面を表示するまでに時間がかかるかもしれない。

良いユーザ体験が損なわれる可能性がある。

そのため、必ずしも汎用的という観点から美しい必要はない。

LSUDs 向けの API であっても同様であり、
クライアントのユースケースを想像して設計する必要はある。

HATEOAS と REST LEVEL3 API

異なるアプローチの API 設計の提唱。

Martin Fowler 氏の「Richardson Maturity Model」という記事内で、
すばらしい REST API に至るまでを 3つのステップに分解して解説している。

martinfowler.com

  • REST LEVEL0 - HTTP を使っている
  • REST LEVEL1 - リソースの概念の導入
  • REST LEVEL2 - HTTPの動詞 (GET/POST/PUT/DELETEなど) の導入
  • REST LEVEL3 - HATEOAS の概念の導入

REST LEVEL3 に相当するのが「異なるアプローチ」である。

HATEOAS (Hypermedia as the Engine of Application State) とは、
API の返すデータの中に、次に行う行動、取得するデータ等の URL を含めることで、
そのデータを見れば次にどこにアクセスすれば良いのかわかるような設計。

www.ics.uci.edu

例えば、ユーザ一覧を返す API の場合、
ユーザごとのリソースを取得するための URL が含まれる。
また、現在のデータとの関連性を rel の中に含める。

{
  "userss": [
    {
      "name": "satou",
      "link": {
        "uri": "https://domain/v1/users/111",
        "rel": "users/detail"
      }
    },
    {
      "name": "suzuki",
      "link": {
        "uri": "https://domain/v1/users/222",
        "rel": "users/detail"
      }
    }
  ]
}

以下のようなメリットがある。

  • クライアントがエンドポイントをハードコードする必要がない
  • クライアントがあらかじめ URI を知る必要がない
    • URI の変更がしやすくなる
    • URI を Hackable なものにする必要がなくなる

しかし、採用するか否かは慎重な検討が必要である。

(2014年段階では) HATEOAS は人口に膾炙しているとは言い難いため、
クライアント側の実装をかえって難しくしてしまう可能性はある。

感想

今回のアウトプットではあえて記載していないのですが、
「検索とクエリパラメータの設計」周りの話はかなり勉強になりました。

また、ログイン周りのお話も同様ですので興味のある方は是非購入を(笑)

クエリパラメータとパスは油断するとイケてない設計になることが多いので、
考える上での基準点を明文化して知ることができたのは大きかったです。