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:
- Primary Key:
apiKey
(String) -
Attributes:
requestCount
(Number),timestamp
(Number)
2. Create Lambda Function
- Set Up the Project Create a new directory and initialize it:
mkdir rate-limiter
cd rate-limiter
npm init -y
npm install aws-sdk
-
Create the Lambda Function Create
index.js
in therate-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" }),
};
}
};
- 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
- Create API Gateway Create a REST API in API Gateway.
- Create Usage Plans and API Keys
- Create a usage plan in API Gateway with request quotas and throttling limits.
- Associate API keys with the usage plan.
- Integrate Lambda with API Gateway
-
Create a resource and method (e.g.,
GET /endpoint
) in API Gateway. -
Set up the method to trigger the
rateLimiter
Lambda function. - Enable API Key requirement for the method.
4. Configure API Gateway to Use Lambda Authorizer
Use Lambda as a custom authorizer for your API Gateway:
-
Create Lambda Authorizer In the API Gateway
console, create a new Lambda authorizer that invokes your
rateLimiter
function. - Attach Authorizer to Methods Attach the Lambda authorizer to the methods you want to protect with rate limiting.
5. Test the Rate Limiting
-
Allow Requests: Send requests with the
x-api-key
header until the limit is reached. -
Deny Excess Requests: Ensure that further requests
within the same time window return
429 Too Many Requests
.
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.