REST APIとGraphQLの併用 ～WEBアプリにおける最適なAPI設計と活用の可能性～

## 1. はじめに

近年、多くのWebアプリケーションでは **REST API** が広く採用されています。RESTは、シンプルな設計と**HTTPプロトコル**を活用した柔軟な通信が特徴であり、企業システムやSaaSなどのバックエンドAPIとして広く普及しています。特に、バックエンドを**Spring Boot**などのフレームワークで開発し、フロントエンドを**SPA**（Single Page Application）で構築するケースでは、REST APIが標準的な選択肢となっています。

筆者自身も業務アプリケーションの開発経験が多く、これまで主にシンプルなCRUDを中心としたREST APIの開発を行ってきました。実際、多くのシステムではREST APIで十分な対応が可能ですが、ダッシュボードのように複雑なデータ取得やリアルタイム取得を必要とするケースも一部存在します。このような場合に、**GraphQL**を活用できる可能性があるのではと考え、少し調べてみました。

REST APIでは、以下のような課題に直面する可能性があります。

* オーバーフェッチ（不要なデータの取得）
* アンダーフェッチ（必要なデータが足りない）
* 複数のAPI呼び出しが必要になるデータ構造
* リアルタイムデータの取得が困難

もちろん、これらの課題に対してもREST APIの設計次第で対応可能なことが多いですが、一部のケースではGraphQLが有効な選択肢となるかもしれません。そこで、本記事ではREST APIを基本としつつ、GraphQLを併用することで管理画面のデータ取得を最適化する可能性について考察します。

なお、**gRPC**や**WebSocket**の通信プロトコルを用いたAPI通信技術も存在しますが、本記事ではREST APIとGraphQLに焦点を当てるため、これらについての詳細な説明は割愛します。（まとめにて**REST API**,**GraphQL**,**gRPC**,**WebSocket**の機能比較表を載せています）

---

## 2. REST APIのメリットと課題

### 2.1 REST APIのメリット

#### 1. シンプルな設計

REST APIは、エンドポイントごとに特定のリソースを取得・作成・更新・削除できるため、直感的で理解しやすい設計になります。

```java
@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}
```
* クライアントは GET /users/1 のようにリクエストを送るだけで、簡単にデータを取得可能

#### 2.HTTPキャッシュの活用

```java
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
    User user = userService.getUserById(id);
    return ResponseEntity.ok()
            .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS)) // 60秒キャッシュ
            .body(user);
}

```
* ETagや Cache-Control を利用することで、不要なAPI呼び出しを抑えられる

### 2.2. REST APIの課題

| 課題 | REST APIでの対応 |
|------|------------------|
| オーバーフェッチ・アンダーフェッチ | クライアントが必要としないデータまで取得 or 必要なデータを得るために複数回リクエストが必要 |
| ダッシュボードなどのデータ集約が難しい | 例えば、売上データ、ユーザー数、エラー発生件数を1画面に表示するには複数のAPIコールが必要 |
| リアルタイムデータの取得が困難 | 一定間隔でポーリングが必要で、サーバー負荷が増加 |


このようなケースでは、 **GraphQLを併用することで解決** できる可能性があります。

## **3. GraphQLの特徴とメリット**

### **3.1. GraphQLの基本概念**
GraphQLは、**クライアントが取得したいデータを指定できるAPIクエリ言語** です。

#### **GraphQL vs REST API**
| | REST API | GraphQL |
|--|--|--|
| データ取得 | 固定のエンドポイント | 1つのエンドポイントで柔軟な取得 |
| オーバーフェッチ | 発生しやすい | 必要なデータだけ取得可能 |
| データ結合 | クライアント側で複数APIを組み合わせる | 1つのクエリで取得可能 |

---

### **3.2. GraphQLのメリット**

#### **1.必要なデータだけ取得できる（オーバーフェッチ・アンダーフェッチの解決）**
REST API では、不要なデータまで取得してしまう（オーバーフェッチ）ことがある。 例えば、GET /users/1 で id, name, email, address, phone など すべての情報が返ってくる。

GraphQL では、取得したいフィールドだけ指定できる
```graphql
query {
  user(id: 1) {
    id
    name
  }
}
```
📌 解説

id と name だけ を指定 → email や address など不要なデータは取得しない。
無駄なデータ転送がない ため、通信量を削減できる。

📌 レスポンス
```json
{
  "data": {
    "user": {
      "id": 1,
      "name": "taro yamada"
    }
  }
}
```
🔹 REST API だとすべてのフィールドが返るが、GraphQL なら本当に必要なものだけ取得できる。

#### 2. 複数のデータを1回のリクエストで取得
REST API では、複数のデータを取得する場合、複数のエンドポイントを叩く必要がある。 例えば、売上データとユーザー数を取得するには：

* GET /sales → 売上データを取得
* GET /users/count → ユーザー数を取得

GraphQL では、1回のクエリで実現できる。

```graphql
query {
  sales {
    total
  }
  users {
    count
  }
}
```
📌 解説

* sales（売上データ）と users（ユーザー数）を1回のクエリで取得できる
* これにより、APIの呼び出し回数を減らし、パフォーマンス向上 につながる

📌 レスポンス
```json
{
  "data": {
    "sales": {
      "total": 50000
    },
    "users": {
      "count": 1200
    }
  }
}
```
🔹 REST API だと2回のリクエストが必要だが、GraphQL なら1回のリクエストで取得可能！

#### 3. リアルタイムデータの取得
REST API では、リアルタイムデータを取得するために、定期的にAPIをポーリング（一定間隔でリクエスト）する必要がある。 

**例えば**

エラーログを監視する場合「GET /error-logs」 を 毎秒実行（ポーリング）することで、サーバー負荷が高くなるが、GraphQL の Subscription を使えば、リアルタイムでデータを受け取れる

```graphql
subscription {
  newErrorLogs {
    timestamp
    message
  }
}
```
📌 解説

エラーログが発生すると、自動的にクライアントに通知される！
ポーリング不要！ 必要なときだけデータを受け取れる。
📌 レスポンス例 （エラー発生時にサーバーから自動でデータが送られる）

```json
{
  "data": {
    "newErrorLogs": {
      "timestamp": "2025-03-20T12:34:56Z",
      "message": "Database connection error"
    }
  }
}
```
🔹 REST API のポーリングとは違い、GraphQL の Subscription なら、必要なときだけリアルタイムで通知が届く

## **4. REST APIとGraphQLの併用戦略**

| API | REST API | GraphQL |
|--|--|--|
| **CRUD操作** | ✅ 適している | ⚠️ 過剰設計の可能性 |
| **ダッシュボード** | ⚠️ API呼び出しが増える | ✅ 最適化できる |
| **リアルタイムデータ** | ⚠️ ポーリングが必要 | ✅ Subscriptionで対応 |

---

## **5. キャッシュ戦略とリアルタイムデータの取得**

### **5.1. HTTPキャッシュが使えない理由**
REST APIでは、`Cache-Control` や `ETag` を利用して**リクエスト/レスポンスモデル** に基づいたキャッシュが可能ですが、GraphQLのリアルタイムデータ取得では **WebSocket (Subscription)** を利用するため適用できません。

また、GraphQLは**すべてのリクエストが `/graphql` という1つのエンドポイントに対して行われるため**、従来のREST APIのように `GET /users/1` のレスポンスを個別にキャッシュすることが難しくなります。

---

### **5.2. GraphQLにおけるキャッシュ戦略**
GraphQLでは、以下の方法でキャッシュを最適化できます。

#### 1. **Apollo Clientによるクライアントキャッシュ**
```javascript
const { data } = useQuery(GET_USER, {
 variables: { id: 1 },
 fetchPolicy: "cache-first",
});
```

#### 2.Redisを使ったサーバーキャッシュ

```java
@GraphQLQuery(name = "user")
public User getUser(@GraphQLArgument(name = "id") Long id) {
    return cacheService.getCachedUser(id, () -> userService.getUserById(id));
}
```

## **6. まとめ**
REST APIは **CRUD操作やHTTPキャッシュを活用したデータ取得** に適していますが、**リアルタイムデータの取得や複数データの統合にはGraphQLが効果的** です。

| API設計 | REST API (HTTPキャッシュ) | GraphQL (WebSocket/Subscription) |
|--|--|--|
| **データ取得方式** | クライアントがリクエスト | サーバーがプッシュ |
| **キャッシュの適用** | HTTPキャッシュ (`Cache-Control`, `ETag`) | Apollo Client, Redis |
| **リアルタイム性** | ポーリングが必要 | WebSocketで即時更新 |

REST APIを基本にしつつ、**ダッシュボードやリアルタイムデータの取得にはGraphQLを併用** することで、より柔軟なAPI設計が可能になります。今後、データ取得の最適化を検討する際には、GraphQLの導入も視野に入れてみましょう。


おまけ、
| 項目              | **REST API**                       | **GraphQL**                         | **gRPC**                               | **WebSocket**                           |
|-------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------|
| **通信プロトコル**  | HTTP                           | HTTP                           | HTTP/2                          | TCP                            |
| **データフォーマット** | JSON, XML                      | JSON                           | Protocol Buffers (Protobuf)    | JSON, バイナリデータ              |
| **主な用途**       | 一般的なWeb API                 | 柔軟なデータ取得が必要なAPI       | 高速な通信・マイクロサービス間通信 | 双方向・リアルタイム通信           |
| **オーバーフェッチ** | 発生しやすい                    | 発生しにくい                    | 発生しにくい                     | なし                            |
| **アンダーフェッチ** | 発生しやすい                    | 発生しにくい                    | 発生しにくい                     | なし                            |
| **リアルタイム通信** | WebSocket併用で可能              | サブスクリプション機能で可能       | 双方向ストリーミングが可能          | 可能                            |
| **パフォーマンス**  | 低～中（JSONのオーバーヘッドあり）  | 中（1回のリクエストで多くのデータ取得可） | 高（バイナリ通信、高速圧縮）       | 高（常時接続）                  |
| **スキーマ定義**   | 必須ではない                      | Schema（型定義）必須             | .protoファイル必須               | なし                            |
| **クライアントのサポート** | 広範（ほぼ全ての環境で対応）        | 広範（フロントエンドとの連携が容易） | 言語ごとに専用のgRPCライブラリが必要 | ブラウザ・モバイルアプリなどで利用 |
| **主な利用例**     | RESTful API, Webサービス        | ダッシュボード, フレキシブルなAPI | マイクロサービス, IoT           | チャット, ゲーム, 金融取引