Skip to main content

jetio-ratelimit

Tests Coverage Status Python versions License

Rate limiting for Jetio: sliding-window by default, IP- or account-keyed (or both, stacked), usable as middleware for routes you don't own the handler for (like jetio-auth's /login) and as a Depends()-composable dependency for routes you do (a CrudRouter policy, a hand-written route).

  • docs/USAGE.md -- the full guide: every mode, every key function, stacking/reusing policies, handling a 429, testing your integration, troubleshooting. Start here for "how do I do X."
  • DESIGN.md -- the reasoning: why sliding window over token bucket, why IP-only limiting is weak against real credential stuffing, and the real bugs found in Jetio/jetio-auth along the way. Start here for "why does it work this way."

Install

pip install -e .[dev]   # from this directory, for now -- not yet published

Quickstart

from jetio import Jetio, CrudRouter
from jetio_auth import AuthRouter
from jetio_ratelimit import RateLimiter, InMemoryStore, Limit, by_ip, by_field, by_user

app = Jetio()
auth = AuthRouter(User, company_name="My App")
auth.register_routes(app)  # POST /register, POST /login

limiter = RateLimiter(store=InMemoryStore())

# Middleware mode: protects /login, which AuthRouter registers internally --
# there's no Depends() hook to attach to on a route we don't define.
# protect_many() stacks two independent limits in one call; either tripping
# blocks the request. AUTH_POLICY is a plain list, so the same two rules
# can be applied to /register or any other auth-adjacent route with one
# more protect_many() call each -- see "Reusing a policy across routes" below.
AUTH_POLICY = [
    Limit(max_attempts=5, window_seconds=60, key_func=by_ip),
    Limit(max_attempts=3, window_seconds=60, key_func=by_field("username")),
]
limiter.protect_many(app, path="/login", limits=AUTH_POLICY)

# Dependency mode: composes into a CrudRouter policy, keyed by the
# authenticated user rather than IP.
CrudRouter(
    model=Order,
    secure=True,
    policy={
        "POST": limiter.dependency(
            max_attempts=10, window_seconds=60,
            key_func=by_user, identity_dependency=auth.get_auth_dependency(),
        ),
    },
).register_routes(app)

Run examples/demo_app.py and hit it with curl to see both modes working against a real jetio-auth-backed app. For why /login gets two stacked limits instead of one, how to reuse one policy across many routes, by_header-keyed API endpoints, using dependency mode outside CrudRouter, and more, see docs/USAGE.md.

Status

v0.1: sliding window algorithm, in-memory store, both API modes, IP/account/ header/user keying, protect_many() for stacking multiple limits (or reusing one policy across many routes) in one call. Not yet done: Redis store (for anything running more than one worker -- InMemoryStore's state is per-process), progressive lockout on repeat violations, an equivalent stacking helper for dependency mode, PyPI publish. See DESIGN.md's build order.

Known limitations

  • InMemoryStore is single-process. Behind multiple workers/replicas, each one has its own counters, so the effective limit becomes limit * worker_count. Don't treat this as sufficient for a horizontally-scaled deployment yet.
  • No X-Forwarded-For support. Behind a reverse proxy, by_ip sees the proxy's IP, not the real client's. Not yet configurable.

Release files for jetio-ratelimit 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jetio-ratelimit 0.1.0
File Size Uploaded
jetio_ratelimit-0.1.0.tar.gz 17.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jetio-ratelimit 0.1.0
File Interpreter ABI Platform
jetio_ratelimit-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.0 kB

Release files / jetio_ratelimit-0.1.0.tar.gz

Download URL jetio_ratelimit-0.1.0.tar.gz
Size 17.4 kB
Tags Source
SHA-256 checksum
How to use checksums
7ec29225c009328e00a0da660361f00102df9641ab83bfc844896a40011888be
BLAKE2b-256 checksum
How to use checksums
a9982eb09de59d1490a8a2da6f5c17c63bc65af802111afa120aacc27a179208
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / jetio_ratelimit-0.1.0-py3-none-any.whl

Download URL jetio_ratelimit-0.1.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b50ad96ce09d42b54fba2ea42332f74bbf15e7e7405cea87fce3602c9ac1b785
BLAKE2b-256 checksum
How to use checksums
1468e4b2a9470d80282dc6fff075f9f276d6f5aaf48fa4d3b7a6b55d30cc7fd1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page