RESTful API 設計の極意：実践ガイド

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/e759ffa0-d01f-f72b-4d65-2755650de6e8.png)](https://leapcell.io/?lc_t=q_restful)

RESTful API（Representational State Transfer API）は、ネットワークアプリケーション間の相互作用を行うための設計スタイルの一つです。REST は標準やプロトコルではなく、一連のアーキテクチャ原則と制約条件の集合です。Web サービスが「RESTful」である場合、それは REST の原則に従い、効率的で信頼性が高く、スケーラブルなネットワークサービスを提供します。

RESTful サービスでは、各リクエストはそのリクエストを処理するために必要なすべての情報を含んでいなければなりません。サーバーはクライアントのリクエストの状態を保持すべきではありません。

RESTful アーキテクチャは複数のレイヤーで構成されることがあり、それぞれが特定の機能を実行できます。このような構造により、より複雑で強力なアプリケーションの構築が可能になります。

## URI 設計

RESTful API の設計では、URL（統一リソースロケータ）は通常リソース（目的語）を表し、HTTP メソッド（GET、POST、PUT、DELETE など）はそのリソースに対する操作（動詞）を表します。この設計スタイルは、アクションよりもリソースの状態と表現を重視します。

### 動詞 + 目的語

動詞は通常、5 つの HTTP メソッドに対応し、CRUD 操作に関連付けられます。

- GET：読み取り（Read）
- POST：新規作成（Create）
- PUT：更新（Update）
- PATCH：更新（Update、通常は部分更新）
- DELETE：削除（Delete）

HTTP 仕様に基づき、メソッド名（動詞）はすべて大文字で表記されるべきです。

### 目的語は名詞であるべき

API を設計する際、URL（統一リソースロケータ）は通常、HTTP 動詞が作用するリソースを表します。RESTful 設計の原則に従うと、URL は動詞ではなく名詞であるべきです。なぜなら、それは操作ではなく「リソース」の集合や個別のインスタンスを表すからです。

誤った例：

- /getAllCars
- /createNewCar
- /deleteAllRedCars

これらの URL には get、create、delete などの動詞が含まれており、操作を表しています。このような設計は RESTful のセマンティックな規則に適合しません。

正しい例：

URL は操作ではなくリソースを表すべきです。以下は適切な URL 設計の例です。

- /users：ユーザーのコレクションを表す
- /users/123：特定の ID（123）を持つ単一のユーザーを表す

上記の例では、/users および /users/123 はどちらも名詞であり、ユーザーのコレクションと特定のユーザーリソースを表しています。このような URL 設計は、理解しやすく、RESTful のリソース指向の原則に適合します。

この命名規則に従うことで、API のパスを明確かつ一貫性のあるものにし、理解しやすくメンテナンスしやすくなります。

### 複数形の URL

一貫性と直感性を保つために、リソースのコレクションを表す URL には複数形を使用することが推奨されます。

URL がリソースのコレクションを指す場合、単数形ではなく複数形を使用します。たとえば、すべてのユーザーのコレクションを表す場合、/user ではなく /users を使用します。

また、単一のリソースを指す URL でも、複数形を使用することが推奨されます。例えば、/users/123 は ID が 123 のユーザーを表します。このように設計することで、一貫性が保たれます。

リソースに階層構造がある場合、URL はこの構造を反映するべきです。例えば、/users/123/posts はユーザー 123 の投稿のコレクションを表します。

### 多階層 URL の回避

リソースの階層構造を考慮すると、多階層の URL を作成しやすくなります。しかし、これは拡張性を損なう可能性があり、意味が曖昧になることがあります。例えば、特定の著者の特定のカテゴリの記事を取得する場合を考えます。

```
GET /authors/12/categories/2
```

このような URL は、理解するのに時間がかかり、拡張性が低くなります。より良い方法として、最初のレベル以外の情報はクエリ文字列を使用して表現するのが適切です。

```
GET /authors/12?categories=2
```

もう一つの例として、公開された記事を検索する場合を考えます。以下の URL を設計することができます。

```
GET /articles?published=true
```

クエリ文字列を使用することで、より柔軟で明確な URL 設計が可能になります。

## ステータスコード

### ステータスコードは正確であるべき

クライアントからのリクエストごとに、サーバーは必ずレスポンスを返す必要があります。レスポンスには、HTTP ステータスコードとデータが含まれます。

HTTP ステータスコードは 3 桁の数値であり、5 つのカテゴリに分類されます。

- **1xx**：情報提供
- **2xx**：成功
- **3xx**：リダイレクト
- **4xx**：クライアントエラー
- **5xx**：サーバーエラー

これらの 5 つのカテゴリには 100 以上の異なるステータスコードがあり、ほとんどのケースをカバーしています。各ステータスコードには標準の（または慣例的な）説明があり、クライアントはステータスコードを確認するだけで、何が起こったのかを判断できます。そのため、サーバーは可能な限り正確なステータスコードを返すべきです。

API では 1xx のステータスコードを使用する必要はありません。以下では、他の 4 つのカテゴリのステータスコードについて説明します。

### 2xx ステータスコード（成功）

異なる HTTP メソッドに対して、適切なステータスコードを返すべきです。一般的な成功を示す **200 OK** 以外にも、より具体的なステータスコードがあります。

- **GET**: `200 OK` - リクエストが成功し、リソースが返される。
- **POST**: `201 Created` - 新しいリソースが作成され、レスポンスには新リソースの URI を含むことが推奨される。
- **PUT**: `200 OK` または `204 No Content` - リソースを完全に更新する際に使用する。レスポンスに内容がある場合は `200`、ない場合は `204`。
- **PATCH**: `200 OK` または `204 No Content` - リソースを部分的に更新する場合に使用する。PUT と同様に、204 は内容がないことを示す。
- **DELETE**: `204 No Content` - リソースが削除されたことを示し、通常レスポンスボディは空。
- **202 Accepted**: リクエストが受理されたが、まだ処理されていないことを示す。非同期処理の場合に適用される。
- **206 Partial Content**: クライアントがリソースの一部のみをリクエストした場合に使用される。例えば、ファイルの一部をダウンロードする際に、サーバーは `Range` ヘッダーに基づいてデータを返す。

### 3xx ステータスコード（リダイレクト）

API では **301（恒久的リダイレクト）** や **302（一時的リダイレクト、307 も同様）** はほとんど使用されません。これらは通常、ブラウザレベルで適用されるため、API では考慮する必要がありません。

API で使用される 3xx のステータスコードは、主に **303 See Other** です。これは「他の URL を参照せよ」という意味で、**POST、PUT、DELETE のリクエスト後に、クライアントが別のリソースを取得するよう誘導する場合に使用** されます。

例えば、注文を作成した後、サーバーが注文の詳細ページにリダイレクトさせたい場合、以下のようなレスポンスを返します。

```
HTTP/1.1 303 See Other
Location: /api/orders/12345
```

### 4xx ステータスコード（クライアントエラー）

4xx ステータスコードは、クライアント側のエラーを示します。以下に代表的なものを示します。

- **400 Bad Request**：クライアントのリクエストが不正であり、サーバーが処理できない。
- **401 Unauthorized**：ユーザーが認証情報を提供していない、または認証に失敗した。
- **403 Forbidden**：ユーザーは認証済みだが、リソースにアクセスする権限がない。
- **404 Not Found**：リクエストされたリソースが存在しない、または利用不可。
- **405 Method Not Allowed**：ユーザーは認証済みだが、使用しようとした HTTP メソッドが許可されていない。
- **410 Gone**：リクエストされたリソースが恒久的に削除された。
- **415 Unsupported Media Type**：リクエストのコンテンツタイプがサポートされていない（例：API は JSON のみをサポートしているが、クライアントが XML を要求した場合）。
- **422 Unprocessable Entity**：クライアントがアップロードしたデータが処理できないため、リクエストが失敗した。
- **429 Too Many Requests**：クライアントのリクエスト回数が制限を超えた。

### 5xx ステータスコード（サーバーエラー）

5xx ステータスコードは、サーバー側のエラーを示します。通常、API はサーバーの詳細なエラー情報をクライアントに開示すべきではありません。そのため、以下の 2 つのステータスコードで十分です。

- **500 Internal Server Error**：クライアントのリクエストは有効だが、サーバー処理中に予期しないエラーが発生した。
- **503 Service Unavailable**：サーバーが一時的にリクエストを処理できない（メンテナンス中など）。

## サーバーのレスポンス

### プレーンテキストを返さない

API のレスポンスデータは、プレーンテキストではなく **JSON 形式** であるべきです。これにより、標準化された構造化データを提供できます。そのため、サーバーのレスポンスの **Content-Type** ヘッダーを `application/json` に設定する必要があります。

クライアント側のリクエストでも、JSON を受け取ることを明示するために **Accept** ヘッダーを `application/json` に設定すべきです。以下はリクエストの例です。

```
GET /orders/2 HTTP/1.1
Accept: application/json
```

### エラー発生時に 200 ステータスコードを返さない

誤った実装の一例として、エラーが発生しているにもかかわらず **200 OK** を返し、レスポンスボディ内にエラー情報を含めるケースがあります。これではクライアントがレスポンスを解析しないとエラーを識別できず、ステータスコードの意味が失われます。

例えば、以下のようなレスポンスは適切ではありません。

```
HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "failure",
  "data": {
    "error": "Expected at least two items in list."
  }
}
```

この場合、エラーが発生しているのに **200 OK** を返しており、クライアントは `"status": "failure"` というフィールドを解析しなければなりません。これは RESTful の設計原則に反します。

適切な方法として、リクエストが無効であることを示す **400 Bad Request** を返し、エラー情報を JSON 形式で提供するべきです。

```
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "Invalid payload.",
  "detail": {
    "surname": "This field is required."
  }
}
```

### リンクの提供

RESTful スタイルの API では、レスポンスにリンクを含めることが一般的です。これは **Hypermedia as the Engine of Application State（HATEOAS）** の概念に基づいています。リンクを提供することで、クライアントは API の他の部分を動的に発見でき、API の可読性と自己記述性が向上します。

以下は、リンクを提供する一般的な方法です。

#### **HAL（Hypertext Application Language）を使用**

HAL は、リソース間のリンクを表現するための人気のあるハイパーメディアフォーマットです。JSON レスポンス内で **\_links** プロパティを使用し、関連するリンクを含めます。

```json
{
  "id": 1,
  "name": "Example",
  "_links": {
    "self": {
      "href": "http://api.example.com/resource/1"
    },
    "related": {
      "href": "http://api.example.com/resource/2"
    }
  }
}
```

#### **JSON 内に直接リンクを含める**

HAL を使用せずに、レスポンスの JSON データ内に直接リンクを含める方法もあります。

```json
{
  "id": 1,
  "name": "Example",
  "links": {
    "self": "http://api.example.com/resource/1",
    "related": "http://api.example.com/resource/2"
  }
}
```

このようにすることで、クライアントは API の他のエンドポイントを探索しやすくなります。

### **コンテンツのレスポンス**

RESTful API 設計では、**POST リクエストは新しいリソースの作成に使用** されます。作成成功後にレスポンスをどのように返すかは、実装や要件によりますが、一般的に以下の 2 つの方法があります。

#### **① 作成されたリソースを返す**

新しいリソースの作成が成功した後、**201 Created** ステータスコードとともに、新しく作成されたリソースの詳細情報をレスポンスとして返す方法です。レスポンスには **Location** ヘッダーを含め、新しいリソースの URI を指定します。

この方法の利点は、クライアントが追加のリクエストを行わなくても、新しいリソースの詳細情報を取得できることです。これにより、処理効率が向上し、ユーザーエクスペリエンスも向上します。

```
HTTP/1.1 201 Created
Location: /resources/123
Content-Type: application/json
{
  "id": 123,
  "name": "New Resource"
  // ... その他のリソース情報
}
```

#### **② レスポンスに具体的なデータを含めない**

RESTful API 設計では、新しいリソースの作成成功後に、レスポンスとして **成功を示すステータスコードのみを返す** 方法もあります。この場合、通常 **201 Created** または **204 No Content** を返し、レスポンスのヘッダーに **Location** フィールドを含めます。

この方法の利点は、レスポンスがシンプルになることです。特に、新しいリソースの詳細情報が大きい場合や、すぐに必要ない場合に有効です。クライアントは必要に応じて、別の GET リクエストを発行して詳細情報を取得できます。

```
HTTP/1.1 201 Created
Location: /resources/123
```

このように、API の設計に応じてレスポンスの方法を選択することができます。

## **まとめ**

RESTful API は **HTTP プロトコルに基づく Web サービスの設計スタイル** であり、リソースの表現とステートレスなやり取りを重視します。**標準的な HTTP メソッド（GET、POST、PUT、DELETE など）やステータスコードを活用** することで、シンプルで効率的かつ理解しやすい API を構築できます。

RESTful 設計を採用することで、Web サービスは **スケーラブル（拡張性が高い）、柔軟（変更が容易）、メンテナンスしやすい** ものになります。正しい URI 設計、適切なステータスコードの使用、エラーハンドリングの明確化など、ベストプラクティスを遵守することで、使いやすく信頼性の高い API を提供できます。

---

### [私たちはLeapcell、バックエンド・プロジェクトのホスティングの最適解です。](https://leapcell.io/?lc_t=q_restful)

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/be937361-cb37-4c33-9faa-72f674f55247.png)](https://leapcell.io/?lc_t=q_restful)

[Leapcell](https://leapcell.io/?lc_t=q_restful)は、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです：

**複数言語サポート**

- Node.js、Python、Go、Rustで開発できます。

**無制限のプロジェクトデプロイ**

- 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

**比類のないコスト効率**

- 使用量に応じた支払い、アイドル時間は課金されません。
- 例: $25で6.94Mリクエスト、平均応答時間60ms。

**洗練された開発者体験**

- 直感的なUIで簡単に設定できます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

**簡単なスケーラビリティと高パフォーマンス**

- 高い同時実行性を容易に処理するためのオートスケーリング。
- ゼロ運用オーバーヘッド — 構築に集中できます。

[ドキュメントで詳細を確認！](https://docs.leapcell.io/)

[![Try Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/b983e368-9990-c120-2975-48d363cf543b.png)](https://leapcell.io/?lc_t=q_restful)

Xでフォローする：[@LeapcellHQ](https://x.com/LeapcellHQ)

---

[ブログでこの記事を読む](https://leapcell.io/blog/restful-api-principles-design-and-best-practices)