Advanced

Claude Codeでレート制限を実装する方法

Claude Codeを活用してAPIのレート制限を効率的に実装。トークンバケット、スライディングウィンドウなどのアルゴリズムを実践コードで解説。

なぜレート制限が必要か

APIを公開する際、レート制限はサービスの安定運用に不可欠です。DDoS攻撃の防御、リソースの公平な配分、コスト管理など、多くの目的で使われます。Claude Codeを使えば、要件に合ったレート制限の実装を短時間で生成できます。

トークンバケットアルゴリズム

もっとも一般的なレート制限アルゴリズムをTypeScriptで実装します。

> トークンバケットアルゴリズムでレート制限を実装して。
> Redisを使ったスケーラブルな実装にして。
import Redis from "ioredis";

const redis = new Redis();

interface RateLimitResult {
  allowed: boolean;
  remaining: number;
  resetAt: number;
}

export async function checkRateLimit(
  key: string,
  maxTokens: number,
  refillRate: number, // トークン/秒
  windowSeconds: number
): Promise<RateLimitResult> {
  const now = Date.now();
  const luaScript = `
    local key = KEYS[1]
    local max_tokens = tonumber(ARGV[1])
    local refill_rate = tonumber(ARGV[2])
    local now = tonumber(ARGV[3])
    local window = tonumber(ARGV[4])

    local data = redis.call('HMGET', key, 'tokens', 'last_refill')
    local tokens = tonumber(data[1]) or max_tokens
    local last_refill = tonumber(data[2]) or now

    -- トークンの補充
    local elapsed = (now - last_refill) / 1000
    tokens = math.min(max_tokens, tokens + elapsed * refill_rate)

    local allowed = tokens >= 1
    if allowed then
      tokens = tokens - 1
    end

    redis.call('HMSET', key, 'tokens', tokens, 'last_refill', now)
    redis.call('EXPIRE', key, window)

    return {allowed and 1 or 0, math.floor(tokens), now + math.floor((1 - tokens) / refill_rate * 1000)}
  `;

  const result = await redis.eval(
    luaScript, 1, key,
    maxTokens, refillRate, now, windowSeconds
  ) as number[];

  return {
    allowed: result[0] === 1,
    remaining: result[1],
    resetAt: result[2],
  };
}

Express ミドルウェアとして使う

上記のロジックをExpressミドルウェアに組み込みます。

import { Request, Response, NextFunction } from "express";
import { checkRateLimit } from "./rate-limiter";

interface RateLimitOptions {
  maxRequests: number;
  windowSeconds: number;
  keyGenerator?: (req: Request) => string;
}

export function rateLimit(options: RateLimitOptions) {
  const {
    maxRequests,
    windowSeconds,
    keyGenerator = (req) => req.ip || "unknown",
  } = options;

  return async (req: Request, res: Response, next: NextFunction) => {
    const key = `rate_limit:${keyGenerator(req)}`;
    const result = await checkRateLimit(
      key, maxRequests, maxRequests / windowSeconds, windowSeconds
    );

    res.setHeader("X-RateLimit-Limit", maxRequests);
    res.setHeader("X-RateLimit-Remaining", result.remaining);
    res.setHeader("X-RateLimit-Reset", Math.ceil(result.resetAt / 1000));

    if (!result.allowed) {
      return res.status(429).json({
        error: "Too Many Requests",
        message: "リクエスト数が上限に達しました。しばらく待ってから再試行してください。",
        retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000),
      });
    }

    next();
  };
}

// 使用例
import express from "express";
const app = express();

// API全体に適用:1分あたり60リクエスト
app.use("/api", rateLimit({ maxRequests: 60, windowSeconds: 60 }));

// 認証エンドポイントはより厳しく:1分あたり5リクエスト
app.use("/api/auth", rateLimit({
  maxRequests: 5,
  windowSeconds: 60,
  keyGenerator: (req) => `auth:${req.ip}`,
}));

Redisなしの簡易実装

小規模なプロジェクトではインメモリでの実装も有効です。

const requestCounts = new Map<string, { count: number; resetAt: number }>();

export function simpleRateLimit(maxRequests: number, windowMs: number) {
  // 定期的にクリーンアップ
  setInterval(() => {
    const now = Date.now();
    for (const [key, data] of requestCounts) {
      if (data.resetAt < now) requestCounts.delete(key);
    }
  }, windowMs);

  return (req: Request, res: Response, next: NextFunction) => {
    const key = req.ip || "unknown";
    const now = Date.now();
    const record = requestCounts.get(key);

    if (!record || record.resetAt < now) {
      requestCounts.set(key, { count: 1, resetAt: now + windowMs });
      return next();
    }

    if (record.count >= maxRequests) {
      return res.status(429).json({ error: "Too Many Requests" });
    }

    record.count++;
    next();
  };
}

レート制限と組み合わせて検索機能を実装する方法は検索機能の実装をご覧ください。APIの設計全般についてはClaude Codeの入門ガイドも参考になります。

まとめ

Claude Codeを使えば、トークンバケットからRedis連携まで、プロジェクトに合ったレート制限を素早く実装できます。セキュリティ要件を自然言語で伝えれば、適切なアルゴリズムと設定値を提案してくれます。

詳しくはClaude Code公式ドキュメントを参照してください。

#Claude Code #レート制限 #API #セキュリティ #Node.js