はじめに
Web APIなどを公開していると、「短時間に同じユーザーから大量リクエストが来るのを防ぎたい」と思うことはありませんか?
そんな時に便利なのが「レートリミット」です。本記事では、Upstash Redis を使って、簡単かつスケーラブルにレートリミットを実装する方法を紹介します。
🧩 なぜレートリミットが必要?
Gemini API は無料枠があるとはいえ、過剰な呼び出しは課金や制限の原因になります。また、不特定多数のユーザーに公開するアプリでは 悪意ある連打 にも備える必要があります。
🎯 実現したいこと
- 同じユーザー(識別子)からのアクセス回数を制限したい
- 制限回数を超えたら処理をブロックしたい
- 毎日リセットされるようにしたい
そこで、今回は @upstash/redis
を使って簡単に「1ユーザーあたり1日5回まで」という制限を追加してみます。
Redisとは?
Redis(リディス) は、超高速で動作する インメモリ型のデータベース です。
- データをメモリ(RAM)上に保存するため、非常に高速に読み書きできる
- 一時的なカウントやキャッシュ、キュー、セッション管理などに広く使われている
- キーと値の組み合わせでデータを保持する「NoSQL」型データベース
レートリミットのように「回数をカウントして一時的に保持」する用途にぴったりです。
Upstashとは?
Upstash(アップスタッシュ) は、Redisをクラウド上で提供してくれるマネージドサービスです。
特徴として:
- VercelやCloudflare Workersなどのサーバレス環境と相性が良い
- REST APIでRedisにアクセスできる(Redisのクライアント接続が不要)
- 無料プランあり → 個人開発にも嬉しい
- グローバルなエッジネットワークで低レイテンシ
簡単に言えば、
Redisを自分で立ち上げたり管理せずに、Upstashに任せてすぐ使えるようにしたもの
という感じです。
🔗 RedisとUpstashの関係
サービス | 役割 |
---|---|
Redis | 高速なインメモリデータベース(本体) |
Upstash | Redisをクラウドで簡単に使えるようにしたもの |
💡 なぜUpstash Redis?
- REST API経由で使える → VercelやCloudflareなどサーバレス環境でも安心
- 無料枠あり → 個人開発にも最適
- 自動スケーリング → 急なアクセス増にも耐えられる
Upstash Redisのセットアップ
まず Upstash Redis の REST URL と Token を発行し、.env.local
に保存します。
UPSTASH_REDIS_REST_URL=your_redis_url
UPSTASH_REDIS_REST_TOKEN=your_redis_token
インストール:
npm install @upstash/redis
レートリミット関数の実装
import { Redis } from '@upstash/redis'
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL || '',
token: process.env.UPSTASH_REDIS_REST_TOKEN || ''
})
/**
* レートリミットをチェックする関数
* @param identifier IPやユーザーIDなど、識別子
* @returns 制限以内なら true、超えていれば false
*/
export async function checkRateLimit(identifier: string): Promise<boolean> {
const key = `rate_limit:${identifier}`;
const limit = 5; // 1日あたりの最大回数
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, 60 * 60 * 24); // 24時間後に期限切れ
}
return current <= limit;
}
🔍 解説
-
identifier
はIP
やuserId
、email
などに置き換えて使えます。 -
redis.incr(key)
Redisで指定キーの値をインクリメントします。キーがなければ1
に初期化されます。 -
redis.expire(key, seconds)
有効期限を秒単位で指定。ここでは24時間(24 * 60 * 60
)でキーが自動削除されます。 -
current <= limit
現在のアクセス数が制限以内かをチェックします。
📌 補足:identifier
(識別子)をどう設計するか?
識別子 | メリット | デメリット |
---|---|---|
IPアドレス | 実装が簡単、匿名ユーザーでも可 | 同一ネットワークで共有される |
ユーザーID | ログイン済みなら正確 | 匿名ユーザーには使えない |
メールアドレス | 複数端末をまたいでも制御可能 | 利用には認証が必要 |
Gemini 関数との統合例
import type { NextApiRequest, NextApiResponse } from 'next'
import { generateWithGemini } from '@/lib/gemini'
import { checkRateLimit } from '@/lib/rateLimit'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const prompt = req.body.prompt
const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || 'unknown'
const allowed = await checkRateLimit(String(ip))
if (!allowed) {
return res.status(429).json({ error: 'Rate limit exceeded. Try again tomorrow.' })
}
try {
const result = await generateWithGemini({ prompt })
res.status(200).json({ result })
} catch (error) {
res.status(500).json({ error: 'Failed to generate content' })
}
}
おわりに
本記事では、Node.js + Upstash Redis を使ったシンプルなレートリミットの実装方法を紹介しました。
APIの保護やスパム防止に非常に有効なので、ぜひ導入してみてください!