Usage Examples with Rush

To make it clearer how rush can be used, we collect examples of how one might integrate Rush into their project.

Warning

Many of these are written by the maintainers as a immediate proof of concept rather than examples of best practices using those frameworks.

Other framework examples are very welcome. The maintainers may not have time, however, to keep them up-to-date so your continued contributions to keep them relevant is appreciated.

Flask

Flask is a popular micro-framework for writing web services. In our examples directory, we have a Flask application with a single route.

In the example, we use the requestor’s IP address and optional credentials to throttle their traffic. We define both anonymous and authenticated rate limits.

We use the RateLimitResult object to determine how to respond and to generate the RateLimit headers on the response. Here are some relevant excerpts:

# examples/flask/src/limiterapp/__init__.py
REDIS_URL = os.environ.get("REDIS_URL")
if REDIS_URL:
    store = redis_store.RedisStore(url=REDIS_URL)
else:
    store = dict_store.DictionaryStore()

anonymous_quota = quota.Quota.per_hour(50)
authenticated_quota = quota.Quota.per_hour(5000, maximum_burst=500)
limiter = gcra.GenericCellRatelimiter(store=store)
anonymous_throttle = throttle.Throttle(rate=anonymous_quota, limiter=limiter)
authenticated_throttle = throttle.Throttle(
    rate=authenticated_quota, limiter=limiter
)

Note

We only allow the dictionary store above because this is meant as an example and we want users to be able to not require Redis when playing around with this.

# examples/flask/src/limiterapp/views.py
auth = request.authorization
ip_address = request.headers.get("X-Forwarded-For", request.remote_addr)
username = "anonymous"
response = flask.Response()

if auth and auth.username and auth.password:
    throttle = limiterapp.authenticated_throttle
    username = auth.username
    log.info("sent credentials", username=auth.username)

userkey = f"{username}@{ip_address}"
result = throttle.check(key=userkey, quantity=1)
response.headers.extend(
    [
        ("X-RateLimit-Limit", result.limit),
        ("X-RateLimit-Remaining", result.remaining),
        ("X-RateLimit-Reset", result.resets_at().strftime(time_format)),
        ("X-RateLimit-Retry", result.retry_at().strftime(time_format)),
    ]
)
# examples/flask/src/limiterapp/views.py
if result.limited:
    log.info("ratelimited", username=username)
    response.status_code = 403
else:
    response.status_code = 200
    response.data = f"Hello from home, {username}"

Playing with this example

To set up this example you need pipenv. You can cd into the directory and run

pipenv install

To run the server you can run

pipenv run gunicorn -w4 limiterapp.views:app

If you want to try rush out with Redis, you should set up a .env file like so:

cp env.template .env
# edit .env to include your REDIS_URL
pipenv run gunicorn -w4 limiterapp.views:app

You can also run black against this project:

pipenv run black -l 78 --py36 --safe src/ test/

If you want to contribute better Flask practices, please do so. The maintainers of rush know that it’s plausible to use app.before_request and middleware to handle this but wanted to keep the example small-ish and reasonably contained. If you think the existing example is hard to understand, we welcome any contributions to make it easier and clearer.