LESSON 30分

ストーリー

高橋アーキテクト
APIが増えてくると、クライアントは混乱する

高橋アーキテクトがマイクロサービスの構成図を描いた。 ユーザーサービス、商品サービス、注文サービス…それぞれが独自のAPIを持っている。

高橋アーキテクト
クライアントは、どのサービスに何を聞けばいいか知る必要がある。サービスが増えるほど、複雑になる
あなた
だから API Gateway で一元化するんですか?
高橋アーキテクト
その通り。さらに、クライアントの種類ごとに最適なAPIを提供するBFF(Backend for Frontend) というパターンもある

API Gatewayとは

基本概念

graph LR
    subgraph "Before(API Gateway なし)"
        W1["Webアプリ"] --> U1["ユーザーサービス"]
        W1 --> P1["商品サービス"]
        W1 --> O1["注文サービス"]
        M1["モバイルアプリ"] --> U1
        M1 --> P1
        M1 --> O1
    end

    subgraph "After(API Gateway あり)"
        W2["Webアプリ"] --> GW["API Gateway"]
        M2["モバイルアプリ"] --> GW
        GW --> U2["ユーザーサービス"]
        GW --> P2["商品サービス"]
        GW --> O2["注文サービス"]
    end

API Gatewayの役割

// 1. ルーティング
// クライアントのリクエストを適切なサービスに転送
// /api/users/* → ユーザーサービス
// /api/products/* → 商品サービス
// /api/orders/* → 注文サービス

// 2. 認証・認可
// すべてのリクエストの認証を一箇所で処理
// JWTトークンの検証、APIキーの検証

// 3. レート制限
// サービスごとではなく、Gateway で一元管理

// 4. ログ・モニタリング
// すべてのAPIリクエストを一箇所でログ記録

// 5. プロトコル変換
// クライアント: REST → Gateway → 内部サービス: gRPC

// 6. レスポンス集約
// 複数サービスの結果を1つのレスポンスに統合

実装例

// Express ベースの簡易 API Gateway
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';

const app = express();

// 認証ミドルウェア(全リクエストに適用)
app.use(authMiddleware);

// レート制限
app.use(rateLimitMiddleware({ windowMs: 60000, max: 100 }));

// ルーティング
app.use('/api/users', createProxyMiddleware({
  target: 'http://user-service:3001',
  pathRewrite: { '^/api/users': '/users' },
}));

app.use('/api/products', createProxyMiddleware({
  target: 'http://product-service:3002',
  pathRewrite: { '^/api/products': '/products' },
}));

app.use('/api/orders', createProxyMiddleware({
  target: 'http://order-service:3003',
  pathRewrite: { '^/api/orders': '/orders' },
}));

BFF(Backend for Frontend)

なぜBFFが必要か

// 問題: 異なるクライアントが異なるデータを必要とする

// Webアプリ(デスクトップ): 大きな画面、高速回線
// → ユーザー情報 + プロジェクト一覧 + 統計データ + 通知

// モバイルアプリ: 小さな画面、低速回線
// → ユーザーの名前とアバター + タスク3件 + 未読通知数

// IoTデバイス: 極小画面、超低速回線
// → タスク数だけ

// 1つのAPIで全クライアントに対応すると:
// - Webは必要なデータが足りない(Under-fetching)
// - モバイルは不要なデータが多い(Over-fetching)

BFFパターン

graph LR
    Web["Webアプリ"] --> WBFF["Web BFF"]
    WBFF --> US["ユーザーサービス"]
    WBFF --> PS["商品サービス"]
    WBFF --> OS["注文サービス"]

    Mobile["モバイルアプリ"] --> MBFF["Mobile BFF"]
    MBFF --> US
    MBFF --> PS

    IoT["IoTデバイス"] --> IBFF["IoT BFF"]
    IBFF --> OS

BFFの実装

// Web BFF(デスクトップ向け)
// 豊富なデータを返す
app.get('/web/dashboard', async (req, res) => {
  const [user, projects, stats, notifications] = await Promise.all([
    userService.getUser(req.userId),
    projectService.listProjects(req.userId, { limit: 10 }),
    statsService.getDashboardStats(req.userId),
    notificationService.getNotifications(req.userId, { limit: 20 }),
  ]);

  res.json({
    user: {
      id: user.id,
      name: user.name,
      email: user.email,
      avatarUrl: user.avatarUrl,
      role: user.role,
    },
    projects,
    stats,
    notifications,
  });
});

// Mobile BFF(モバイル向け)
// 必要最小限のデータを返す
app.get('/mobile/dashboard', async (req, res) => {
  const [user, tasks, unreadCount] = await Promise.all([
    userService.getUser(req.userId),
    taskService.getMyTasks(req.userId, { limit: 3 }),
    notificationService.getUnreadCount(req.userId),
  ]);

  res.json({
    user: {
      name: user.name,
      avatarUrl: user.avatarUrl,
    },
    recentTasks: tasks.map(t => ({
      id: t.id,
      title: t.title,
      status: t.status,
    })),
    unreadNotifications: unreadCount,
  });
});

API Gateway vs BFF

観点API GatewayBFF
目的リクエストのルーティングと横断的関心事クライアント固有のAPI提供
通常1つクライアントの種類ごとに1つ
ビジネスロジック含まないクライアント向けの変換ロジックを含む
管理者インフラチームフロントエンドチーム
組み合わせBFFの前段に配置可能Gateway の後段に配置可能

組み合わせパターン

graph LR
    Web["Webアプリ"] --> GW["API Gateway<br/>認証、レート制限、ログ"]
    Mobile["モバイルアプリ"] --> GW
    IoT["IoTデバイス"] --> GW

    GW --> WBFF["Web BFF"]
    GW --> MBFF["Mobile BFF"]
    GW --> IBFF["IoT BFF"]

    WBFF --> SVC1["サービス群"]
    MBFF --> SVC1
    IBFF --> SVC1

    style GW fill:#f9f,stroke:#333

まとめ

パターン役割適する場面
API Gatewayルーティング、認証、レート制限マイクロサービスの一元管理
BFFクライアント固有のAPI提供複数クライアント向けAPI
組み合わせ横断的関心事 + クライアント最適化大規模システム

チェックリスト

  • API Gatewayの役割(ルーティング、認証、レート制限)を理解した
  • BFFパターンが必要な理由を説明できる
  • API GatewayとBFFの違いを説明できる
  • 組み合わせパターンの構成を理解した

次のステップへ

API GatewayとBFFを学びました。

次は演習です。APIバージョン移行計画を実際に立ててみましょう。


推定読了時間: 30分