In this tutorial, we will deploy a AWS Lambda function ratelimited based on the client’s IP address using @upstash/ratelimit and Serverless Framework.

Prerequisites

  1. Install the Serverless Framework with npm i serverless -g

Project Setup

Create a Serverless Framework application with the following options:

➜  tutorials > ✗ serverless
Serverless ϟ Framework

Welcome to Serverless Framework V.4

Create a new project by selecting a Template to generate scaffolding for a specific use-case.

✔ Select A Template: · AWS / Node.js / HTTP API

✔ Name Your Project: · ratelimit-serverless

✔ Template Downloaded

✔ Create Or Select An Existing App: · Create A New App

✔ Name Your New App: · ratelimit-serverless

Your new Service "ratelimit-serverless" is ready. Here are next steps:

• Open Service Directory: cd ratelimit-serverless
• Install Dependencies: npm install (or use another package manager)
• Deploy Your Service: serverless deploy
cd ratelimit-serverless

Create package.json with @upstash/ratelimit as a dependency:

package.json
{
    "dependencies": {
      "@upstash/ratelimit": "latest",
      "@upstash/redis": "latest"
    }
  }

Install the dependencies:

npm install

Database Setup

Create a Redis database using Upstash Console or Upstash CLI and copy the UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN into your .env file.

.env
UPSTASH_REDIS_REST_URL=<YOUR_URL>
UPSTASH_REDIS_REST_TOKEN=<YOUR_TOKEN>

Ratelimited Function Setup

Update handler.js:

handler.js
const { Ratelimit } = require("@upstash/ratelimit");
const { Redis } = require("@upstash/redis");

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"),
  prefix: "@upstash/ratelimit",
  analytics: true,
});

exports.ratelimit = async (event) => {
  const identifier = event.requestContext.http.sourceIP;
  const { success, limit, remaining, pending } = await ratelimit.limit(
    identifier
  );
  const response = {
    success: success,
    limit: limit,
    remaining: remaining,
  };

  // pending is a promise for handling the analytics submission
  await pending;

  if (!success) {
    return {
      statusCode: 429,
      body: JSON.stringify(response),
    };
  }
  return {
    statusCode: 200,
    body: JSON.stringify(response),
  };
};

Update serverless.yml to pass the environment variables:

serverless.yml
service: ratelimit-serverless

provider:
  name: aws
  runtime: nodejs20.x
  environment:
    UPSTASH_REDIS_REST_URL: ${env:UPSTASH_REDIS_REST_URL}
    UPSTASH_REDIS_REST_TOKEN: ${env:UPSTASH_REDIS_REST_TOKEN}

functions:
  ratelimit:
    handler: handler.ratelimit
    events:
      - httpApi:
          path: /
          method: get

Developing

Run the following command to start your dev session.

serverless dev

Deployment

Run the following command to deploy your service.

serverless deploy

Visit the output url.