今年エンジニアになり、エンジニアについて右も左もわからない状態でAPI設計について担当した私が学んだAPI設計のベストプラクティスについて紹介しようと思います。
この記事で学べる事
- APIとは
- API設計のベストプラクティス
APIとは
そもそもAPIとはなにか知らない方もいらっしゃると思います。
APIとは「Application Programming Interface」の略です。
APIでなにができるのかわかりやすく言うと データ連携 です。
サーバのデータを取得したり、修正したり、削除したりなど様々なことが出来ます。
身近なもので使われているのはYoutubeやInstagramなど様々です。
API設計のベストプラクティス
APIを設計するうえにあたって意識することは2つあります。
1. エンドポイントの設計
2. レスポンスデータの設計
この2つをしっかり意識することでAPI設計のベストプラクティスにつながります。
エンドポイントの設計
エンドポイントとは何でしょうか?
Webでエンドポイントを検索すると「末端、終端」と出てきますが、APIを設計するうえでの意味合いとしてはURIになります。
このURIを正しく設計するために必要なことは書籍「Web API The Good Parts」によると
覚えやすく、どんな機能を持つURIなのかがひと目でわかる
とのことです。
具体的にこのURIを設計するために守るべき基本的原則を見ていきましょう。
不要な単語を避けたURIにする
不必要な単語を避けたほうがよいなんてあたりまえじゃないかと思うかもしれませんが、
ここで例をみてみましょう。
https://api.com/service/api/serach
https://api.com/search
よい例を見ただけでも何がしたいのかわかりますよね?
このように意味が重複するような単語を使ってパスを増やさないようにしましょう。
省略した言葉は使わない
イメージが湧きづらいのでこちらも例を見てみましょう。
https://api.com/s
https://api.com/service
「s」だけではURIをみて何をしたいのか、どんな機能を備えているのか理解することが出来ません。
このようにひとめで理解できないURIというのは大前提の「覚えやすく、どんな機能を持つURIなのかがひと目でわかる」URIに反します。
省略後はこのような理由で避けるようにしましょう。
小文字のみで構成されているURI
大文字と小文字が混在するURIは間違えの温床になります。
そのためホスト名が基本的に小文字で表現されているため、パスも小文字で統一しましょう。
実装方法が反映されていないURI
例えばphpで書かれているとした場合、「php」という単語をわざわざパス内に入れるのは避けましょう。
その理由としてはサーバー攻撃をしようとする悪い人にしか利点がなく、サーバーの脆弱性の露呈につながりかねないからです。
HTTPメソッドについて
URIというリソースをどのように操作するのかを指定するときにHTTPメソッドを使います。
メソッド名 | 詳細 |
---|---|
GET | リソースを取得 |
POST | 新しいリソースを送信 |
PUT | リソースを修正 |
DELETE | リソースの削除 |
PATCH | リソースのメタ情報を取得 |
レスポンスボディの設計
レスポンスで考慮すべきことについて順番に見ていきましょう。
データフォーマット
基本的にJSONを使いましょう。
JSONはシンプルで世界的にもスタンダードになっているため使わない理由がありません。
しかし、仕様上XMLを使わないといけないなどデファクトルールがある場合はそちらに従いましょう。
データの内部構造について
データはフラットにする
そもそもフラットにしない場合の選択肢として階層構造というのがあります。
{
"company": {
"name": "ABC Corporation",
"departments": [
{
"name": "Sales",
"manager": "John Doe",
"employees": [
{ "name": "Alice", "role": "Sales Representative" },
{ "name": "Bob", "role": "Account Manager" }
]
},
{
"name": "Engineering",
"manager": "Jane Smith",
"employees": [
{ "name": "Charlie", "role": "Software Engineer" },
{ "name": "Dave", "role": "DevOps Engineer" }
]
}
]
}
}
[
{
"company_name": "ABC Corporation"
},
{
"department_name": "Sales",
"manager": "John Doe",
"employee_name": "Alice",
"employee_role": "Sales Representative"
},
{
"department_name": "Sales",
"manager": "John Doe",
"employee_name": "Bob",
"employee_role": "Account Manager"
},
{
"department_name": "Engineering",
"manager": "Jane Smith",
"employee_name": "Charlie",
"employee_role": "Software Engineer"
},
{
"department_name": "Engineering",
"manager": "Jane Smith",
"employee_name": "Dave",
"employee_role": "DevOps Engineer"
}
]
フラットにするメリット
- パフォーマンスの向上
→必要な情報のみを取得するので処理時間が少ない - アクセスが簡単
→階層構造では情報の取捨選択が難しい
などがあげられます。
配列はオブジェクトの中に収める
どういうことなのかこちらも例を合わせて確認しましょう。
{
"employees": [
{
"name": "Alice",
"department": "Sales",
"role": "Sales Representative"
},
{
"name": "Bob",
"department": "Sales",
"role": "Account Manager"
},
{
"name": "Charlie",
"department": "Engineering",
"role": "Software Engineer"
},
{
"name": "Dave",
"department": "Engineering",
"role": "DevOps Engineer"
}
]
}
これはemployeesというオブジェクトの中に配列が格納されています。
なぜ、オブジェクトの中に配列を格納することをよしとするのでしょうか?
セキュリティ的に強い構造にするためです。
オブジェクトで配列を包んでいなければ、JSONインジェクションに対して脆弱性が生じ、本来発生するはずのないリスク、問題に直面してしまいます。
このような観点からオブジェクト内に配列を格納するようにしましょう。
エラーハンドリング
エラーが起きた場合のレスポンスの返し方も考えておかなければなりません。
その際に基本的にステータスコードとエラー詳細を含めておけば問題はありません。
ステータスコード | 意味 |
---|---|
100番台 | 情報レスポンス |
200番台 | 成功レスポンス |
300番台 | リダイレクトレスポンス |
400番台 | クライアント起因のエラーレスポンス |
500番台 | サーバー起因のエラーレスポンス |
エラー詳細を返さないといけない理由について説明します。
ステータスコードは汎用性かつ一般性があるもので、個々のAPIについてエラーを表現するには不十分だからです。
例えば、400番台のエラーが返ってきたとして何が原因なのか分からないので、修正するのが大変ですよね。
エラーを返す際はレスポンスボディに入れる方法が有名なので実際に確認してみましょう。
{
"error": [
{
"code": "Alice",
"message": "Bad Authentication data",
}
]
}
エラーは配列で返すようにすることで、複数個のエラーが同時に起こった時は開発者にとって親切な設計であるといえます。
まとめ
いかがだったでしょうか。
上記の内容をAPI設計時に行うことで開発のしやすさや拡張性に富んだ実装が出来ると思います。
是非参考にしてみてください。