In this guide, we'll explore a streamlined approach to rate limit users using recently released Netlify Blobs. By the end, you'll have an edge function that'd rate limit users based on their IP Address.
Setup a Node.js Project
Let's start by creating a directory and initializing a Node.js project:
mkdir rate-limiter
npm init -y
Install Netlify Blobs
Install Netlify Blobs
package to manage data storage of usage per ip address to rate limit the users with.
npm i @netlify/blobs
Setup Netlify Edge Functions
Get started by creating Netlify Edge Functions by creating the default netlify/edge-functions
directory with a index.js
file as one of the edge function(s).
mkdir netlify/edge-functions
touch index.js
Setup Netlify Configuration
Create a netlify.toml
at the root of your project with the following content:
[[edge_functions]]
function = "index"
path = "/*"
[build]
publish="."
The code above makes sure that index.js
is used to serve incoming requests for all paths on your deployment.
Set Rate Limiting Config
In the newly created index.js
, set the maximum number of reuqests (here, maxUpdates
) in the set interval (here, timeSpan
) that do not exceed the rate limits.
// File: index.js
const rateLimitConfig = { maxUpdates: 3, timeSpan: 86400 }
export default async (_, context) => {
// Rate limiting logic here
}
Create Unique User Identifier
Retrieve the user's IP address from the Netlify Edge Functions context object
Use the IP address as a unique identifier for rate limiting via creating the
identifier
Load the store (here, named
visits
) that keeps the collection of all the unique idenitifersTry to look for an existing record for the particular identifier
// File: index.js
import { getStore } from '@netlify/blobs'
export default async (_, context) => {
// Create a unique identifier based on user's IP
const identifier = 'limiter_' + context.ip
// Get the visits store
const visits = getStore('visits')
const t = await visits.get(identifier)
// If a rate limiting key is found
if (t) {
// Continue Rate limiting logic here
}
else {
// Continue Rate limiting logic here
}
}
Flow of Rate Limiting based on the Stored Value of User Usage Record
If a rate limiting key is found for the user's IP:
- Retrieve the rate limit data for the key
- Calculate the time difference since the last update
- Reset the count if the time window has passed
- Check if the request count is below the limit
- Increment the count if within the limit
- Return appropriate responses based on the conditions
// File: index.js
// If a rate limiting key is found
if (t) {
// Get rate limit data for the key
const { count_updates, last_update } = JSON.parse(t)
// Calculate time difference in seconds
const currentTime = new Date().getTime()
const timeDifference = Math.floor((currentTime - new Date(last_update).getTime()) / 1000)
// If time window has passed, reset count
if (timeDifference >= rateLimitConfig.timeSpan) {
await visits.set(identifier, JSON.stringify({ count_updates: 1, last_update: currentTime }))
// Continue with your processing
return new Response(`Reload 2 more times to exceed the rate limit.`)
}
// Check if the request count is below the limit
if (count_updates < rateLimitConfig.maxUpdates) {
// Increment the number of updates in the store
await visits.set(identifier, JSON.stringify({ count_updates: count_updates + 1, last_update: new Date().getTime() }))
// Continue with your processing
return new Response(`Reload ${rateLimitConfig.maxUpdates - count_updates} more time(s) to exceed the rate limit.`)
} else {
// If the limits equal or exceeds, return with a rate limit exceeded message
return new Response(`Rate limit exceeded.`)
}
}
else {
// If a key is not found, set the key with a single update and continue
}
If no rate limiting key is found:
- Sets a new key with a single update for the user
// File: index.js
// If a rate limiting key is found
if (t) {
// Continue Rate limiting logic here
}
else {
// If a key is not found, set the key with a single update and continue
await visits.set(identifier, JSON.stringify({ count_updates: 1, last_update: new Date().getTime() }))
return new Response(`Reload 2 more times to exceed the rate limit.`)
}
Deployment and Live Demo
All done, let's deploy our rate limiter now!
Deploying to Netlify
# Deploy to Netlify
netlify deploy --prod
Live Demo
Explore the live example at tryblobs.netlify.app, and witness the Rate Limiter in action.
Top comments (0)