Skip to main content

A simple api rate-limiting library with analytics support

Project description

Limitify

A simple api-rate-limiting library for Python web frameworks with support for FastAPI, Flask, and Django.

Installation

Python

pip install limitify

Quick Start

FastAPI Implementation

Option 1: Middleware (Application-wide rate limiting)

from fastapi import Request, HTTPException, FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from limitify import RateLimiter

app = FastAPI()

class RateLimitMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, api_key: str):
        super().__init__(app)
        self.limiter = RateLimiter(api_key)
    
    async def dispatch(self, request: Request, call_next):
        status, data = await self.limiter.check_limit(request)
        
        if status != 200:
            detail = data.get("detail", "Rate limit error")
            raise HTTPException(status_code=status, detail=detail)
            
        response = await call_next(request)
        return response

app.add_middleware(RateLimitMiddleware, api_key="<api_key>")

@app.get("/users")
async def get_users():
    return {"msg": "hello world!"}

Option 2: Dependency Injection (Route-specific rate limiting)

from fastapi import Request, HTTPException, FastAPI, Depends
from functools import wraps
from limitify import RateLimiter
import asyncio

app = FastAPI()
limiter = RateLimiter("<api_key>")

def rate_limit():
    """FastAPI dependency for rate limiting"""
    async def check_rate_limit(request: Request):
        status, data = await limiter.check_limit(request)
        
        if status != 200:
            detail = data.get("detail", "Rate limit error")
            raise HTTPException(status_code=status, detail=detail)
        
        return True
    
    return check_rate_limit

@app.get("/users")
async def get_users(request: Request, _: bool = Depends(rate_limit())):
    return {"msg": "hello world!"}

@app.get("/posts")
async def get_posts(request: Request, _: bool = Depends(rate_limit())):
    return {"posts": ["post1", "post2"]}

Flask Implementation

from flask import request, jsonify, Flask
from limitify import RateLimiter
import asyncio

app = Flask(__name__)

def ratelimit_middleware(api_key):
    limiter = RateLimiter(api_key)
    
    def decorator(f):
        def wrapper(*args, **kwargs):
            # Run async code inside sync Flask
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            status, data = loop.run_until_complete(limiter.check_limit(request))
            loop.close()

            if status != 200:
                return jsonify({"error": data.get("detail", "Rate limit error")}), status
            return f(*args, **kwargs)
        wrapper.__name__ = f.__name__
        return wrapper
    return decorator

@app.route("/admin")
@ratelimit_middleware("<api_key>")
def main():
    return "hello world!"

if __name__ == '__main__':
    app.run(port=8000)

Django Implementation

Settings Configuration

# myproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    # ...other apps...
    'myapp',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ...other middleware...
    'myapp.middleware.RateLimitMiddleware',
]

Middleware Implementation

# myapp/middleware.py
import asyncio
from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from limitify import RateLimiter

class RateLimitMiddleware(MiddlewareMixin):
    API_KEY = "GdnGypZSjvxcvqSxitX6EiGyVNYboaitSvOL4f0hIUY"
    
    def __init__(self, get_response=None):
        super().__init__(get_response)
        self.limiter = RateLimiter(self.API_KEY)
        self.loop = asyncio.new_event_loop()
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        # Skip rate limiting for admin URLs (optional)
        if request.path.startswith('/admin/'):
            return None
        
        # Run rate limiter check
        status, data = self.loop.run_until_complete(
            self.limiter.check_limit(request)
        )
        
        if status != 200:
            return JsonResponse(
                {"error": data.get("detail", "Rate limit error")},
                status=status
            )
        return None  # Continue processing
    
    def __del__(self):
        self.loop.close()

API Reference

Configuration Options

  • apiKey (required) - Your API key for the rate limiting service

RateLimiter Class

The main class for implementing rate limiting functionality.

Methods

  • check_limit(request) - Checks if the current request should be rate limited
    • Returns: (status_code, data) tuple
    • status_code: HTTP status code (200 for allowed, 4xx for rate limited)
    • data: Dictionary containing error details if rate limited

Framework Support

  • FastAPI - Full async support with middleware
  • Flask - Decorator-based implementation with async compatibility
  • Django - Middleware implementation with optional path exclusions

Usage Notes

FastAPI

  • Uses async middleware for optimal performance
  • Integrates seamlessly with FastAPI's dependency injection system
  • Supports all FastAPI features including automatic API documentation
  • Two implementation options:
    • Middleware: Application-wide rate limiting for all routes
    • Dependency: Route-specific rate limiting with more granular control

Flask

  • Uses decorator pattern for easy route-specific rate limiting
  • Handles async operations within Flask's synchronous context
  • Compatible with Flask blueprints and extensions

Django

  • Implements as Django middleware for application-wide rate limiting
  • Supports path-based exclusions (e.g., admin URLs)
  • Follows Django's middleware patterns and conventions

Contributing

We welcome contributions! Please see our contributing guidelines for more information.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For support and questions, please visit our documentation or contact our support team.

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

limitify-0.1.1.tar.gz (5.7 kB view details)

Uploaded Source

Built Distribution

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

limitify-0.1.1-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

Details for the file limitify-0.1.1.tar.gz.

File metadata

  • Download URL: limitify-0.1.1.tar.gz
  • Upload date:
  • Size: 5.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for limitify-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c6ec5c3a0ed236df8971533459342737c396aea505a75dc848d50a5467a18483
MD5 25c4811e0ca62d714ad5957a54ec5f72
BLAKE2b-256 e02538a7b45eb5d94287c7ccca1ab9664547f389afdfb7a61bb3e388ec35a560

See more details on using hashes here.

File details

Details for the file limitify-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: limitify-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 5.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for limitify-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6c98374e161701d47181b4860d119c2b878c74d04d0424db1d301b8de38d819e
MD5 f59152cb59462870cb45857168c0f9b6
BLAKE2b-256 686f1cfd956bca0f1224445d25c85230d19590f3ef7c61c3355e275e03df1a5b

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