{"id":31539785,"url":"https://github.com/anto18671/fastlimiter","last_synced_at":"2026-05-19T07:33:38.534Z","repository":{"id":257010256,"uuid":"857132754","full_name":"anto18671/fastlimiter","owner":"anto18671","description":"A fast and flexible token bucket rate limiter for FastAPI applications.","archived":false,"fork":false,"pushed_at":"2024-09-13T22:11:22.000Z","size":21,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-04T05:52:58.680Z","etag":null,"topics":["middleware","rate-limit","rate-limiter","rate-limiting","token-based"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/fastlimiter/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anto18671.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-13T21:48:20.000Z","updated_at":"2024-10-16T17:42:42.000Z","dependencies_parsed_at":"2024-09-14T09:59:36.241Z","dependency_job_id":"fc224374-dce6-46b5-9cca-1835dacf53f4","html_url":"https://github.com/anto18671/fastlimiter","commit_stats":null,"previous_names":["anto18671/fastlimiter"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/anto18671/fastlimiter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anto18671%2Ffastlimiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anto18671%2Ffastlimiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anto18671%2Ffastlimiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anto18671%2Ffastlimiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anto18671","download_url":"https://codeload.github.com/anto18671/fastlimiter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anto18671%2Ffastlimiter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278291022,"owners_count":25962673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["middleware","rate-limit","rate-limiter","rate-limiting","token-based"],"created_at":"2025-10-04T09:14:58.127Z","updated_at":"2025-10-04T09:14:59.305Z","avatar_url":"https://github.com/anto18671.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FastLimiter\n\n[![PyPI version](https://img.shields.io/pypi/v/fastlimiter.svg?cacheSeconds=3600)](https://pypi.org/project/fastlimiter/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA fast and flexible token bucket rate limiter for FastAPI applications.\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n  - [Prerequisites](#prerequisites)\n  - [Install via Pip](#install-via-pip)\n  - [Install from Source](#install-from-source)\n- [Quick Start](#quick-start)\n- [Usage](#usage)\n  - [Basic Usage](#basic-usage)\n    - [As Middleware](#as-middleware)\n    - [As Decorator](#as-decorator)\n  - [Advanced Usage](#advanced-usage)\n    - [Custom Key Function](#custom-key-function)\n    - [Collecting Statistics](#collecting-statistics)\n    - [Updating Parameters at Runtime](#updating-parameters-at-runtime)\n- [API Reference](#api-reference)\n  - [RateLimiter Class](#ratelimiter-class)\n    - [Initialization](#initialization)\n    - [Methods](#methods)\n- [Configuration](#configuration)\n- [Examples](#examples)\n  - [Limiting Based on API Key](#limiting-based-on-api-key)\n  - [Custom Callback Function](#custom-callback-function)\n  - [Resetting Rate Limiter for a Specific Client](#resetting-rate-limiter-for-a-specific-client)\n  - [Applying Different Limits to Different Endpoints](#applying-different-limits-to-different-endpoints)\n  - [Limiting by User ID](#limiting-by-user-id)\n  - [Customizing Rate Limit Exceeded Response](#customizing-rate-limit-exceeded-response)\n- [Contributing](#contributing)\n  - [Reporting Bugs](#reporting-bugs)\n  - [Feature Requests](#feature-requests)\n  - [Pull Requests](#pull-requests)\n  - [Code Style](#code-style)\n  - [Testing](#testing)\n- [License](#license)\n- [Contact](#contact)\n\n## Features\n\n- **Flexible Rate Limiting**: Configure rate limits based on tokens, capacity, burst size, and time intervals to suit different scenarios.\n- **Token Bucket Algorithm**: Implements the efficient token bucket algorithm, which is ideal for handling bursts and smoothing out request rates.\n- **FastAPI Integration**: Seamlessly integrates with FastAPI applications through middleware or route decorators.\n- **Per-Client Limiting**: Rate limits are applied per client, identified by IP address or custom keys.\n- **Statistics Collection**: Optionally collect detailed statistics, including allowed and denied requests, which can be used for monitoring and analytics.\n- **Customizable Callbacks**: Add custom functions to execute after each request, allowing for logging, alerting, or other side effects.\n- **Dynamic Configuration**: Update rate limiting parameters at runtime without restarting the application.\n\n## Installation\n\n### Prerequisites\n\n- Python 3.8 or higher\n- FastAPI 0.65.0 or higher\n\n### Install via Pip\n\nInstall FastLimiter from PyPI:\n\n```bash\npip install fastlimiter\n```\n\n### Install from Source\n\nAlternatively, you can clone the repository and install it:\n\n```bash\ngit clone https://github.com/anto18671/fastlimiter.git\ncd fastlimiter\npip install .\n```\n\n## Quick Start\n\nHere's how you can quickly get started with FastLimiter in your FastAPI application:\n\n```python\nfrom fastapi import FastAPI, Request\nfrom fastlimiter import RateLimiter, setup_rate_limiter\n\napp = FastAPI()\n\n# Initialize the rate limiter\nrate_limiter = RateLimiter(rate=10, capacity=100, seconds=60)\n\n# Setup the rate limiter middleware\nsetup_rate_limiter(app, rate_limiter)\n\n@app.get(\"/items\")\nasync def read_items(request: Request):\n    return {\"message\": \"Hello, World!\"}\n```\n\nIn this example, the rate limiter allows up to 100 requests per client per 60 seconds, refilling at a rate of 10 tokens per 60 seconds.\n\n## Usage\n\n### Basic Usage\n\n#### As Middleware\n\nTo apply rate limiting to all incoming requests, use the middleware:\n\n```python\nfrom fastapi import FastAPI\nfrom fastlimiter import RateLimiter, setup_rate_limiter\n\napp = FastAPI()\n\nrate_limiter = RateLimiter(rate=5, capacity=10, seconds=60)\nsetup_rate_limiter(app, rate_limiter)\n```\n\n#### As Decorator\n\nTo apply rate limiting to specific routes, use the `limit` decorator:\n\n```python\nfrom fastapi import FastAPI, Request\nfrom fastlimiter import RateLimiter\n\napp = FastAPI()\n\nrate_limiter = RateLimiter(rate=5, capacity=10, seconds=60)\n\n@app.get(\"/limited\")\n@rate_limiter.limit()\nasync def limited_endpoint(request: Request):\n    return {\"message\": \"This endpoint is rate-limited.\"}\n```\n\n### Advanced Usage\n\n#### Custom Key Function\n\nYou can customize how the rate limiter identifies clients by overriding `get_key_from_request`:\n\n```python\ndef custom_key_function(self, request: Request) -\u003e str:\n    return request.headers.get(\"X-API-Key\", \"default\")\n\nrate_limiter.get_key_from_request = custom_key_function.__get__(rate_limiter, RateLimiter)\n```\n\n#### Collecting Statistics\n\nEnable statistics collection to monitor rate limiting:\n\n```python\nrate_limiter.enable_stats_collection()\n\nstats = rate_limiter.get_stats(\"client_key\")\nprint(stats)\n```\n\n#### Updating Parameters at Runtime\n\nYou can dynamically update the rate limiter's parameters at runtime:\n\n```python\nrate_limiter.update_rate(new_rate=20)\nrate_limiter.update_capacity(new_capacity=50)\nrate_limiter.update_burst(new_burst=10)\nrate_limiter.update_time(seconds=30)\nrate_limiter.update_stats_window(new_stats_window=120)\n```\n\n## API Reference\n\n### RateLimiter Class\n\n#### Initialization\n\n```python\nRateLimiter(\n    rate: int,\n    capacity: int = 1024,\n    burst: int = None,\n    stats_window: int = 60,\n    enable_stats: bool = True,\n    seconds: int = 0,\n    minutes: int = 0,\n    hours: int = 0\n)\n```\n\n- **rate** _(int)_: The rate at which tokens are added to the bucket.\n- **capacity** _(int)_: Maximum number of tokens in the bucket.\n- **burst** _(int, optional)_: Extra tokens allowed during bursts. Defaults to 0 if not provided.\n- **stats_window** _(int, optional)_: Time window for collecting statistics in seconds.\n- **enable_stats** _(bool, optional)_: Enable or disable statistics collection.\n- **seconds**, **minutes**, **hours**: Define the time interval over which tokens are refilled.\n\n#### Methods\n\n##### allow_request(key: str) -\u003e bool\n\nDetermines if a request identified by `key` is allowed based on the rate limit.\n\n- **Parameters**:\n  - `key` _(str)_: The unique identifier for the client/request.\n- **Returns**:\n  - `bool`: `True` if the request is allowed, `False` otherwise.\n- **Raises**:\n  - `HTTPException`: Raises an HTTP 429 exception if the request is denied.\n\n##### get_wait_time(key: str) -\u003e float\n\nReturns the time in seconds a client identified by `key` needs to wait before making a new request.\n\n- **Parameters**:\n  - `key` _(str)_: The unique identifier for the client/request.\n- **Returns**:\n  - `float`: Time in seconds to wait before the next allowed request.\n\n##### update_stats(key: str, allowed: bool, timestamp: float)\n\nUpdates the statistics for a given `key`.\n\n- **Parameters**:\n  - `key` _(str)_: The unique identifier for the client/request.\n  - `allowed` _(bool)_: Whether the request was allowed.\n  - `timestamp` _(float)_: The time when the request was processed.\n\n##### get_stats(key: str) -\u003e Dict\n\nRetrieves the statistics for a given `key`.\n\n- **Parameters**:\n  - `key` _(str)_: The unique identifier for the client/request.\n- **Returns**:\n  - `Dict`: A dictionary containing statistical data such as total allowed, total denied, etc.\n\n##### reset(key: str = None)\n\nResets the rate limiter state for a specific `key` or all keys if `key` is `None`.\n\n- **Parameters**:\n  - `key` _(str, optional)_: The unique identifier for the client/request. If `None`, resets all keys.\n\n##### update_capacity(new_capacity: int)\n\nUpdates the capacity of the token bucket.\n\n- **Parameters**:\n  - `new_capacity` _(int)_: The new maximum number of tokens.\n\n##### update_burst(new_burst: int)\n\nUpdates the burst size.\n\n- **Parameters**:\n  - `new_burst` _(int)_: The new burst size.\n\n##### update_stats_window(new_stats_window: int)\n\nUpdates the time window for statistics collection.\n\n- **Parameters**:\n  - `new_stats_window` _(int)_: The new statistics window in seconds.\n\n##### update_time(seconds: int = 0, minutes: int = 0, hours: int = 0)\n\nUpdates the time interval over which tokens are refilled.\n\n- **Parameters**:\n  - `seconds`, `minutes`, `hours`: Time components for the new interval.\n\n##### update_rate(new_rate: int)\n\nUpdates the rate at which tokens are added to the bucket.\n\n- **Parameters**:\n  - `new_rate` _(int)_: The new token addition rate.\n\n##### get_key_from_request(request: Request) -\u003e str\n\nRetrieves a unique key from the incoming request. By default, uses the client's IP address.\n\n- **Parameters**:\n  - `request` _(Request)_: The incoming FastAPI request.\n- **Returns**:\n  - `str`: The unique key for rate limiting.\n\n##### enable_stats_collection()\n\nEnables statistics collection.\n\n##### disable_stats_collection()\n\nDisables statistics collection.\n\n##### add_callback(callback: Callable)\n\nAdds a callback function to be executed after each request is processed.\n\n- **Parameters**:\n  - `callback` _(Callable)_: The function to call after processing a request.\n\n##### limit()\n\nCreates a rate-limiting decorator for FastAPI routes.\n\n- **Returns**:\n  - `Callable`: A decorator that can be applied to FastAPI route handlers.\n\n##### fastapi_middleware(request: Request, call_next: Callable)\n\nMiddleware function to apply rate limiting to incoming FastAPI requests.\n\n- **Parameters**:\n  - `request` _(Request)_: The incoming FastAPI request.\n  - `call_next` _(Callable)_: The next middleware or route handler.\n\n## Configuration\n\nCustomize the rate limiter by adjusting the parameters:\n\n- **Rate**: The number of tokens added to the bucket over the specified time interval.\n- **Capacity**: The maximum number of tokens the bucket can hold.\n- **Burst**: Additional tokens allowed for handling bursts of requests.\n- **Time Interval**: The period over which tokens are refilled (specified in seconds, minutes, and/or hours).\n\nExample:\n\n```python\nrate_limiter = RateLimiter(\n    rate=100,\n    capacity=200,\n    burst=50,\n    seconds=60,\n    enable_stats=True,\n    stats_window=300\n)\n```\n\n## Examples\n\n### Limiting Based on API Key\n\n```python\ndef api_key_key_function(self, request: Request) -\u003e str:\n    return request.headers.get(\"X-API-Key\", \"anonymous\")\n\nrate_limiter.get_key_from_request = api_key_key_function.__get__(rate_limiter, RateLimiter)\n```\n\n### Custom Callback Function\n\n```python\ndef log_request(allowed: bool, key: str):\n    status = \"allowed\" if allowed else \"denied\"\n    emoji = \"😊\" if allowed else \"😞\"\n    print(f\"Request from {key} was {status}. {emoji}\")\n\nrate_limiter.add_callback(log_request)\n```\n\n### Resetting Rate Limiter for a Specific Client\n\n```python\nrate_limiter.reset(key=\"client_ip\")\n```\n\n### Applying Different Limits to Different Endpoints\n\n```python\nfrom fastapi import FastAPI, Request\nfrom fastlimiter import RateLimiter\n\napp = FastAPI()\n\n# General rate limiter for most endpoints\ngeneral_limiter = RateLimiter(rate=100, capacity=200, seconds=60)\n\n# Specific rate limiter for a heavy endpoint\nheavy_limiter = RateLimiter(rate=10, capacity=20, seconds=60)\n\n@app.get(\"/general\")\n@general_limiter.limit()\nasync def general_endpoint(request: Request):\n    return {\"message\": \"This is a general endpoint.\"}\n\n@app.get(\"/heavy\")\n@heavy_limiter.limit()\nasync def heavy_endpoint(request: Request):\n    return {\"message\": \"This endpoint has stricter rate limiting.\"}\n```\n\n### Limiting by User ID\n\nIf your application uses authentication, you might want to rate limit based on user ID:\n\n```python\ndef user_id_key_function(self, request: Request) -\u003e str:\n    user = request.state.user  # Assuming user is stored in request.state\n    return str(user.id) if user else \"anonymous\"\n\nrate_limiter.get_key_from_request = user_id_key_function.__get__(rate_limiter, RateLimiter)\n```\n\n### Customizing Rate Limit Exceeded Response\n\nCustomize the response when the rate limit is exceeded:\n\n```python\nfrom fastapi.responses import PlainTextResponse\n\nasync def rate_limit_middleware(request: Request, call_next: Callable):\n    key = rate_limiter.get_key_from_request(request)\n    try:\n        await rate_limiter.allow_request(key)\n        response = await call_next(request)\n        return response\n    except HTTPException as exc:\n        return PlainTextResponse(\n            \"You have exceeded your request rate limit. Please try again later.\",\n            status_code=exc.status_code\n        )\n\napp.middleware(\"http\")(rate_limit_middleware)\n```\n\n## Contributing\n\nWe welcome contributions to improve FastLimiter! Here's how you can contribute:\n\n### Reporting Bugs\n\nIf you find a bug, please open an issue on [GitHub](https://github.com/anto18671/fastlimiter/issues) with detailed steps to reproduce the problem.\n\n### Feature Requests\n\nHave an idea for a new feature? Open an issue with the tag \"enhancement\" to discuss it.\n\n### Pull Requests\n\n1. Fork the repository on GitHub.\n2. Clone your forked repository to your local machine.\n3. Create a new branch for your changes: `git checkout -b feature/your-feature-name`.\n4. Make your changes and commit them with clear messages.\n5. Push your changes to your fork: `git push origin feature/your-feature-name`.\n6. Open a pull request on the main repository.\n\n### Code Style\n\nPlease follow the PEP 8 style guide for Python code.\n\n### Testing\n\nEnsure that all existing tests pass and write new tests for your code.\n\n- Run tests with `pytest`.\n- For asynchronous code, use `pytest_asyncio`.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n\n## Contact\n\nFor questions or suggestions, please open an issue on [GitHub](https://github.com/anto18671/fastlimiter/issues):\n\n- **Author**: Anthony Therrien\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanto18671%2Ffastlimiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanto18671%2Ffastlimiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanto18671%2Ffastlimiter/lists"}