ExtrasRate Limits (API Calls)

Extras

Rate Limits (API Calls)

To prevent abuse, it’s recommended to limit the number of API calls a user can perform in a given time frame based on their IP address. In this example, we’ll be limiting it to 5 API calls per minute using Upstash.

You can find an example of how the middleware.ts file should look like at the end of this page.

  1. Login to your Upstash account or create a new one [here].

  2. Create a new Redis database.

  3. In the DETAILS section of the database, copy the UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN

  4. Update the following variables inside the .env.local in the codebase:

.env.local
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
  1. In the codebase, run the following command to install the @upstash/ratelimit package:
npm install @upstash/redis @upstash/ratelimit
  1. In the middleware.ts file, add the RATE_LIMITED_URLS array outside of the middleware function. This array contains the URLs that will be rate limited. You can add more URLs to the array if you want to rate limit more endpoints.
middleware.ts
const RATE_LIMITED_URLS = ["/api/example-call"];
  1. In the middleware.ts file, add the redis client with the UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN outside of the middleware function:
middleware.ts
const redis = new Redis({
    url: process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL,
    token: process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN,
});
  1. In the middleware.ts file, add the rateLimit outside of the middleware function. In our case, we’ll be limiting it to 5 API calls per minute (60 seconds). If a user makes more than 5 API calls in a minute, they will receive a 429 Too Many Requests response.
middleware.ts
const ratelimit = new Ratelimit({
    redis: redis,
    limiter: Ratelimit.slidingWindow(5, "60 s"),
});
  1. In the middleware.ts file, add function to check if the URL is rate limited and return the appropriate response.
middleware.ts
if (RATE_LIMITED_URLS.some((url) => request.nextUrl.pathname.startsWith(url))) {
    const ip = request.ip ?? "127.0.0.1";
    const { success } = await ratelimit.limit(ip);
 
    if (!success) {
        return new nextResponse("Too Many Requests", { status: 429 });
    }
}
⚠️

Please add this if statement inside the middleware function BUT before the handleRedirection function. Otherwise, the rate limit will not work as it will be executed after the API call has been made.

Here’s an example of how the middleware.ts file should look like:

middleware.ts
import { Redis } from "@upstash/redis";
import { Ratelimit } from "@upstash/ratelimit";
 
const RATE_LIMITED_URLS = ["/api/example-call"];
 
...
 
const redis = new Redis({
    url: process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_URL,
    token: process.env.NEXT_PUBLIC_UPSTASH_REDIS_REST_TOKEN,
});
 
const ratelimit = new Ratelimit({
    redis: redis,
    limiter: Ratelimit.slidingWindow(5, "60 s"),
});
 
export const middleware = async (request: nextRequest) => {
    ...
 
    const {
        data: { user },
    } = await supabaseClient.auth.getUser();
 
    if (RATE_LIMITED_URLS.some((url) => request.nextUrl.pathname.startsWith(url))) {
        const ip = request.ip ?? "127.0.0.1";
        const { success } = await ratelimit.limit(ip);
 
        if (!success) {
            return new nextResponse("Too Many Requests", { status: 429 });
        }
    }
 
    const routingResponse = await handleRedirection({ request, user });
 
    if (routingResponse) return routingResponse;
 
    ...
};