『Web API デザインの鉄則』第3章 インタフェース設計

WEB+DB PRESS Vol.82

Web APIのインタフェースを定義する際に決めなければならない点は以下になります。

  • エンドポイントURI
  • HTTPメソッド
  • クエリパラメータ

エンドポイントURIの定義

ROA(Resource Oriented Architecture)におけるリソースは、URIを持つ必要があります。

エンドポイントURIとは、個々のリソースの所在を表すURIです。

前回に引き続き、本記事ではブログポストのリソースの扱いを題材にしていきます。
(オリジナルの記事ではメールのドメインリソースを題材としています)

すでに存在するリソースを返すエンドポイント

  • GETメソッドでアクセスできる
  • リソースの表現はapplication/json形式
  • /api/posts:複数のpostsリソースを取得(コレクションリソース)
  • /api/posts{/posts_id}:単一のpostsリソースを取得
  • /api/posts{/posts_id}/comments{/id}:ポストに関連するコメントを取得する(エントリリソース)

新しいリソースを作成するエンドポイント

  • POSTメソッドでアクセスできる
  • リソースの表現はapplication/json形式
  • /api/posts:新しいpostsリソースを作成

すでに存在するリソースを削除するエンドポイント

  • DELETEメソッドでアクセスできる
  • 削除が成功した場合は204 No Contentで応答する
  • /api/posts{/posts_id}:単一のpostsリソースを削除

HTTPメソッドの選び方

RESTにおいてよく用いられるHTTPメソッドは次の4つです。

  • GET(リソースの取得)
  • POST(リソースの作成)
  • PUT(リソースの更新)
  • DELETE(リソースの削除)

POSTを利用するケース

a. コレクションリソースに対して新規のエントリリソースを追加
b. 既存のリソースに対して状態を追加
c. オーバーロードPOST

aとbが一般的な利用方法です。

cのオーバーロードは、「ROAの用途では表現しきれないインターフェースを持つもの全般を表現するために用いる手法」です。具体的には、リソースの差分更新などに使用されます。

PUTを利用するケース

a. 既存のエントリリソースを更新
b. 新規のエントリリソースを(明示的に)追加

aは既存のリソースに対する差分更新ではなく置き換えだという点が重要です。PUTメソッドによる更新の際は、置き換えるべきリソースの完全な表現をリソースに含める必要があり、一部分だけを更新することはできません。完全な表現が含まれるからこそ、PUTメソッドの冪等性があるといえます。

差分更新については、PATCHという新しいHTTPメソッドがRFC5789で提案されており、Rails4でも採用されています。

コレクションとクエリパラメータ

コレクションリソースを取得する場合、エントリを何らかのリストとして表現する必要があります。こういったコレクションに対しては、取得件数や並び順、検索条件などを取得時に指定したいことがあります。

クエリパラメータが必要なケース

コレクションリソース全体を取得すると膨大な量になってしまうような場合には、ページネーションが必要となります。

ページネーションのためには、以下のようなクエリパラメータが必要です。

  • コレクション取得の開始位置(OFFSET)
  • コレクションの最大取得件数(LIMIT)
  • コレクションのソートフィールド(ORDER BY)
  • コレクションの並び順(ASC/DESC)

『リーダブルコード』第3章 誤解されない名前 読書メモ

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

鍵となる考え:名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する

filter()だと、選択するのか除外するのか分からない。選択するならselect()、除外するならexclude()とした方が分かりやすい。

限界値を含めるときは min と max を使う

このコードには、商品数が10の場合にもエラーとして処理してしまうというバグがある。
限界値を明確にするには、名前の前に max_ や min_ をつけたほうがよい。

範囲を指定するときは first と last を使う

これでは、[2, 3]が表示されるのか、[2, 3, 4]が表示されるのか分からない。
終端を範囲に含めるのであれば、lastを使ったほうが良い。

※この辺、英語のニュアンスの問題なので、非ネイティブには伝わりづらいような…。

包含/排他的範囲には begin と end を使う

10月16日に開催されたイベントを表示するなら、以下のようなコードになる。

ここで、PrintEventsInRange()の仮引数の名前のような、包含範囲を示すには、begin/endを使うのがよい。

真偽値の名前

以下の変数名は、パスワードをこれから読み取る必要があるのか、既に読み取り済みなのか分からない。

真偽値の変数名の頭には、is・has・can・shouldなどをつけて分かりやすくする。また、否定形を使うと分かりづらくなることがあるので注意。

ユーザの期待に合わせる

多くのプログラマは、get で始まるメソッドはメンバの値を返すだけの「軽量アクセサ」であるという規約に慣れ親しんでいる。

らしい(自分はあまり実感が無いが…)。

その他、C++標準ライブラリのlist.size()等、データ量によっては処理に非常に時間がかかるメソッドに、一見すると軽そうな名前がつけられていると、軽い気持ちで使ってしまい、結果として処理がものすごく遅くなったりする。

まとめ

最善の名前とは、誤解されない名前である。

『Web API デザインの鉄則』第2章 読書メモ

WEB+DB PRESS Vol.82

第1章で、「Web APIをリリースするまでに決めなければならないこと」として、以下の5項目が挙げられています。

  1. 認可(Authorization)方式の決定
  2. リソース設計
  3. インタフェース設計
  4. エラー表現
  5. ドキュメント

このうち、第2章では「リソース設計」を扱っています。

リソースの定義

Web+DB Pressの記事の方ではEメールを送信するためのドメインを例に挙げてリソース設計を行っていますが、本記事ではブログの「記事(post)」をリソースとして設計してみます。

シンプルなブログ記事に必要な項目は以下のようなものになります。

  • タイトル
  • 本文
  • 状態
  • 作成日
  • 更新日

これを表にすると以下のようになります。人間には読みやすいですが、この表を機械に読み取らせてバリデーションさせるのは難しい。

フィールド名 名称 データ型 詳細
title タイトル string 記事タイトル。255文字まで。
content 本文 string 記事本文。65535文字まで。
is_public 状態 boolean 記事の状態。下書き(false)・公開(true)のいずれか。デフォルトはfalse。
created 作成日 string 記事作成日。ISO 8601形式の時刻を表す文字列。
updated 更新日 string 記事更新日。ISO 8601形式の時刻を表す文字列。

postリソースの例は以下のようになります。

記事では、ここで、データを定義するためのフォーマットとしてJSON Schemaを使用しています。

公式サイトによると、JSON Schemaの特徴は以下のように紹介されています。

JSON Schema
describes your existing data format
clear, human- and machine-readable documentation
complete structural validation, useful for
automated testing
validating client-submitted data

JSON Schemaは、データのフォーマットを定義するための仕様で、人間にも機械にも読みやすい。自動テストやクライアントの送信した値のバリデーションに便利、とのこと。

読みやすさ・書きやすさに関しては、XMLよりはマシかな程度ですね。読みやすさに関しては、JSON Schemaを表形式に変換するツール等があれば改善されそうです。書きやすさに関しても、ymlで書いてJSONに変換すればだいぶマシになるかもしれません。

JSON Schemaの最大のご利益は、このフォーマット(リソースの仕様)をそのままバリデーション等に使えることです。例えばPHPでもJSON Schemaに基づくバリデーターはいくつか実装されており、最も人気があるのはjustinrainbow/json-schemaです。

※PHPでのJSON Schemaの利用法に関しては、こちらの記事が参考になります。

『Web API デザインの鉄則』第1章 読書メモ

WEB+DB PRESS Vol.82

第1特集の『Web API デザインの鉄則』が興味深い内容だったので、要約しておきます。

Web APIとは何か

  • HTTPないしはHTTPSプロトコルによって通信が行われる
  • 特定のHTTPメソッドを用いてアクセスできる
  • 特定のURIにおいて提供される
  • URIのクエリパラメータやHTTPリクエストボディに一貫した呼び出し方の決まりがある
  • HTTPレスポンスのヘッダやボディの表現方法に一定の決まりがある

なぜWeb APIを使うのか

  • HTTPやHTTPSといったポピュラーなネットワークプロトコル経由でデータをやりとりできる
  • インタフェースを制約することで、アプリケーション連携が壊れないように設計できる
  • 同期的にデータをやりとりできる

※Web APIのアーキテクチャスタイルにはREST、RPC、SOAPなどがあるが、この記事では主にREST、補足的にRPCを用いている。

RESTスタイルの特徴:ROA

※ROA(Resource Oriented Architecture)

ROAの4つの概念:

  • リソース
  • URI
  • 表現(Representation)
  • リンク

リソースとは、データとして表現できるもの。
ROAにおいては、リソースはURIで識別する。
また、リソースは様々な表現を取りうる。たとえば、同じデータでもHTML/XML/JSONなど様々なフォーマットで表現できる。
リソースとリソースを結ぶのがリンク。

ROAの4つの特徴

アドレス可能性(Addresability)
提供する情報がURIを通して表現できること。
ステートレス性(Stateless)
APIリクエストのためのHTTPリクエストがすべて分離・独立していること。
接続性(Connectability)
リソースが別のリソースとの関連を示すリンクをもちうること。
統一インタフェース(Uniform Interface)
リソースの操作がHTTPメソッドという共通したインターフェースを持つこと。

RPCスタイルの特徴

Remote Procedure Callの名前の通り、リモートホストの関数を呼び出すようなスタイル。
一般的なプログラミングの考え方をそのまま応用しやすい。

RESTにするかRPCにするか

RESTは設計時の制約が強い。さまざまな個所を異なる人が設計したとしても一定の一貫性を担保できる。
RPCは柔軟性が高く中央集権的。エンドポイントはL7で分散できない。

RESTが向いている場合

  • 公開APIなど、不特定多数のクライアントがAPIを用いる場合
  • 複数のエンジニアがAPIの設計をする場合
  • L7で分散したい場合

RPCが向いている場合

  • クライアントが社内に限定されていたり、SDKのような形で必ずラップされている場合
  • 限定されたエンジニアがAPIの設計をする場合

多くの場合、RESTを選択するべき。

RESTful APIをリリースするまでに決めなければならないこと

  1. 認可(Authorization)方式の決定
  2. リソース設計
  3. インタフェース設計
  4. エラー表現
  5. ドキュメント

内容的には、『Webを支える技術』を実装寄りにして、濃縮した感じ。

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)