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は、エンドポイントごとに特定のリソースを取得・作成・更新・削除できるため、直感的で理解しやすい設計になります。
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
- クライアントは GET /users/1 のようにリクエストを送るだけで、簡単にデータを取得可能
2.HTTPキャッシュの活用
@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 では、取得したいフィールドだけ指定できる
query {
user(id: 1) {
id
name
}
}
📌 解説
id と name だけ を指定 → email や address など不要なデータは取得しない。
無駄なデータ転送がない ため、通信量を削減できる。
📌 レスポンス
{
"data": {
"user": {
"id": 1,
"name": "taro yamada"
}
}
}
🔹 REST API だとすべてのフィールドが返るが、GraphQL なら本当に必要なものだけ取得できる。
2. 複数のデータを1回のリクエストで取得
REST API では、複数のデータを取得する場合、複数のエンドポイントを叩く必要がある。 例えば、売上データとユーザー数を取得するには:
- GET /sales → 売上データを取得
- GET /users/count → ユーザー数を取得
GraphQL では、1回のクエリで実現できる。
query {
sales {
total
}
users {
count
}
}
📌 解説
- sales(売上データ)と users(ユーザー数)を1回のクエリで取得できる
- これにより、APIの呼び出し回数を減らし、パフォーマンス向上 につながる
📌 レスポンス
{
"data": {
"sales": {
"total": 50000
},
"users": {
"count": 1200
}
}
}
🔹 REST API だと2回のリクエストが必要だが、GraphQL なら1回のリクエストで取得可能!
3. リアルタイムデータの取得
REST API では、リアルタイムデータを取得するために、定期的にAPIをポーリング(一定間隔でリクエスト)する必要がある。
例えば
エラーログを監視する場合「GET /error-logs」 を 毎秒実行(ポーリング)することで、サーバー負荷が高くなるが、GraphQL の Subscription を使えば、リアルタイムでデータを受け取れる
subscription {
newErrorLogs {
timestamp
message
}
}
📌 解説
エラーログが発生すると、自動的にクライアントに通知される!
ポーリング不要! 必要なときだけデータを受け取れる。
📌 レスポンス例 (エラー発生時にサーバーから自動でデータが送られる)
{
"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によるクライアントキャッシュ
const { data } = useQuery(GET_USER, {
variables: { id: 1 },
fetchPolicy: "cache-first",
});
2.Redisを使ったサーバーキャッシュ
@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 | チャット, ゲーム, 金融取引 |