『Web API〜the good parts〜』を読んだ

はじめまして。事業開発グループでエンジニアをしている谷端です。
ココナラ法律相談(https://legal.coconala.com)をメインで担当しています。

ココナラ法律相談は、

  • バックエンド:Ruby on Rails
  • フロントエンド:Vue.js

で開発しています。

ココナラ入社前はフロントエンドの開発に関してはjQueryがメインだったこともあり、新たにVue.jsに関するキャッチアップが必要でした。

ざっくりいうと、Vue.jsがAPIを叩いて、そのデータをVue.jsで加工するようなみたいな開発手法をとっています。そこで、先輩になにか参考になる書籍はないか聞いたところ、下記の書籍を紹介してもらったので、自分の備忘録も兼ねてブログにまとめておこうと思います。

『Web API〜the good parts〜』

f:id:kosuke-tanihata:20180627154708j:plain

この本を読んで学べる事

  • どのようにWebAPIを開発するべきか
  • クライアントとサーバーサイドにおける開発においてどこでデータを区切るのか
  • openでもclosedでも明確でわかりやすく汎用的なWebAPIを作る方法(言うは易し)

この本の概要

  • 2章:エンドポイントとリクエストの形式
  • 3章:レスポンスデータの設計
  • 4章:HTTPの仕様を理解
  • 5章:設計変更を想定したWeb APIの作り方
  • 6章:セキュリティ

1章 WebAPIとは?

※ここはイントロなので割愛

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

リクエストの形式

データにアクセスする際に用いるhttpメソッド一覧と使用目的

httpメソッド 使用目的
GET 情報の取得
POST データ作成
DELETE 削除
PUT 複数件更新
PATCH 一件更新

put/patchの使い分けが難しい所ですが 1件だけデータを更新する場合put複数更新する場合はpatchを使用するようにしています。

良いエンドポイントとは?

現在のサービスを例にまとめていきたいと思います。

  • 読んで理解できるエンドポイントになっているか?
    • ✕ legal.coconala.com/api/p0101/c0704/lawyer
      • 何かの条件で絞り込まれた弁護士が取得できそう
    • ◯ legal.coconala.com/api/lawyer/prefecture=1&category=4
      • 県とカテゴリーの条件で絞り込まれた弁護士が取得できると推測できる
  • 大文字小文字で分けない
    • ✕ legal.coconala.com/getLawyers
      • 文字をつなぐ時はハイフンでつなぐことで(googleが推奨)ディレクトリで切る必要がなくなる。
      • また、httpメソッドを応用すればそもそもgetなどの動詞をつける機会をぐっと減らせる。
    • ◯ legal.coconala.com/lawyers/11
  • 改造しやすい
    • ✕ legal.coconala.com/c0500
    • ◯ legal.coconala.com/api/cagegory/1
      • 1の数値変えたら他の値categoryについての情報がとれそう。
  • サーバーのアーキテクチャーが反映されていない
    • ✕ legal.coconala.com/cgi-bin/lawyer/1/pricings
      • サーバーのディレクトリ配置が推測できそうでやばそう。
    • ◯ legal.coconala.com/lawyers/1/pricings

件数の取得位置が明確である

サービス名 取得数 相対位置 絶対位置
twitter count cursor max_id
youtube maxResults pageToken publishBefore

などがありますが、筆者は page/per_pageまたはoffset/limitを使用を勧めています。
件数の絶対値で指定しておかないと新しくデータが追加された際にバグの発生に繋がります。 (ex 同じ投稿が二回表示される、、、みたいな)

memo

  • urlにsearchを入れるor入れない問題
    • 一覧を取得するのか検索結果を返すかによるのでサービスの内容を意識すると良い
  • 1ページのリクエスト多すぎ問題
    • 自社用のAPIを開発するならば、1ページに複数要素がある場合(トップページなど)はパーツごとにAPIを作っていると何度も通信を発生させないといけないケースがあるので1リクエストに複数情報を入れるという手もある。

3章 レスポンスデータの設計

データ形式

海外サービスのほとんどが json形式だが、複数形式をサポートしないといけない場合は urlの後ろに ?format=jsonみたいに指定できるようにして対応すると良い

データはフラットにする

{
    "id": 1,
    "name" : "kousuke tanihata",
    "profile" :{
        "gender" :"male"
    }
}

↑のように不要なネストを避ける。
ただし、親子関係を示したい場合は適切にネストを使う必要がある。

ページネーションをどのように表現するか

hasNextのように次のページを示すパラメーターを作ってあげる。

{
    "profile ": [
                {
            "id": 1,
            "name": "サンプルjsonです",
     },
        {
            "id": 2,
            "name": "jonasan joaster",
     }
    ],
    "hasNext": true,
}

エラーがある際は http statusを利用する

エラーがあった際は http statusだけでなく、エラーの原因/要因を適切に伝える事が大事です。 ユーザーに適切な情報を伝える工夫にもなります。

{
    "status" : 404,
    "error_message" : "idが指定されていません",
}
{
    "status" : 500,
    "error_message" : "サーバーの不具合です",
}

エラーの詳細を伝える

単なるステータスメッセージを伝えるだけでなく、エラーの原因や参照すべきURLなども付けてあげるととても開発がしやすいです。

{
    "errors":{
        "message" : "invalid Auth",
        "url" : "doc.fshuh.com/fagahua",
    }
}

エラーの際に誤って htmlを返さないように設計する。
API使用者側がエラーを処理する難易度があがる(プロジェクトでやっていた箇所があったので修正しました、、、)。

4章 httpの仕様を利用する

番号代 意味
100 情報
200 成功
300 リダイレクト
400 ユーザー要因のエラー
500 サーバー要因のエラー

詳細
https://gist.github.com/rosylilly/3401612

上記の httpメソッドを利用する事で getLawyerみたいにしなくてすむ。

200番台

202 Accepted ファイルアップロード中
204 No Content 削除完了

300番台

API設計では極力使わない。使うならドキュメントに書くようにする。

400番台

405 httpメソッドが間違っている
406 フォーマットがエラー
409 Conflict リソースが競合している(指定されたIDやemailがすでに使用されている)
429 レートリミットを超えている

などなどバリデーションエラーのメッセージと組み合わせて適切なものを使用する。

500番台

500 サーバエラー
504 一時的なエラー

リクエストを返す際には必ずメディアタイプを指定する。

5章 設定変更をしやすいWeb APIを作る

urlを/v1とか/v2で分けるのがオススメ。 versionの区切りをメディアクエリーにすると冗長になる。 ドキュメントに廃止期間を明示する。

はじめて現在のプロジェクトのコードを見たときは不思議に思いましたが、これがあると仕様変更がとても楽になりました。

6章 堅牢な webAPIを作る〜安定性と安全性〜

セキュリティー問題について書かれています。 他の本でも言及されている箇所が多い気がしますが、

  1. 誤った設定で個人情報が公開された状態になっていたケースがある。
  2. まずはhttps化しよう
  3. xssに気をつける

jsonを返すなら content-typeの値が text/htmlではなく、Content-Type: application/jsonに設定する。

まとめと感想

ココナラに入ってはじめてREST(っぽく)APIを開発するようになりました。

フロントにデータを渡す処理を実装する際に書いたコードをボロカスにレビューされ修正してましたが、この本を読む事でバックエンドとフロントエンドの責務の分離をある程度理解する事ができました。

開発中疑問に思っていた事が解消できてかつ整理されてとても学びがありました。

本書は、ココナラに入る前に読んでおきたかったです。