APIの設計をメモ

coding

APIの設計についてのメモ。ざっくり書いていく。

良いAPIとは何か?

良いAPIとは何だろうか、と考える。

一言で言えば、「分かりやすいAPI」が良いAPIだと思う。

外部から見ても分かりやすい設計。内部の人間が見ても分かりやすい設計。美しい設計と言い換えてもいいかもしれない。

これに、セキュリティなどが乗っかってくる。

APIの登場人物

  • エンドポイント
  • レスポンスデータ

いかに、エンドポイントを考えて設計するか。直感的に分かりやすいURIが良いと思うし、無駄なエンドポイントや分かりづらいものは省くべき。

そして、どのようなレスポンスデータを返すか。

これも分かりやすい構造や扱いやすいデータが好まれると思う。APIを設計しなくても、APIを叩く側からすると分かりづらいレスポンスデータはそれだけでゲンナリしてしまうし、よろしくないと思う。

エンドポイントの考え方

以下ではエンドポイントの考え方についてメモしていく。

短く読みやすいURI

冗長なURIは避けるべきで、一目見て分かりやすい言葉をチョイスする。

https://api.example.com/123

よりも、

https://api.example.com/items/123

こちらの方が直感的に分かりやすい。これはアイテムページの詳細を取得するAPIなんだなと直感的に分かる。

なお、URIに一貫性を持たせたい。

https://api.example.com/items/123

というAPIなのに、ユーザー部分は

https://api.example.com/user/123

だと気持ち悪い。itemsは複数形なのに、ユーザーページではusersを使っていない。

エンドポイントにアクションを含めるか

何らかのアクションを起こすエンドポイントがあるとする。

例えば、ある商品情報を取得したり新規作成したり、削除したりする場合だ。

直感的に分かりやすいエンドポイントを心がけると以下のようになる。

https://api.example.com/items/get/123

https://api.example.com/items/post/123

https://api.example.com/items/delete/123

ただ、これは冗長であるし適切ではない。アクションはhttpメソッドに含めることができるので、メソッドで対応できるものは極力URIに含めないようにする。

https://api.example.com/items/123(GET)

https://api.example.com/items/123(POST)

https://api.example.com/items/123(DELETE)

レスポンスデータの考え方

以下ではレスポンスデータの考え方についてメモしていく。

レスポンスデータはキャメルケースで

PythonなんかでAPIを設計すると、レスポンスデータの値をスネークケースで書きたくなる。

これはこれで問題ないけど、キャメルケースで書きたい。

なぜなら、フロント側でゴニョゴニョする場合、JavaScriptはキャメルケースで書かれるから。

ちなみに、APIを叩くiOSアプリを作った場合、やっぱりこっちもキャメルケースで書くことにになる。

SwiftにはCodingKyesというものがあり、EncodeとDecodeでキー名が違う時に対応させる仕組みがある。

struct Post: Codable
  id: Int
  title: String
  publishedDate: Date

  enum CodingKeys: String, CodingKey {
  case id = "post_id"
  case title
  case publishedDate = "published_date"
}

しかし、そもそもレスポンスデータを最初からキャメルケースで設計しておけば、こういった手間がかからないのでキャメルケースで書く。

内部構造のネストはほどほどに

内部構造をネストしまくっているAPIを見かけることもあるが、分かりづらいなあと感じる。

自分が設計する時もネストし過ぎないよう、シンプルに書くことを心がけたい。

配列で返すか、オブジェクトで返すか

JSONでレスポンスデータを返す時、配列・オブジェクトどちらでも返すことができる。

配列で返す場合

[
  {
    "id": 123
    "name": "sand color tarp"
    "price": 5000 
  },
  {
    "id": 124
    "name": "tent"
    "price": 20000 
  },
]

オブジェクトで返す場合

{
  "items" [
    {
      "id": 123
      "name": "sand color tarp"
      "price": 5000 
    },
    略
  ]
}

一つの考え方として、エンドポイントにitemsを含む場合はオブジェクトを返さずに配列で返した方がスッキリする気がする。

https://api.example.com/items/123

エンドポイント単体で考えるなら、この考え方もあながち悪くないと思うが、レスポンスデータ単体で見ても明示的に何のデータか分かりやすくするためにはオブジェクトを含んだ状態で返すと分かりやすいように思う。

実際に多くのサービスでレスポンスデータはオブジェクトを返すように設計されているので、自分も習いたいと思う。

大量のデータを返さないようにする

https://api.example.com/users/

で、サービスに登録されている全ての商品やユーザーを返すようなAPIはどうだろう。

もっとイメージしやすく言うと、Twitterですべての登録されているユーザーを返すようなAPI設計をしていたらどうだろうか。

サービスが小さい時はデメリットを想像し辛いが、大きなサービスになるとすごいことになってしまうと容易に想像できる。

だから、最初からAPIの設計に一覧データを全て返さないような設計にする。

具体的にはクエリで指定された条件を返すようにする。

また、https://api.example.com/itemsのような一覧を返すエンドポイントはエラーで返すような設計にする。

続きがある一覧情報をどう返すか

APIを叩いて100件の結果が返ってきたとする。この情報は100件で終わるものなのか、200件で終わるものなのか。

こういった時に、101件を取得するように設計して返す情報に続きがある旨をnext: trueのような形で記載する。

プログラミング独学のおすすめ本

アメリカにて独学でプログラミングを学ぶ方法を紹介しているジョン・ソンメズ氏による翻訳本。

どのようにプログラミングを独学で勉強していくかのロードマップが詳しく記載されています。

ソフトウェア開発者のキャリアについても言及されているので、プログラミング初心者以外の人にもおすすめ。



カテゴリー