REST WebAPI設計を学ぶ
Web APIとは
WebAPI(Web Application Programming Interface)は、異なるソフトウェアやサービス間でデータを交換したり機能を共有するためのインターフェース。
一言でいうとインターネットを通じて異なるプログラムやサービスがお互いに通信し合うための方法です🚀
RESTfulとは
REST(Representational State Transfer)は、Web上で情報やサービスを簡潔で一貫した方法でやり取りするアーキテクチャ(設計)スタイルです。
RESTfulという言葉は、このRESTアーキテクチャの原則に従って設計されたWebサービスやAPIを指します。
REST原則
REST原則にはさまざまな概念が含まれていますが、以下の6つの基本原則が最も重要とされています。
クライアント/サーバーの分離
システムはクライアント(画面UI)とサーバー(データ)で分離することにより、拡張性が向上し様々なプラットフォームやデバイス間での互換性が確保されます。
ステートレスな通信
それぞれのリクエストは独立しており、過去のリクエストの情報に依存しません。これにより、システムの可用性と信頼性が向上します。
キャッシュ可能
レスポンスはキャッシュ可能であるべきで、効率的なインタラクションを可能にします。キャッシュされたデータは、繰り返し同じデータをリクエストする際にサーバーの負荷を軽減します。
統一インターフェース
システム内の全てのリソースは、一貫したインターフェースを通じてアクセスされるべきです。これは、インタラクションを簡素化し、システム全体の拡張性を向上させます。
レイヤードシステム
システムは複数の層に分けることができ、各層は特定の機能に焦点を当てます。
各層の役割を決めて独立させることで再利用性が高まるだけではなくセキュリティ、負荷分散、キャッシュなどの様々な拡張機能をシステムに統合しやすくなります。
コードオンデマンド
クライアントに対して必要に応じて実行可能なコード(例えばJavaScriptのスクリプト)をサーバーからダウンロードし、クライアント側で実行することを可能にします。
URIの設計
URI設計時は下記のことを考慮します。
短く記憶しやすい
× | GET http://api.example.com/service/api/search |
apiが重複して使用されている。意味をもたないserviceという単語がある |
○ | GET http://api.example.com/search |
シンプルな上、意味が理解できる |
人間が読んで理解できる
× | GET http://api.example.com/sv/u |
省略されていて理解できない |
○ | GET http://api.example.com/users |
省略されておらず理解できる |
全て小文字
× | GET http://api.example.com/Users |
大文字小文字が混在していて間違えやすい |
○ | GET http://api.example.com/users |
小文字で統一されていて間違えにくい |
単語はハイフンで繋げる
× | GET http://api.example.com/popular_users |
アンダースコアはタイプライターで下線を引くためのもの |
○ | GET http://api.example.com/popular-users |
ハイフンは単語を繋ぐためのもの |
単語は複数形にする
× | GET http://api.example.com/user/1 |
そもそもURIで表現しているのはリソースの集合 |
○ | GET http://api.example.com/users/1 |
複数形でリソースの集合であることを明示 |
エンコードを必要とする文字を使わない
× | GET http://api.example.com/%E3%83%A6%.. |
URIから意味が理解できない |
○ | GET http://api.example.com/users |
URIから意味が理解できる |
サーバー側のアーキテクチャが反映されていない
× | GET http://api.example.com/cgi-bin/get_users.php?id=1 |
脆弱性を突かれる可能性がある |
○ | GET http://api.example.com/users/1 |
サーバー側のアーキテクチャを反映せず単純なURI |
改造しやすい
× | GET http://api.example.com/items/alpha/1 |
システム依存と思われるURI設計は意味が理解できない |
○ | GET http://api.example.com/items/1 |
意味が理解しやすいURI設計 |
ルールが統一されている
× | GET http://api.example.com/friends?id=1 |
他のURIはパスパラメーターに対してクエリパラメーターで設計されていて統一されていない |
○ | GET http://api.example.com/friends/1 |
他のURIと統一されたパスパラメーター |
HTTPメソッドの適用
HTTPメソッドは、HTTP(Hypertext Transfer Protocol)を使用してWebサーバーとクライアント間で通信する際に使用されるコマンドです。
これらのメソッドは、Webブラウザ、API、その他のHTTPクライアントがサーバーに対して行いたい操作の種類を指定します。
主要なHTTPメソッドには以下のものがあります
メソッド名 | 説明 |
---|---|
GET | リソースの取得 |
POST | リソースの新規登録 |
PUT | リソースの更新 |
DELETE | リソースの削除 |
例として下記のリクエストを見てみます。
GET /v1/users/123 HTTP/1.1
Host: api.example.com
/v1/users/123
はURIで、リソースを示すのに対し
GET
がHTTPメソッドで、リソースに対する操作を示します。
これらのことから、このリクエストはユーザー情報を取得することが理解できます。
クエリとパスの使い分け
パスパラメーターはURLのパスの一部としてリソースの特定に使用し、
クエリパラメーターはURLの末尾に追加され、リソースの取得方法を細かく指定するのに使用します。
パスパラメーター
URL中に埋め込まれるパラメータです。
例 GET http://api.example.com/users/1
使用ケース
特定のリソースやリソースの集合を指定するとき。
リソースの識別がリクエストの主目的である場合。
URLの構造的な部分としてリソースの位置を示すとき。
例
/users/123: 特定のユーザー(IDが123)を指定。
/books/456/chapters/2: 特定の本(IDが456)の特定の章(第2章)を指定
クエリパラメーター
URLの末尾にある?
に続くキーバリューです。
例 GET http://api.example.com/users?page=2
使用ケース
リソースをフィルタリング、ソート、またはカスタマイズする際。
リクエストにオプションや追加情報を提供する場合。
リソースの識別よりも、その操作や取得方法に焦点を当てる場合。
例
/users?age=30: 年齢が30歳のユーザーをフィルタリング。
/books?sort=title&limit=10: 本のタイトルでソートし、最初の10件のみ取得。
ステータスコード
ステータスコードとは、レスポンスの一部としてサーバーがクライアントに送信する数値コードで、
リクエストの結果を示すものです。下記の5分類があります。
ステータスコード | 説明 |
---|---|
100番台 | 情報 |
200番台 | 成功 |
300番台 | リダイレクト |
400番台 | クライアントサイド起因のエラー |
500番台 | サーバーサイド起因のエラー |
レスポンスのデータフォーマット
主要なレスポンスフォーマットは下記の3種類です。
JSON
軽量で読みやすいデータ交換形式で、多くのプログラミング言語で簡単に扱えます。
{
"name": "John",
"age": 30
}
XML
マークアップ言語で、データの構造を詳細に記述できます。
JSONと比較すると末尾にも閉じタグが必要なため冗長であることがわかります。
<user>
<name>John</name>
<age>30</age>
</user>
JSONP
クロスドメインリクエストを可能にするためのJSONです。
JSONデータをコールバック関数でラップします。
callbackFunction({"name": "John", "age": 30})
データフォーマットの指定方法
データフォーマットの指定方法は下記3種類です。
クエリパラメーター
http://api.sample.com/v1/users?format=json
拡張子
http://api.sample.com/v1/users.json
リクエストヘッダー
GET http://api.sample.com/v1/users
HOST api.sample.com
Accept appication/json
レスポンスの内部構造
レスポンスの内部構造では下記のことを考慮することが重要です。
エンベロープは使用しない
エンベロープとは、レスポンスボディー内のメタ情報を指します。
ヘッダー情報と役割が被るためエンベロープは使わないようにしましょう。
そうすることで、レスポンスの構造をより単純かつ直接的にします。
× 悪い例
{
"data": {
"name": "John",
"age": 30
},
"status": "success",
"error": null
}
○ 良い例
{
"name": "John",
"age": 30
}
オブジェクトはできるだけフラットにする
フラットなデータ構造は、解析や処理が容易であり、特に大規模なシステムや多くの異なるクライアントによる使用の場合に効果的です。
ネストされたデータ構造はレスポンスの容量が増えます。
× 悪い例
{
"user": {
"id": "12345",
"profile": {
"name": "JohnDoe",
"age": 30
},
"contact": {
"email": "johndoe@example.com"
}
}
}
○ 良い例
{
"userId": "12345",
"userName": "JohnDoe",
"userAge": 30,
"userEmail": "johndoe@example.com"
}
プロパティの命名規則を統一する
キャメルケースやパスカルケースなどの命名規則が混在してしまうと、APIの一貫性と可読性が損なわれ、使用者が混乱する可能性があります。
APIのプロパティ命名においては、一つの命名規則に統一することが重要です。
× 悪い例
{
"UserID": 1, // パスカルケース
"user_name": "JohnDoe", // スネークケース
"userEmail": "johndoe@example.com", // キャメルケース
"user-age": 30 // ケバブケース
}
○ 良い例
{
"userId": 1,
"userName": "JohnDoe",
"userEmail": "johndoe@example.com",
"userAge": 30
}
日付はRFC3339形式を使う
日付の表現において、RFC3339形式は国際的な標準であり、特にAPIやウェブサービスで広く用いられています。
× 悪い例
{
"createdAt": "Sat, 27 Mar 21 13:00:00 +0000" // 標準ではない形式(RFC822形式)
}
○ 良い例
{
"createdAt": "2021-03-27T13:00:00Z" // RFC3339形式
}
大きな数値(64bit整数)は文字列で返す
大きな数値(特に64ビット整数)をAPIレスポンスとして返す際に文字列形式を使用することは、特にJavaScriptのような一部のプログラミング言語が大きな整数を正確に扱えない場合に重要です。
× 悪い例
{
"largeNumber": 12345678901234567890 // number型
}
○ 良い例
{
"largeNumber": "12345678901234567890" // string型
}
エラー表現で考慮すること
エラー詳細はレスポンスボディに含める
クライアント(APIを使用する開発者やシステム)はエラーの原因を正確に理解し、適切に対処することができます。
× 悪い例
{
"error": "Resource not found"
}
○ 良い例
{
"error": {
"code": 404,
"message": "Resource not found",
"details": "The requested item with ID 12345 does not exist."
}
}
エラーの際にHTMLが返却されないようにする
通常APIのレスポンスとして期待されるのはHTMLではなくJSON形式です。
エラーが発生した際にHTMLを返すのではなく、JSONやXMLなどの構造化されたフォーマットでエラー情報を返すことでAPIのクライアント(特にプログラムやアプリケーション)はエラー情報を自動的に処理しやすくなります。
× 悪い例
<html>
<head><title>Error</title></head>
<body>
<h1>500 Internal Server Error</h1>
<p>An unexpected error occurred while processing the request.</p>
</body>
</html>
○ 良い例
{
"error": {
"code": 500,
"message": "Internal Server Error",
"details": "An unexpected error occurred while processing the request."
}
}
まとめ
REST WebAPI設計において改めて学んだことをまとめてみましたがいかがだったでしょう。
RESTfulな設計は非常に深いトピックであり、多くのサブトピックを含むことを実感しました。
本記事では表面的な説明に留めていますがRESTfulなAPI設計の際には、REST原則や、URI設計を共通の枠組みとすることで、開発者が理解し易く、利用者にとっても使いやすくなる点や、HTTPメソッド利用によるシンプルさと一般性、ステートレスなアーキテクチャによる独立性と拡張性など多くのメリットがあることがわかります。
RESTful APIのインターフェースに則ったAPI定義に作成方法については、下記にまとめていますので読んでいただけたら嬉しいです🍍
参考
Discussion