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.3.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.3-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: flask_ratelimit_simple-1.0.3.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.3.tar.gz
Algorithm Hash digest
SHA256 db6e79e6b1f7ea9fcc900fde4ea3200be378b6bd0f823d0dabae0ccf8cb41844
MD5 a52597c6b9458e975c3f389d0e6af4dc
BLAKE2b-256 e793af52e2eab6a9246adffa58fd596a08333289869e0497333d5b8a0dc31008

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for flask_ratelimit_simple-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 56cff046c726a762f3dcaebfa678c22457b73852e71de0e8d5227413a0611d64
MD5 87f237cba45680cb26383169fdb58aac
BLAKE2b-256 4bc5bb04004a95f22d87ba99592be28db5de6c9bfb664fce505863bec3965836

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