ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-03-25中級

Antigravity × Upstash Redis:エッジキャッシュとレート制限で高速・安全なAPIを構築する

Antigravity と Upstash Redis を組み合わせて、Cloudflare Workers 上でエッジキャッシュとレート制限を実装する方法をステップバイステップで解説します。

antigravity435upstashrediscloudflare-workers8edge-cache2rate-limiting2serverless2

取り組みの背景 — なぜエッジでキャッシュとレート制限が必要なのか

API を公開するとき、パフォーマンスとセキュリティは常にセットで考える必要があります。特にサーバーレス環境では、リクエストのたびにコールドスタートやデータベースへのアクセスが発生し、レスポンス速度に直結します。さらに、レート制限がなければ悪意あるリクエストがリソースを枯渇させるリスクもあります。

Upstash Redis は、HTTP ベースの REST API でアクセスできるサーバーレス Redis サービスです。TCP コネクションが使えない Cloudflare Workers のようなエッジ環境でも、そのまま利用できる点が大きな強みです。

Antigravity の AI エージェント支援を活用しながら、Upstash Redis によるエッジキャッシュとレート制限を Cloudflare Workers 上に実装する方法を順を追って整理していきます。

前提知識と環境準備

この記事を読み進めるにあたって、以下の基本的な知識があると理解がスムーズです。

必要なツール

  • Antigravity(最新版)
  • Node.js 18 以上
  • Upstash アカウントupstash.com で無料プランから開始可能)
  • Cloudflare アカウント(Workers の無料枠で十分)

Upstash Redis データベースの作成

まず Upstash Console にアクセスし、新しい Redis データベースを作成します。リージョンは利用者に近い場所を選択してください。作成後、以下の2つの値を控えておきます。

# Upstash Console の REST API セクションから取得
UPSTASH_REDIS_REST_URL=https://your-database.upstash.io
UPSTASH_REDIS_REST_TOKEN=AXxxxxxxxxxxxxxxxxxxxxxxxxxxxx

プロジェクトのセットアップ

Antigravity のターミナルで、Hono フレームワークを使った Cloudflare Workers プロジェクトを作成します。Antigravity のエージェントに依頼すると、ボイラープレートを一瞬で生成してくれます。

# プロジェクト作成
npm create hono@latest my-edge-api -- --template cloudflare-workers
cd my-edge-api
 
# Upstash Redis クライアントをインストール
npm install @upstash/redis @upstash/ratelimit

次に wrangler.toml に環境変数を設定します。

# wrangler.toml
name = "my-edge-api"
compatibility_date = "2026-03-01"
 
[vars]
ENVIRONMENT = "production"
 
# シークレットは wrangler secret put で設定
# wrangler secret put UPSTASH_REDIS_REST_URL
# wrangler secret put UPSTASH_REDIS_REST_TOKEN

エッジキャッシュの実装

Upstash Redis をキャッシュレイヤーとして使うことで、データベースへのアクセスを大幅に削減できます。以下は、API レスポンスを Redis にキャッシュするミドルウェアの実装例です。

// src/cache.ts
import { Redis } from "@upstash/redis/cloudflare";
import type { Context, Next } from "hono";
 
// Upstash Redis クライアントの初期化
function getRedis(c: Context): Redis {
  return new Redis({
    url: c.env.UPSTASH_REDIS_REST_URL,
    token: c.env.UPSTASH_REDIS_REST_TOKEN,
  });
}
 
// キャッシュミドルウェア
export function cacheMiddleware(ttlSeconds: number = 300) {
  return async (c: Context, next: Next) => {
    const redis = getRedis(c);
    const cacheKey = `cache:${c.req.url}`;
 
    // キャッシュヒットを試行
    const cached = await redis.get<string>(cacheKey);
    if (cached) {
      // キャッシュヒット — Redis から即座にレスポンスを返す
      return c.json(JSON.parse(cached), 200, {
        "X-Cache": "HIT",
        "X-Cache-TTL": String(ttlSeconds),
      });
    }
 
    // キャッシュミス — オリジンへリクエストを通す
    await next();
 
    // 成功レスポンスをキャッシュに保存
    if (c.res.status === 200) {
      const body = await c.res.clone().text();
      await redis.set(cacheKey, body, { ex: ttlSeconds });
      c.res.headers.set("X-Cache", "MISS");
    }
  };
}
 
// 特定キーのキャッシュを手動で無効化
export async function invalidateCache(
  redis: Redis,
  pattern: string
): Promise<number> {
  const keys = await redis.keys(`cache:${pattern}`);
  if (keys.length === 0) return 0;
 
  // パイプラインで一括削除(ネットワークラウンドトリップを最小化)
  const pipeline = redis.pipeline();
  keys.forEach((key) => pipeline.del(key));
  await pipeline.exec();
 
  return keys.length;
}

X-Cache ヘッダーを付与しているので、レスポンスがキャッシュから返されたのかオリジンから返されたのかを簡単に判別できます。

レート制限の実装

Upstash の @upstash/ratelimit パッケージを使えば、スライディングウィンドウ方式のレート制限をわずか数行で実装できます。

// src/ratelimit.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis/cloudflare";
import type { Context, Next } from "hono";
 
// レート制限ミドルウェア
export function rateLimitMiddleware(
  maxRequests: number = 60,
  windowSeconds: number = 60
) {
  return async (c: Context, next: Next) => {
    const redis = new Redis({
      url: c.env.UPSTASH_REDIS_REST_URL,
      token: c.env.UPSTASH_REDIS_REST_TOKEN,
    });
 
    const ratelimit = new Ratelimit({
      redis,
      // スライディングウィンドウ: windowSeconds 秒間に maxRequests 回まで
      limiter: Ratelimit.slidingWindow(maxRequests, `${windowSeconds} s`),
      analytics: true, // Upstash Console でアナリティクスを確認可能
    });
 
    // クライアントの識別子(IP アドレスまたは API キー)
    const identifier =
      c.req.header("X-API-Key") ||
      c.req.header("CF-Connecting-IP") ||
      "anonymous";
 
    const { success, limit, remaining, reset } =
      await ratelimit.limit(identifier);
 
    // レート制限ヘッダーを常に付与
    c.res.headers.set("X-RateLimit-Limit", String(limit));
    c.res.headers.set("X-RateLimit-Remaining", String(remaining));
    c.res.headers.set("X-RateLimit-Reset", String(reset));
 
    if (!success) {
      // レート制限超過 — 429 Too Many Requests を返す
      return c.json(
        {
          error: "Too Many Requests",
          message: `Rate limit exceeded. Try again after ${new Date(reset).toISOString()}`,
          retryAfter: Math.ceil((reset - Date.now()) / 1000),
        },
        429
      );
    }
 
    await next();
  };
}

スライディングウィンドウ方式は、固定ウィンドウ方式と比べて境界付近でのバースト(突発的な大量リクエスト)を防げるため、より公平なレート制限が実現できます。

メインアプリケーションへの統合

作成したミドルウェアを Hono アプリケーションに組み込みます。

// src/index.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { cacheMiddleware, invalidateCache } from "./cache";
import { rateLimitMiddleware } from "./ratelimit";
import { Redis } from "@upstash/redis/cloudflare";
 
type Bindings = {
  UPSTASH_REDIS_REST_URL: string;
  UPSTASH_REDIS_REST_TOKEN: string;
};
 
const app = new Hono<{ Bindings: Bindings }>();
 
// グローバルミドルウェア
app.use("*", cors());
app.use("/api/*", rateLimitMiddleware(100, 60)); // 60秒間に100リクエストまで
 
// キャッシュ付きエンドポイント(5分間キャッシュ)
app.get("/api/articles", cacheMiddleware(300), async (c) => {
  // 実際のデータ取得処理(DB や外部 API)
  const articles = await fetchArticlesFromDB();
  return c.json({ articles, timestamp: new Date().toISOString() });
});
 
// キャッシュなしエンドポイント(リアルタイム性が必要なデータ)
app.get("/api/stats", async (c) => {
  const redis = new Redis({
    url: c.env.UPSTASH_REDIS_REST_URL,
    token: c.env.UPSTASH_REDIS_REST_TOKEN,
  });
 
  // Redis をリアルタイムカウンターとして使用
  const pageViews = await redis.incr("stats:pageviews");
  return c.json({ pageViews });
});
 
// キャッシュ無効化エンドポイント(管理者用)
app.post("/api/cache/purge", async (c) => {
  const redis = new Redis({
    url: c.env.UPSTASH_REDIS_REST_URL,
    token: c.env.UPSTASH_REDIS_REST_TOKEN,
  });
 
  const deleted = await invalidateCache(redis, "*articles*");
  return c.json({ purged: deleted });
});
 
// ダミーのデータ取得関数(実際のプロジェクトではDBアクセスに置き換え)
async function fetchArticlesFromDB() {
  return [
    { id: 1, title: "Getting Started with Edge Computing" },
    { id: 2, title: "Redis Patterns for Serverless" },
  ];
}
 
export default app;

Antigravity のエージェントを活用した開発のコツ

Antigravity のエージェントモードを使えば、上記のようなインフラコードの生成・リファクタリングが格段にスムーズになります。

実際の開発で役立つプロンプト例をいくつか紹介します。

# キャッシュ戦略の相談
「このAPIエンドポイントに最適なキャッシュTTLを提案して。
  - /api/articles → 更新頻度: 1日数回
  - /api/user/profile → 更新頻度: ユーザー操作時
  - /api/stats → リアルタイム性が必要」

# レート制限の設計
「以下の要件でレート制限を設計して:
  - 無料ユーザー: 60 req/min
  - Proユーザー: 300 req/min
  - APIキー認証ベースで識別」

Antigravity のエージェントは wrangler.toml の設定や TypeScript の型定義も一括で生成してくれるので、設定漏れを防ぎやすいのも利点です(Antigravity × Hono でサーバーレスAPIを構築する も参考にしてください)。

デプロイとテスト

Wrangler を使ってデプロイし、動作を確認しましょう。

# ローカル開発
npx wrangler dev
 
# シークレットの設定
npx wrangler secret put UPSTASH_REDIS_REST_URL
npx wrangler secret put UPSTASH_REDIS_REST_TOKEN
 
# 本番デプロイ
npx wrangler deploy

デプロイ後、以下のコマンドでキャッシュとレート制限の動作を確認します。

# 1回目: キャッシュ MISS
curl -i https://my-edge-api.your-subdomain.workers.dev/api/articles
# → X-Cache: MISS
 
# 2回目: キャッシュ HIT(高速レスポンス)
curl -i https://my-edge-api.your-subdomain.workers.dev/api/articles
# → X-Cache: HIT
 
# レート制限テスト(100回連続リクエスト)
for i in $(seq 1 105); do
  echo "Request $i: $(curl -s -o /dev/null -w '%{http_code}' https://my-edge-api.your-subdomain.workers.dev/api/articles)"
done
# → 101回目以降で 429 が返る

よくあるエラーと対処法

Upstash 接続エラー

UPSTASH_REDIS_REST_URL または UPSTASH_REDIS_REST_TOKEN が正しく設定されていない場合、以下のようなエラーが出ます。

Error: Unauthorized - Invalid token

wrangler secret list でシークレットが登録されているか確認してください。ローカル開発では .dev.vars ファイルに環境変数を記述します。

キャッシュが更新されない

TTL の設定が長すぎると、データ更新後も古いキャッシュが返され続けます。コンテンツ更新時には /api/cache/purge エンドポイントを叩くか、Write-Through キャッシュパターンを採用してください。

レート制限が厳しすぎる/緩すぎる

Upstash Console のアナリティクスダッシュボードで実際のリクエスト分布を確認し、maxRequestswindowSeconds の値を調整しましょう。analytics: true を設定しておくと、Upstash Console から視覚的にトラフィックパターンを分析できます。

まとめ

Antigravity と Upstash Redis を組み合わせることで、Cloudflare Workers 上にエッジキャッシュとレート制限を備えた高速・安全な API を構築できます。

本記事で扱ったポイントを整理すると、以下のとおりです。

  1. Upstash Redis は HTTP REST API でアクセスできるため、TCP が使えないエッジ環境でも利用可能
  2. キャッシュミドルウェア でデータベースの負荷を大幅に削減し、レスポンス速度を向上
  3. レート制限ミドルウェア でスライディングウィンドウ方式の公平なアクセス制御を実現
  4. Antigravity のエージェント がインフラコードの生成・設定を支援し、開発効率を向上

次のステップとして、Antigravity でセキュアな API バックエンドを設計する を読んで、認証・認可の実装も合わせて進めてみてください。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-06-14
エッジキャッシュが Next.js の空ページを固定化していた原因と、cache-worker のガード設計
ユーザーから「時々読み込みエラーになる」と報告されるのに手元では再現しない。SSR の例外が HTTP 200 で配信され、それをエッジキャッシュが固定化していた原因を Antigravity のエージェントで切り分け、cache-worker にキャッシュ拒否ガードを実装した記録です。
アプリ開発2026-04-28
Antigravity で SaaS を丸ごと作る — Stripe 課金・認証・デプロイを1つのIDEで完結させる
Antigravity IDE だけで SaaS プロダクトを構築する全工程を解説します。Supabase認証、Stripe課金、Cloudflare Workersデプロイまで、IDEを離れずに完結させる実践ガイドです。
アプリ開発2026-04-27
AntigravityでWebhook受信エンドポイントを取りこぼしなく作る実践パターン
StripeやGitHubからのWebhookを確実に処理するエンドポイントの設計・実装・テストを、Antigravity を使って効率的に進めるための実践パターンをまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →