Quart-Rate-Limiter is an extension for Quart to allow for rate limits to be
defined and enforced on a per route basis. The 429 error response
includes a RFC7231 compliant
Retry-After
header and the successful responses contain headers
compliant with the RateLimit Header Fields for HTTP RFC
draft.
To add a rate limit first initialise the RateLimiting extension with the application,
app = Quart(__name__)
rate_limiter = RateLimiter(app)
or via the factory pattern,
rate_limiter = RateLimiter()
def create_app():
app = Quart(__name__)
rate_limiter.init_app(app)
return app
Now this is done you can apply rate limits to any route by using the
rate_limit
decorator,
@app.route('/')
@rate_limit(1, timedelta(seconds=10))
async def handler():
...
Or to apply rate limits to all routes within a blueprint by using the
limit_blueprint
function,
blueprint = Blueprint("name", __name__)
limit_blueprint(blueprint, 1, timedelta(seconds=10))
Or to apply rate limits to all routes in an app, define the default limits when initialising the RateLimiter,
rate_limiter = RateLimiter(
default_limits=[RateLimit(1, timedelta(seconds=10))]
)
and then to exempt a route,
@app.route("/exempt")
@rate_exempt
async def handler():
...
To alter the identification of remote users you can either supply a global key function when initialising the extension, or on a per route basis.
By default rate limiting information (TATs) will be stored in memory,
which will result in unexpected behaviour if multiple workers are
used. To solve this a redis store can be used by installing the
redis
extra (pip install quart-rate-limiter[redis]
) and then
using as so,
from quart_rate_limiter.redis_store import RedisStore
redis_store = RedisStore(address)
RateLimiter(app, store=redis_store)
This store uses redis,
and any extra keyword arguments passed to the RedisStore
constructor will be passed to the redis create_redis
function.
A custom store is possible, see the RateLimiterStoreABC
for the
required interface.
To limit a route to 1 request per second and a maximum of 20 per minute,
@app.route('/')
@rate_limit(1, timedelta(seconds=1))
@rate_limit(20, timedelta(minutes=1))
async def handler():
...
Alternatively the limits
argument can be used for multiple limits,
@app.route('/')
@rate_limit(
limits=[
RateLimit(1, timedelta(seconds=1)),
RateLimit(20, timedelta(minutes=1)),
],
)
async def handler():
...
To identify remote users based on their authentication ID, rather than their IP,
async def key_function():
return current_user.id
RateLimiter(app, key_function=key_function)
The key_function
is a coroutine function to allow session lookups
if appropriate.
Quart-Rate-Limiter is developed on GitHub. You are very welcome to open issues or propose merge requests.
The best way to test Quart-Rate-Limiter is with Tox,
$ pip install tox
$ tox
this will check the code style and run the tests.
This README is the best place to start, after that try opening an issue.