API Gateway と Hasura で構築する高速な GraphQL API
目次
はじめに
モダンなアプリケーション開発では、複数のデータソースを統一的に扱う必要があります。API Gateway と Hasura を組み合わせることで、スケーラブルで保守性の高い API インフラを実現できます。
本記事では、この二つのツールの特性を理解し、実装例を通じて実践的な活用方法を解説します。
API Gateway とは
概要
AWS API Gateway は、アプリケーションとバックエンドサービスの間に位置するマネージドなフロントドアです。クライアントのリクエストを適切なバックエンドにルーティングし、セキュリティ、スケーリング、監視を統一的に管理します。
主な役割
- トラフィック管理: 数十万の同時リクエストを自動的に処理
- 認証・認可: IAM、Cognito、Lambda authorizer など複数の方式に対応
- レート制限: 顧客ティアごとの使用量制御
- キャッシング: レスポンスキャッシュで応答速度を向上
- 監視: CloudWatch や X-Ray による詳細なメトリクス収集
API Gateway のアーキテクチャ
Client Requests
↓
API Gateway(エントリーポイント)
↓
認証・認可・レート制限・キャッシング
↓
バックエンドサービス(Lambda・EC2・HTTP エンドポイント)
↓
Response → Client
Hasura とは
概要
Hasura は、GraphQL エンジンとして機能するオープンソースツールです。データベースやマイクロサービスを GraphQL インターフェースで統一し、自動的に本番対応の API を生成します。
従来の GraphQL との違い
従来の GraphQL サーバーでは、各フィールドに対してレゾルバー関数を手書きする必要があります。一方、Hasura はコンパイラ・アプローチを採用し、GraphQL クエリを直接最適化された SQL クエリに変換します。
GraphQL Query
↓
GraphQL AST にパース
↓
SQL AST に変換
↓
変数と変換を適用
↓
最適化された SQL を実行
主な機能
- 自動スキーマ生成: データベーステーブルから完全な GraphQL API を自動生成
- マルチソース対応: PostgreSQL、マイクロサービス API、REST API を統合
- リアルタイム: GraphQL Subscription で変更を即座に配信
- 行レベルセキュリティ: ロールベースの細粒度なアクセス制御
- カスタムロジック: Actions や Event Triggers で ビジネスロジックを追加
API Gateway と Hasura の連携
アーキテクチャパターン
Client Applications
↓
AWS API Gateway(REST/HTTP/WebSocket)
- 認証・認可
- レート制限
- キャッシング
↓
Hasura GraphQL Layer
- スキーマ統合
- フィールドレベルのアクセス制御
- リアルタイム Subscription
↓
バックエンドデータソース
- データベース
- マイクロサービス API
- 外部 GraphQL/REST API
連携のメリット
| 機能 | API Gateway | Hasura | 統合効果 |
|---|---|---|---|
| リクエストルーティング | ✓ | - | 完全なトラフィック管理 |
| 認証戦略 | 複数対応 | ヘッダーベース | 階層的なセキュリティ |
| レート制限 | API レベル | クエリレベル | 包括的な制御 |
| リアルタイム | WebSocket | Subscription 内蔵 | シームレスなリアルタイム |
| データ統合 | オーケストレーション | 統一化 | 統一されたインターフェース |
| 監視 | インフラレベル | クエリレベル | フルスタック可視性 |
実装例
例1: E-コマース API の構築
複数のマイクロサービスを統合した E-コマース API を構築する場合を考えます。
構成要素:
- 商品カタログサービス(GraphQL API)
- 在庫管理(PostgreSQL データベース)
- 決済プロセッサー(REST API)
- CMS 連携(REST API)
実装ステップ:
1. Hasura の設定
# docker-compose.yml
version: "3.6"
services:
postgres:
image: postgres:14
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: ecommerce
volumes:
- db_data:/var/lib/postgresql/data
hasura:
image: hasura/graphql-engine:latest
depends_on:
- postgres
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:password@postgres:5432/ecommerce
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: admin_secret
ports:
- "8080:8080"
volumes:
db_data:2. 在庫データベースのセットアップ
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE inventory (
id SERIAL PRIMARY KEY,
product_id INTEGER REFERENCES products(id),
quantity INTEGER NOT NULL,
warehouse_id INTEGER,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- インデックスを作成してクエリを高速化
CREATE INDEX idx_inventory_product_id ON inventory(product_id);
CREATE INDEX idx_products_name ON products(name);3. REST API を GraphQL にラップ
Hasura の Actions を使用して、決済プロセッサーの REST API を GraphQL にラップします。
# Actions を定義
mutation ProcessPayment($amount: Float!, $currency: String!) {
processPayment(amount: $amount, currency: $currency) {
transaction_id
status
timestamp
}
}Hasura Admin Console で以下を設定:
- Webhook URL:
https://payment-service.example.com/process - 入出力型定義
- エラーハンドリング
4. API Gateway のセットアップ
# AWS CLI で REST API を作成
aws apigateway create-rest-api \
--name "ECommerceAPI" \
--description "Unified E-Commerce API"API Gateway にて:
- リソース
/graphqlを作成 - Hasura エンドポイントへのプロキシ統合を設定
- JWT 認証用の Lambda authorizer を追加
5. 認証の実装
# Lambda Authorizer (JWT 検証)
import json
import jwt
import os
def lambda_handler(event, context):
token = event['authorizationToken']
try:
decoded = jwt.decode(
token,
os.environ['JWT_SECRET'],
algorithms=['HS256']
)
auth_context = {
'x-hasura-user-id': decoded['sub'],
'x-hasura-role': decoded.get('role', 'user')
}
return {
'principalId': decoded['sub'],
'policyDocument': {
'Version': '2012-10-17',
'Statement': [{
'Action': 'execute-api:Invoke',
'Effect': 'Allow',
'Resource': event['methodArn']
}]
},
'context': auth_context
}
except jwt.InvalidTokenError:
raise Exception('Unauthorized')6. GraphQL クエリの例
query GetProductsWithInventory($warehouse: Int!) {
products {
id
name
price
description
inventory(where: { warehouse_id: { _eq: $warehouse } }) {
quantity
updated_at
}
}
}
subscription OnInventoryUpdate($product_id: Int!) {
inventory(where: { product_id: { _eq: $product_id } }) {
quantity
warehouse_id
updated_at
}
}例2: リアルタイム協働編集アプリケーション
ドキュメント管理システムで複数ユーザーによる同時編集をサポートする場合です。
アーキテクチャ:
1. クライアント更新要求
↓
API Gateway(REST エンドポイント)
↓
Hasura mutation でドキュメント更新
↓
データベース変更
↓
Hasura Event Trigger 発火
↓
Webhook で外部サービスに通知
2. リアルタイム購読
↓
API Gateway(WebSocket)
↓
Hasura subscription で変更を配信
↓
接続中の全クライアントに更新を配信
実装例:
# ドキュメント更新の mutation
mutation UpdateDocument($doc_id: Int!, $content: String!, $user_id: Int!) {
update_documents_by_pk(
pk_columns: { id: $doc_id }
_set: { content: $content, updated_at: "now()" }
) {
id
updated_at
}
insert_document_history_one(
object: {
document_id: $doc_id
user_id: $user_id
content_delta: $content
timestamp: "now()"
}
) {
id
}
}
# リアルタイム購読
subscription OnDocumentUpdate($doc_id: Int!) {
documents_by_pk(id: $doc_id) {
id
content
updated_at
updated_by {
id
name
}
}
document_history(
where: { document_id: { _eq: $doc_id } }
order_by: { timestamp: desc }
limit: 10
) {
id
content_delta
user_id
timestamp
}
}Event Trigger の設定:
# Webhook handler
from flask import Flask, request
import requests
app = Flask(__name__)
@app.route('/webhook/document-updated', methods=['POST'])
def document_updated():
event = request.json['event']
doc_id = event['data']['new']['id']
# 接続中のクライアントに通知
for client_ws in active_connections:
asyncio.create_task(
client_ws.send_json({
'type': 'document.updated',
'document_id': doc_id,
'timestamp': event['created_at']
})
)
return {'status': 'ok'}ベストプラクティス
1. キャッシング戦略
┌─────────────────────────────────────────┐
│ CDN キャッシュ │
│ (静的コンテンツ: 1時間) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ API Gateway キャッシュ │
│ (レスポンス: 5分) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Hasura クエリキャッシュ │
│ (頻繁なクエリ: 1分) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ データベース │
└─────────────────────────────────────────┘
2. レート制限の設定
# API Gateway でのレート制限
- スタンダードユーザー: 100 req/min
- プレミアムユーザー: 1000 req/min
- API キー検証: X-API-Key ヘッダー必須
# Hasura でのクエリ制限
- クエリ深度: 最大 10 レベル
- クエリ複雑度: スコア制度で制御3. セキュリティ層
┌─────────────────────────────────────────┐
│ API Gateway IAM ポリシー │
│ (API レベルの認可) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Hasura RBAC │
│ (ロールベースのアクセス制御) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Hasura Row-Level Security │
│ (行レベルのフィルタリング) │
└─────────────────────────────────────────┘
よくある質問
Q: Hasura だけでは不十分なのか?
A: Hasura は優れた GraphQL エンジンですが、エンタープライズレベルのトラフィック管理、複雑な認証戦略、API 分析には API Gateway が必要です。API Gateway と Hasura は相補的な役割を果たします。
Q: コストの増加は?
A: Hasura はオープンソースで無料、または クラウド版で段階的課金です。API Gateway は使用量ベースの課金となり、適切に設計すればコストを抑えられます。
Q: 既存の API Gateway から移行できるか?
A: はい。Apigee、MuleSoft などの既存 API Gateway と並行運用し、段階的に Hasura へ移行することも可能です。
まとめ
API Gateway と Hasura の組み合わせは、モダンなバックエンド API インフラを構築する強力なアプローチです:
- API Gateway: トラフィック管理、セキュリティ、監視を担当
- Hasura: データ統合、GraphQL 生成、リアルタイム機能を担当
この二層構造により、スケーラブルで保守性の高い、開発効率の優れた API プラットフォームを実現できます。
ぜひ自分のプロジェクトで試してみてください。
関連記事
- 技術
REST API vs GraphQL: 開発規模ごとの選択基準
REST APIとGraphQLの選択は技術の優劣ではなく、チーム規模とデータ要件の文脈で決まる。小規模・中規模・大規模それぞれの判断基準と、失敗事例から得た実践的な意思決定フレームワークを解説する。
GraphQLAPIアーキテクチャ - 技術
Webカメラだけで物理マウスを捨てる - NonMouseをM2 Mac + Python 3.14で再起動して自分用にチューニングした話
Webカメラと手のランドマーク検出でマウスを動かすOSS「NonMouse」を、M2 Mac + Python 3.14で動かすまでの依存再構築・Tasks API移行・TUI化と、押下トグル操作や加速カーブのチューニングを実装ベースで記録。
Python - 技術
Claude Codeマルチエージェントのリアルタイム監視ダッシュボードを作った
Claude Codeをtmuxで11人編成のマルチエージェントとして運用する中で生まれた「誰が何をしているか分からない」課題を、173行のBashスクリプトによるターミナルTUIダッシュボードで解決した設計と実装の記録。
ClaudeAIマルチエージェント
