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.0.tar.gz (5.6 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.0-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: limitify-0.1.0.tar.gz
  • Upload date:
  • Size: 5.6 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.0.tar.gz
Algorithm Hash digest
SHA256 4294634bbd5195e6bbb84c0ef033b59e9d2203c817d46869393d3c707c8ccedb
MD5 35a53eca1dc78526fe0d0f86e98925c8
BLAKE2b-256 e91d0b1156a3b6956ef53632eef8371bf73f2ad2a34e7df9a18653cf9a6897d3

See more details on using hashes here.

File details

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

File metadata

  • Download URL: limitify-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7cd03b9ee9bd1d27ddedeb6f43d3ce8622e567ee91bc967f901cc3282b350de5
MD5 96662529f7ca48d8ad9d80e0b77b9e48
BLAKE2b-256 34200b8b167aa0bcee62af78de4a680fdae0e385d36167ca7ad4a60474500c78

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