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.
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 allowedX-RateLimit-Remaining- Requests remainingX-RateLimit-Reset- Seconds until limit resetsRetry-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
gobject to store rate limit data per request - Stores timestamps of requests in memory
- Automatically cleans up expired entries
User Identification
-
Authenticated users (Flask-Login detected):
- Tracked by
current_user.id - Limits apply per user account
- Tracked by
-
Anonymous users:
- Tracked by IP address (
request.remote_addr) - Limits apply per IP
- Tracked by IP address (
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:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request
License
MIT License - see LICENSE file for details
Support
Related Packages
- flask-security-headers - Security utilities
- flask-supercache - Caching
- flask-querymonitor - Query optimization
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c2fc72646e2fcf5ebaf792ab0a9824a107574a742815942d86fbe12a9f7d682
|
|
| MD5 |
3df63eb738b7cbdb020a39e0a88a5e42
|
|
| BLAKE2b-256 |
9de054ed372725fbd7b5d4fcd3155407b8a2faec089e7f2d06efe03b7c5f4087
|
File details
Details for the file flask_ratelimit_simple-1.0.2-py3-none-any.whl.
File metadata
- Download URL: flask_ratelimit_simple-1.0.2-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db93e719c6cf846bcf69645fb9c150016966c7937a811d8e4308a98bcc4a5abb
|
|
| MD5 |
dce09c973f490005210fc698c10a0821
|
|
| BLAKE2b-256 |
18286592c8ecaf64cdddec8e3892f0bb3e5fcdae6789f3b2662e9c99eb0d51ba
|