Skip to main content

A request rate limiter for fastapi

Project description

fastapi-limiter-valkey

pypi license workflows workflows

Introduction

FastAPI-Limiter-Valkey is a rate limiting tool for fastapi routes with lua script.

It is a friendly fork from FastAPI-Limiter and adapted to use Valkey.

Requirements

Install

Just install from pypi

> pip install fastapi-limiter-valkey

Quick Start

FastAPI-Limiter-Valkey is simple to use, which just provide a dependency RateLimiter, the following example allow 2 times request per 5 seconds in route /.

import valkey.asyncio as vk
import uvicorn
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI

from fastapi_limiter import FastAPILimiter
from fastapi_limiter.depends import RateLimiter

@asynccontextmanager
async def lifespan(_: FastAPI):
    valkey_connection = vk.from_url("valkey://localhost:6379", encoding="utf8")
    await FastAPILimiter.init(valkey_connection)
    yield
    await FastAPILimiter.close()

app = FastAPI(lifespan=lifespan)

@app.get("/", dependencies=[Depends(RateLimiter(times=2, seconds=5))])
async def index():
    return {"msg": "Hello World"}


if __name__ == "__main__":
    uvicorn.run("main:app", debug=True, reload=True)

Usage

There are some config in FastAPILimiter.init.

valkey

The async valkey instance.

prefix

Prefix of valkey key.

identifier

Identifier of route limit, default is ip, you can override it such as userid and so on.

async def default_identifier(request: Request):
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        return forwarded.split(",")[0]
    return request.client.host + ":" + request.scope["path"]

callback

Callback when access is forbidden, default is raise HTTPException with 429 status code.

async def default_callback(request: Request, response: Response, pexpire: int):
    """
    default callback when too many requests
    :param request:
    :param pexpire: The remaining milliseconds
    :param response:
    :return:
    """
    expire = ceil(pexpire / 1000)

    raise HTTPException(
        HTTP_429_TOO_MANY_REQUESTS, "Too Many Requests", headers={"Retry-After": str(expire)}
    )

Multiple limiters

You can use multiple limiters in one route.

@app.get(
    "/multiple",
    dependencies=[
        Depends(RateLimiter(times=1, seconds=5)),
        Depends(RateLimiter(times=2, seconds=15)),
    ],
)
async def multiple():
    return {"msg": "Hello World"}

Not that you should note the dependencies orders, keep lower of result of seconds/times at the first.

Rate limiting within a websocket.

While the above examples work with rest requests, FastAPI also allows easy usage of websockets, which require a slightly different approach.

Because websockets are likely to be long lived, you may want to rate limit in response to data sent over the socket.

You can do this by rate limiting within the body of the websocket handler:

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    ratelimit = WebSocketRateLimiter(times=1, seconds=5)
    try:
        while True:
            try:
                data = await websocket.receive_text()
                await ratelimit(websocket, context_key=data)  # NB: context_key is optional
                await websocket.send_text("Hello, world")
            except HTTPException:
                await websocket.send_text("Hello again")
    except WebSocketDisconnect:
        print("Client disconnected")
    finally:
        await websocket.close()

Lua script

The lua script used.

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2]

local current = tonumber(server.call('get', key) or "0")
if current > 0 then
    if current + 1 > limit then
        return server.call("PTTL", key)
    else
        server.call("INCR", key)
        return 0
    end
else
    server.call("SET", key, 1, "px", expire_time)
    return 0
end

License

This project is licensed under the Apache-2.0 License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_limiter_valkey-0.1.2.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_limiter_valkey-0.1.2-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_limiter_valkey-0.1.2.tar.gz.

File metadata

  • Download URL: fastapi_limiter_valkey-0.1.2.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fastapi_limiter_valkey-0.1.2.tar.gz
Algorithm Hash digest
SHA256 9c3127c9af963201e081a266199a8bf2b7ff8c4cc2eb36290f886749b5fd7d6e
MD5 9bebd9afc3ec0cae91c39e9a9c55822c
BLAKE2b-256 1fae634dbea137b527da6a0df32a4ab70cf3bc7a37e9ad041080d069680f6a4e

See more details on using hashes here.

File details

Details for the file fastapi_limiter_valkey-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_limiter_valkey-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4ca43f98b90b7f0e2c5b0e2c5333f0eb3aa9cbdd85194a6a9d8053b07b5d165b
MD5 fe66b70ffa3775de11c34ac35c85d405
BLAKE2b-256 da158c75dbc7d9278a26c1aa6988621c53e0199e2b06c0982fe2b1ee7feea63c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page