I want to configure rate limiting with SlowAPI (in-memory, without Redis Cache etc.), but I don't want to add the @limiter.limit()
decorator seperately for every endpoint.
So, something I don't want to do manually would be:
@limiter.limit("5/minute")
async def myendpoint(request: Request)
pass
So, essentially, I want to include it in a middleware:
from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
@app.middleware("http")
async def check_request(request: Request, call_next):
client_ip = request.client.host
prefix = "request_rate_limiter." + client_ip
#... (logic from slowapi to get allowed flag)
if allowed:
response = await call_next(request)
return response
But I didn't find a solution on how to receive a boolean from the limiter.
How would I proceed from this and would this work?
It would be great if I could configure it for different routes and also for example depending on a user subscription (e.g. free/premium).
Thanks!
To apply a global (default) limit to all routes, you could use the SlowAPIMiddleware
, as shown in the example below. The relevant documentation could be found here.
Related answers could also be found here and here.
from fastapi import FastAPI
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.middleware import SlowAPIMiddleware
from slowapi.errors import RateLimitExceeded
limiter = Limiter(key_func=get_remote_address, default_limits=["1/minute"])
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)
@app.get("/")
async def main():
return "Only once per minute"
To exempt a route from the global limit, you could use the @limiter.exempt
decorator on a given route, as shown in the following example. However, it seems that, currently, the decorator would only work for endpoints defined with normal def
instead of async def
(it could be a bug in the relevant implementation of SlowAPI—UPDATE: The issue has been fixed, so please make sure to upgrade to the latest version of SlowAPI).
@app.get("/someroute")
@limiter.exempt
async def someroute():
return "I'm unlimited"