🔧

Next.jsでのRate Limitingの実装

2023/12/31に公開

はじめに

アプリケーションにおいて、Rate Limitingはとても重要な機能です。
Next.jsでの実装はとても簡単なので、本記事ではUpstashというサービスを使用して、Next.jsでのRate Limitingの実装方法を紹介します。

技術スタック

  • Next.js
  • Upstash
  • Redis
  • tRPC

Upstashとは

Upstashは、Redisをサーバーレスで提供するサービスです。
とても手軽にRedisを使用することができ、無料枠もあるのでおすすめです。

1. 環境変数の設定

まずUpstashのアカウントを作成し、Redisのデータベースを作成します。
データベースの作成

続いて、データベースの接続情報を環境変数に設定します。
図のように、REST APIの項目にて、.envの内容をコピーしして自分のプロジェクトの.envに貼り付けます。
データベースの接続情報

2. Rate Limitingの実装

まずUpstashのライブラリーをインストールします。

bun install @upstash/ratelimit @upstash/redis

続いて、サンプルコードのように、RatelimitRedisをインポートし、Ratelimitを初期化します。
この設定では、60秒間に1回のリクエストを許可するように設定しています。

import {postRouter} from "~/server/api/routers/post";
import {createTRPCRouter} from "~/server/api/trpc";
+ import {Ratelimit} from "@upstash/ratelimit";
+ import {Redis} from "@upstash/redis";

/**
 * This is the primary router for your server.
 *
 * All routers added in /api/routers should be manually added here.
 */
export const appRouter = createTRPCRouter({
    post: postRouter,
});

+ export const rateLimiter = new Ratelimit({
+     redis: Redis.fromEnv(),
+     limiter: Ratelimit.slidingWindow(1, "60 s")
+ });

// export type definition of API
export type AppRouter = typeof appRouter;

続いて、サンプルコードのようにRate Limitingを実装したいAPIの関数にて、rateLimiterを使用します。
このAPIは、ユーザーIDごとに60秒間に1回のリクエストを許可するように設定しています。
リクエストが多すぎる場合は、TOO_MANY_REQUESTSのエラーを返します。

import {rateLimiter} from "~/server/api/root";
import {TRPCError} from "@trpc/server";

export const postRouter = createTRPCRouter({
    // ...省略
    
    create: protectedProcedure
        .input(z.object({name: z.string().min(1)}))
        .mutation(async ({ctx, input}) => {
+            const {success} = await rateLimiter.limit(ctx.session.user.id);
+            if (!success) {
+                 throw new TRPCError({code: "TOO_MANY_REQUESTS"});
+            }

            // simulate a slow db call
            await new Promise((resolve) => setTimeout(resolve, 1000));

            await ctx.db.insert(posts).values({
                name: input.name,
                createdById: ctx.session.user.id,
            });
        }),

    // ...省略

3. 動作確認

続いて、実際に動作確認を行います。
アプリを起動後にログインし、適当に投稿を作成します。
その後、60秒以内に再度投稿を作成しようとすると、TOO_MANY_REQUESTSのエラーが発生することが確認できます。

まとめ

Next.jsでのRate Limitingの実装はとても簡単でした。
Upstashを使用することで、Redisの管理も簡単に行うことができます。
ぜひ、Next.jsでのRate Limitingの実装にUpstashをお試しください。

Discussion