Skip to main content

Lightweight in-memory rate limiting for Flask

Project description

Flask-RateLimit-Simple

Lightweight, in-memory rate limiting for Flask - Protect your API endpoints from abuse without the complexity of Redis or external dependencies.

PyPI version Python Support License: MIT

Why Flask-RateLimit-Simple?

Most rate limiting solutions require Redis or Memcached. This package uses in-memory storage with automatic cleanup, making it:

  • Zero external dependencies - No Redis, no Memcached
  • Production-ready - Battle-tested at WallMarkets
  • Standards-compliant - Returns proper X-RateLimit-* headers
  • Smart tracking - IP-based for anonymous, user-based for authenticated

Features

🚀 Simple Decorator API

Just add @rate_limit() to any route - no complex setup required

📊 Standard Rate Limit Headers

Returns RFC-compliant headers:

  • X-RateLimit-Limit - Maximum requests allowed
  • X-RateLimit-Remaining - Requests remaining
  • X-RateLimit-Reset - Seconds until limit resets
  • Retry-After - When to retry (on 429 responses)

🎯 Smart User Tracking

  • Anonymous users: Tracked by IP address
  • Authenticated users: Tracked by user ID (via Flask-Login)
  • Automatic detection: No configuration needed

🧹 Automatic Cleanup

Expired entries are automatically removed - no memory leaks

🔧 Flexible Configuration

Set different limits for different endpoints

Installation

pip install flask-ratelimit-simple

Quick Start

pip install flask-ratelimit-simple

Usage Examples

Basic Rate Limiting

from flask import Flask
from flask_ratelimit_simple import rate_limit

app = Flask(__name__)

# Limit login attempts: 5 per 5 minutes
@app.route('/login', methods=['POST'])
@rate_limit('login', limit=5, period=300)
def login():
    # Your login logic here
    return {'message': 'Login successful'}

# Limit API calls: 100 per minute
@app.route('/api/data')
@rate_limit('api_data', limit=100, period=60)
def get_data():
    return {'data': [...]}  

# Limit password resets: 3 per hour
@app.route('/reset-password', methods=['POST'])
@rate_limit('password_reset', limit=3, period=3600)
def reset_password():
    # Send reset email
    return {'message': 'Reset email sent'}

Different Limits for Different Endpoints

# Strict limit for authentication
@app.route('/api/auth/login', methods=['POST'])
@rate_limit('auth_login', limit=5, period=300)  # 5 per 5min
def api_login():
    pass

# Generous limit for public data
@app.route('/api/products')
@rate_limit('products_list', limit=1000, period=3600)  # 1000 per hour
def list_products():
    pass

# Very strict for expensive operations
@app.route('/api/export', methods=['POST'])
@rate_limit('data_export', limit=2, period=86400)  # 2 per day
def export_data():
    pass

Response Headers

Successful Request (200 OK)

HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 42

Rate Limit Exceeded (429 Too Many Requests)

HTTP/1.1 429 TOO MANY REQUESTS
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 247
Retry-After: 247
Content-Type: application/json

{"error": "Rate limit exceeded. Try again in 247 seconds."}

Real-World Use Cases

API Protection

# Protect your API from abuse
@app.route('/api/v1/search', methods=['POST'])
@rate_limit('api_search', limit=30, period=60)  # 30 searches per minute
def search_api():
    query = request.json.get('query')
    results = perform_expensive_search(query)
    return {'results': results}

Authentication Security

# Prevent brute force attacks
@app.route('/login', methods=['POST'])
@rate_limit('login_attempts', limit=5, period=900)  # 5 attempts per 15min
def login():
    username = request.form['username']
    password = request.form['password']
    
    if verify_credentials(username, password):
        return redirect('/dashboard')
    
    return {'error': 'Invalid credentials'}, 401

Resource-Intensive Operations

# Limit expensive operations
@app.route('/generate-report', methods=['POST'])
@rate_limit('report_generation', limit=3, period=3600)  # 3 reports per hour
def generate_report():
    # This takes 30 seconds and uses lots of CPU
    report = create_detailed_report()
    return send_file(report)

Email/SMS Sending

# Prevent spam
@app.route('/send-verification', methods=['POST'])
@rate_limit('verification_email', limit=3, period=3600)  # 3 emails per hour
def send_verification():
    send_email(current_user.email, verification_code)
    return {'message': 'Verification email sent'}

How It Works

Storage

  • Uses Flask's g object to store rate limit data per request
  • Stores timestamps of requests in memory
  • Automatically cleans up expired entries

User Identification

  1. Authenticated users (Flask-Login detected):

    • Tracked by current_user.id
    • Limits apply per user account
  2. Anonymous users:

    • Tracked by IP address (request.remote_addr)
    • Limits apply per IP

Algorithm

  • Sliding window approach
  • Counts requests within the time period
  • Removes expired timestamps automatically
  • O(n) complexity where n = number of requests in window

Configuration

Custom Error Messages

from flask_ratelimit_simple import rate_limit

@app.errorhandler(429)
def ratelimit_handler(e):
    return {
        'error': 'Too many requests',
        'message': 'Please slow down and try again later',
        'retry_after': e.description
    }, 429

Integration with Flask-Login

from flask_login import LoginManager, current_user

login_manager = LoginManager(app)

# Rate limits automatically use current_user.id when available
@app.route('/api/user/profile')
@login_required
@rate_limit('profile_view', limit=100, period=60)
def view_profile():
    # This limit is per user, not per IP
    return {'user': current_user.to_dict()}

Performance

  • Memory usage: ~100 bytes per tracked request
  • Overhead: <1ms per request
  • Scalability: Suitable for single-server deployments
  • Cleanup: Automatic, runs on each request

When to Use This Package

Good for:

  • Single-server Flask applications
  • Development and testing
  • Small to medium traffic (< 10k requests/min)
  • When you don't want Redis complexity

Not recommended for:

  • Multi-server deployments (use Redis-based solution)
  • Very high traffic (> 100k requests/min)
  • When you need persistent rate limit data across restarts

Testing

import pytest
from flask import Flask
from flask_ratelimit_simple import rate_limit

def test_rate_limiting():
    app = Flask(__name__)
    
    @app.route('/test')
    @rate_limit('test', limit=3, period=60)
    def test_endpoint():
        return {'success': True}
    
    client = app.test_client()
    
    # First 3 requests should succeed
    for i in range(3):
        response = client.get('/test')
        assert response.status_code == 200
    
    # 4th request should be rate limited
    response = client.get('/test')
    assert response.status_code == 429

Production Usage

This package is used in production at:

  • WallMarkets - Multi-vendor marketplace
  • Protecting authentication endpoints
  • Rate limiting API calls
  • Preventing abuse of resource-intensive operations

Comparison with Alternatives

Feature flask-ratelimit-simple Flask-Limiter flask-ratelimit
Redis required ❌ No ✅ Yes ✅ Yes
Setup complexity Low Medium Medium
Multi-server ❌ No ✅ Yes ✅ Yes
Memory usage Low N/A N/A
Dependencies 0 2+ 2+

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Submit a pull request

License

MIT License - see LICENSE file for details

Support

Related Packages


Made with ❤️ by the WallMarkets 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

flask_ratelimit_simple-1.0.2.tar.gz (7.5 kB view details)

Uploaded Source

Built Distribution

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

flask_ratelimit_simple-1.0.2-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file flask_ratelimit_simple-1.0.2.tar.gz.

File metadata

  • Download URL: flask_ratelimit_simple-1.0.2.tar.gz
  • Upload date:
  • Size: 7.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for flask_ratelimit_simple-1.0.2.tar.gz
Algorithm Hash digest
SHA256 6c2fc72646e2fcf5ebaf792ab0a9824a107574a742815942d86fbe12a9f7d682
MD5 3df63eb738b7cbdb020a39e0a88a5e42
BLAKE2b-256 9de054ed372725fbd7b5d4fcd3155407b8a2faec089e7f2d06efe03b7c5f4087

See more details on using hashes here.

File details

Details for the file flask_ratelimit_simple-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for flask_ratelimit_simple-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 db93e719c6cf846bcf69645fb9c150016966c7937a811d8e4308a98bcc4a5abb
MD5 dce09c973f490005210fc698c10a0821
BLAKE2b-256 18286592c8ecaf64cdddec8e3892f0bb3e5fcdae6789f3b2662e9c99eb0d51ba

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