Web APIについて調べてみた -3章編-

##背景
Web APIはリクエストを投げるだけで終わらない。
リクエストを投げるまでの設計は2章までの話で、返ってきたレスポンスデータの設計も考えなければならない。
レスポンスデータってどうやって設計するのか知らないので、美しいレスポンスデータの設計方法について知りにきた。

###読んだ本
O'Reillyの本を読んでみた
[WEB API The Good Parts](https://honto.jp/netstore/pd-book_26352551.html)

###章立て
前回のはこちら
[Web APIについて調べてみた -2章編-](https://qiita.com/danbo_lobo/items/7d89f80246d9d183931c)
今回は3章についてまとめてみた。
メモ程度の記述なので悪しからず。

##データフォーマットを考える
APIが返すデータをどのような表現方法で返すかを考える必要がある。
具体的には、**JSON**や**XML**などのフォーマットがある。
どっちを使うのか？というと、別に悩む必要もなく、JSONにデフォルトとして対応し、需要や必要があればXMLを使えば良い。
JSONの方が普及した理由として、以下がある。
>・シンプルで同じデータを表すのにサイズが小さくて済むこと
・Javasciriptとの相性がよかったこと

###JSON以外で返す方法
こうして、JSONがほぼスタンダードとして使われていっているが、どうしてもJSON以外で返したいという場合だって勿論ある。
そういう時どうしたらいいのかというと、以下3つの手段がある。
>・クエリパラメータを使う方法
　クエリパラメータを用意して、そこにJSONやXMLといったデータ形式を指定する方法。最もよく使われる。
・拡張子を使う方法
　ファイルに拡張子を付けるのと同様に、URIの最後に拡張子を付けること
・リクエストヘッダでメディアタイプを指定する方法
　リクエストヘッダを付けてデータ形式を指定する方法だが、あまり使われない。

###JSONPの取り扱い
JSONのブラウザを渡す方法の1つに、**JSONP**というものがある。
JSONPとは、「JSON with padding」の略で、通常はJSONをJavascriptでくるんだものを指すらしいです。
書き方のイメージは[あと味](https://taiju.hatenablog.com/entry/20090902/1251851867)が分かりやすかったので、参考にすると良い。
実際に実装するとなった時は、[JSONPをごりごり実装するときのポイント](https://qiita.com/stkdev/items/f3e6cae58ab73faee502)を参照すると良い。。

####JSONPとエラー処理
JSONPの問題として、サーバがエラーを返した際に、正しく対応できない！という問題がある。
scriptコードはエラーのステータスコード(400)などが返ると、スクリプトを読み込むのをやめてしまうからだ。
要するに、エラーコードの400番代と500番代が出ると、クライアント側では何が起きているのか分からなくなってしまう。
よって、JSONPを使う時は**200番代のステータスコードを返すようにする**のが望ましい。
最後に筆者は何でもかんでもJSONPに対応する必要はないと述べている。

###データの内部構造の考え方
利用するデータのフォーマットが決まれば、次にそのフォーマットを使ってどんなデータを返すか決めていく作業に入る。
1つの作業をするのに複数のAPIが必要になるようなAPIの設計は「Chatty API(おしゃべりなAPI)」と呼ばれ、あまり好ましくありません。
APIを設計する時は、少しでも利用しやすく少ない回数で済むAPI設計にすると良い。

####レスポンス内容をユーザーが選べるようにする
取得する項目を利用者が選べるようにするというものが、よく用いられる。
例えばクエリパラメータを使って、ユーザー情報のうち名前と年齢を取得したい、といったことを指定することが可能になる。
また、ユーザー情報の種類を選ぶ方法として、各項目名を直接指定する方法の他に、予めいくつかの取得する項目の量を異なるセットを用意しておいて、その名前を指定させるという方法がある。
例としてAmazonのProduct Advertising APIが挙げられており、そうしたセットのことを**「レスポンスグループ」**と呼ぶ。

####エンベロープは必要？
データの全体構造を考える節に移った。ここではエンベロープの必要性について解かれている。
#####エンベロープって何？
そもそもエンベロープとは何なのか。本文では以下のようにある。
>日本語で「封筒」を意味し、APIのデータ構造の文脈で言えば、全てのデータ（レスポンスやリクエスト）を同じ構造でくるむこと

実際に今までの章を参考に、図式化したものが以下になる。
![エンベロープ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430110/ece3229d-1109-d363-4ffb-e9453e2ecaf2.png)
また、コードとして記載した例は以下になる。

```bash:enverope例
{
 "header" : "success" ,
 "errorCode" : 0 ,
},
"response" : {
  ...実際のデータ...
  }
}
```

こうしたエンベロープの記述は、例こそあれど、実際は**使用しない方がよい**と記載されている。
というのも、Web APIは基本的にHTTPを利用しており、HTTPがエンベロープの役割を果たしているからだそうだ。
エンベロープを実際に使う場合は、JSONPを利用している時だった。

####データの表記方法はフラットにするべきか？
JSONもXMLも階層構造を持っており、階層構造を用いて記述することもできる。
しかし、結論からいうと階層構造をできる限り持たずに**フラットに**書くのが望ましいとしている。
[GoogleのJavaScriptスタイルガイド](https://google.github.io/styleguide/jsguide.html)にもそういう記述があるらしい。

####配列の利用
今まで例として挙げてきたSNSの開発において、タイムラインや友人一覧などAPIで配列を返したいケースが出てきたとする。
そうした時、JSONオブジェクトでは順序が考慮されません。じゃあどうするのか。
ここでは、JSONの配列仕様を利用すると良いとしている。
また、APIのレスポンスとしては２種類方法がある。
>①配列をそのまま返す方法
②レスポンス全体をオブジェクトにして、その中に配列を入れる方法

筆者は、どちらを選んでもいいができる限りオブジェクトにして、その中に配列を入れる方法をとった方が安全じゃないかなーって話していた。

####データのフォーマット
各データ項目の名前について考える節となっている。
名前を考えていく上でのポイントを以下引用する。
>・多くのAPIで同じ意味に利用されている一般的な単語を用いる
・なるべく少ない単語数で表現する
・複数の単語を連結する場合、その連結方法はAPI全体を通して統一する
・変な省略形は極力利用しない
・単数形/複数形に注意する

こうしたポイントを意識する他、[ProgrammableWeb](https://www.programmableweb.com/)を参照しつつ、APIを調べ参考にすると良いとしている。

#####どうしても複数の単語を連結する場合は？
スネークケース/キャメルケース/スパイナルケースと呼ばれる方法のどれかを使うのが一般的とされる。
（突然また新しい単語が出てきて内心戸惑った）
それぞれのケースについては[分かりそうで分からないシリーズ](https://wa3.i-3-i.info/word1180.html)を参照すると分かりやすいのでおすすめ。
一般に使用されているサービスでは、どの方法を使っているのかをまとめたのが以下表になる。

|サービス|連結方法|
|---|---|
|Twitter|スネークケース|
|Facebook|スネークケース|
|Youtube|キャメルケース|
|Instagram|スネークケース|

また、実際に変換する場合の手順は[正規表現でスネークケース↔キャメルケース/パスカルケースの変換](https://qiita.com/ryo0301/items/7c7b3571d71b934af3f8)を参照すると分かりやすくて良い。

スネークケースよりもキャメルケースの方が読みやすい、という研究結果も出ているらしいが、どちらを使うべきかはなかなか難しい問題だって著者も述べていた。

####大きな整数の表し方
巨大な数字を扱う時、気をつけなければならないことがある。
それは、コンピュータ自体にも限度があるということだ。
コンピュータにおける表現可能な数値は、普通2進数で表し、ビット長は８ビット/32ビットなどで固定される。
こうしてビットが固定されると自ずと限度数が見えてくる。
もし、IDなど巨大な数値を扱わなければならなくなったら、数値をそのままJSONとして返すと問題が生じるので、
IDは`id`や`id_str`など同じ数値を文字列として格納したものを返すと良い。

##いざ、レスポンスデータの設計へ
漸く、、、レスポンスデータの設計に入る。
まず、エラーの表現について考える必要があると述べている。
###エラーの表現
エラーとなった時に「エラーが発生しました」と返すだけでは不親切なので、何が起きてどう対応すれば良いのかわかるように表示させてあげる必要がある。
そこで登場するのが、エラーのステータスコードである。

|ステータスコード|意味|
|---|---|
|100番台|情報|
|200番台|成功|
|300番台|リダイレクト|
|400番台|クライアント再度に起因するエラー|
|500番台|サーバサイドに起因するエラー|

上記の大まかな区分けからさらに詳細を知りたい場合は、[HTTPレスポンスステータスコード](https://developer.mozilla.org/ja/docs/Web/HTTP/Status)を参照すると良い。

こうしたエラーコードだけをレスポンスとして返せばいいのかというと、それではダメで、きちんとエラー詳細をクライアントに返す必要がある。
このエラー詳細を返す方法は２種類あって、以下にまとめる。
>①HTTPのレスポンスヘッダに入れて返す方法
②レスポンスボディに返す方法

詳細は個人ブログ[エラーの詳細をクライアントに返す方法](https://lhiroki1205.hatenablog.com/entry/2020/11/14/150709)にも記載されていたので、こちらも参照するべし。

###メンテナンスとステータスコード
APIを停止しなければならない、という状況は極力避けるべきだと、本文に述べられている。
仮にAPIが停止すれば、そのAPIを利用しているクライアントのアプリやサービスはすべて動作しなくなるか、或いは動作の一部が制限されてしまうからだ。
どうしてもメンテナンスしなければならない場合は、`503`を返すようにし、現在サービスが停止していることを伝えるのが望ましい。

##まとめ
JSONあるいは目的に応じたデータフォーマットを採用すること
データを不要なエンベロープで包まないこと
レスポンスをできる限りフラットな状態にすること
各データの名前が簡潔で分かりやすく、適切な単数複数形を用いること
エラーの形式を統一し、クライアント側でエラー詳細を機械的に理解できるようにすること

##感想
API設計の重要性について分かってきたので、
次回はHTTPの仕様について学んでいく。