Adding A Rate Limiter Middleware To A Robyn Server | Python
In this article, we are going to learn how to add a rate limiter middleware to a Robyn server through robyn-rate-limits
, a plugin developed by IdoKendo.
Requirements
Python 3 installed
Pip installed
Rate Limiter
According to this article, published by CloudFlare, a rate limiter is a strategy for limiting network traffic. It puts a cap on how often someone can repeat an action within a certain timeframe – for instance, trying to log in to an account. Rate limiting can help stop certain kinds of malicious bot activity. It can also reduce strain on web servers.
Rate limiting is often employed to stop bad bots from negatively impacting a website or application. Bot attacks that rate limiting can help mitigate include Brute force attacks, DoS and DDoS attacks and Web scraping.
Rate limiting also protects against API overuse, which is not necessarily malicious or due to bot activity, but is important to prevent nonetheless.
Robyn Rate Limiter Plugin
According to the documentation, the rate limiter plugin enables you to implement rate limiting for your Robyn application's routes. It helps prevent abuse, and brute-force attacks and ensures fair usage of your resources.
To use this plugin, we have to install it first:
pip install robyn robyn-rate-limits
We create a python file, app.py
to create a Robyn server.
from robyn import Robyn, Robyn
from robyn_rate_limits import InMemoryStore
from robyn_rate_limits import RateLimiter
app = Robyn(__file__)
limiter = RateLimiter(store=InMemoryStore, calls_limit=3, limit_ttl=100)
@app.before_request()
def middleware(request: Request):
return limiter.handle_request(app, request)
@app.get("/")
def h():
return "Hello, World!"
app.start(port=8080)
In the example above (taken from the documentation), the robyn-rate-limits
plugin is used to enforce a rate limit of 3 requests per 100-seconds window for specific routes. If a client exceeds this limit, they will receive a "Too many requests" message.
We start our server as usually do, by running py app.py
command in our console.
Now, we have to create a python script, to test the rate limiter.
test_limiter.py
For this script we have to import the requests
library.
import requests
import time
def test_rate_limiter(url, rate_limit, time_window):
"""Tests a rate limiter with the given parameters."""
start_time = time.time()
allowed_requests = 0
blocked_requests = 0
while time.time() - start_time < time_window:
try:
response = requests.get(url)
response.raise_for_status() # Raise an exception for non-200 status codes
allowed_requests += 1
except requests.exceptions.RequestException as e:
blocked_requests += 1
print(f"Request blocked: {e}")
time.sleep(time_window / rate_limit) # Delay to respect the rate limit
print(f"Allowed requests: {allowed_requests}")
print(f"Blocked requests: {blocked_requests}")
# Example usage:
url = "http://localhost:8080/" # Replace with the actual URL
rate_limit = 3 # Requests per second
time_window = 5 # Seconds
test_rate_limiter(url, rate_limit, time_window)
In the example above, we define the test_rate_limiter() function with three parameters: url
, rate_limit
and time_window
.
This program makes requests to an URL and tracks allowed and blocked requests. response.raise_for_status()
is if the status code in the response is different from a successful status code(200), it will raise an exception. And it will print the exception, in our case, it should be a "Too many request" message. time.sleep
pauses execution to respect the rate limit.
We set the url
to the URL address where our Robyn server is receiving requests, rate_limit
to 3, and the time_window
to 5.
We run this program, executing this command in another terminal: py test_limiter.py
.
Now, we should receive the following response in our console:
Conclusion
This is an easy to use and an useful plugin that allow us to build more resilient services with Robyn. Also, this plugin has a feature that uses Redis to store the calls, you can take a look to the plugin's repository for an example of how to use it.
Thank you for taking the time to read this article.
If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through Twitter, or LinkedIn.