profile

Create an API rate limiter using AWS Lambda, API Gateway, and DynamoDB

To create an API rate limiter using AWS Lambda, API Gateway, and DynamoDB, you can follow these steps. This solution will enforce rate limiting on your API to control the number of requests a user can make in a given timeframe.

1. Set Up DynamoDB Table

Create a DynamoDB table named RateLimits with the following schema:

2. Create Lambda Function

  1. Set Up the Project Create a new directory and initialize it:
   mkdir rate-limiter
   cd rate-limiter
   npm init -y
   npm install aws-sdk
  1. Create the Lambda Function Create index.js in the rate-limiter directory:
   // index.js
   const AWS = require("aws-sdk");
   const dynamo = new AWS.DynamoDB.DocumentClient();
   const TABLE_NAME = "RateLimits";
   const RATE_LIMIT = 100; // Max requests
   const TIME_WINDOW = 60 * 1000; // 1 minute in milliseconds
   exports.handler = async (event) => {
     const apiKey = event.headers["x-api-key"];
     const currentTime = Date.now();
     const params = {
       TableName: TABLE_NAME,
       Key: {
         apiKey: apiKey,
       },
     };
     let rateLimitData;
     try {
       rateLimitData = await dynamo.get(params).promise();
     } catch (error) {
       console.error("Error fetching rate limit data:", error);
       return {
         statusCode: 500,
         body: JSON.stringify({ message: "Internal Server Error" }),
       };
     }
     if (
       !rateLimitData.Item ||
       currentTime - rateLimitData.Item.timestamp > TIME_WINDOW
     ) {
       const newItem = {
         apiKey: apiKey,
         requestCount: 1,
         timestamp: currentTime,
       };
       try {
         await dynamo.put({ TableName: TABLE_NAME, Item: newItem }).promise();
       } catch (error) {
         console.error("Error updating rate limit data:", error);
         return {
           statusCode: 500,
           body: JSON.stringify({ message: "Internal Server Error" }),
         };
       }
       return {
         statusCode: 200,
         body: JSON.stringify({ message: "Request allowed" }),
       };
     } else if (rateLimitData.Item.requestCount < RATE_LIMIT) {
       const updatedItem = {
         ...rateLimitData.Item,
         requestCount: rateLimitData.Item.requestCount + 1,
       };
       try {
         await dynamo
           .put({ TableName: TABLE_NAME, Item: updatedItem })
           .promise();
       } catch (error) {
         console.error("Error updating rate limit data:", error);
         return {
           statusCode: 500,
           body: JSON.stringify({ message: "Internal Server Error" }),
         };
       }
       return {
         statusCode: 200,
         body: JSON.stringify({ message: "Request allowed" }),
       };
     } else {
       return {
         statusCode: 429,
         body: JSON.stringify({ message: "Too Many Requests" }),
       };
     }
   };
  1. Deploy the Lambda Function Zip the contents and upload it to AWS Lambda or use the AWS CLI:
   zip -r function.zip .
   aws lambda create-function --function-name rateLimiter --zip-file fileb://function.zip --handler index.handler --runtime nodejs14.x --role arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_LAMBDA_ROLE

3. Integrate with API Gateway

  1. Create API Gateway Create a REST API in API Gateway.
  2. Create Usage Plans and API Keys
  1. Integrate Lambda with API Gateway

4. Configure API Gateway to Use Lambda Authorizer

Use Lambda as a custom authorizer for your API Gateway:

  1. Create Lambda Authorizer In the API Gateway console, create a new Lambda authorizer that invokes your rateLimiter function.
  2. Attach Authorizer to Methods Attach the Lambda authorizer to the methods you want to protect with rate limiting.

5. Test the Rate Limiting

Final Thoughts

This setup enforces rate limiting using AWS Lambda and DynamoDB, leveraging API Gateway for API management and scalability. This design can be extended to support more complex rate limiting policies and additional features as needed.