Skip to content

Commit

Permalink
- Configuring the global default through the FastAPILimiter.init method.
Browse files Browse the repository at this point in the history
- Update status to 429 when too many requests.
- Update default_callback params and add `Retry-After` response header.
  • Loading branch information
long2ice committed Jan 7, 2021
1 parent 249ba90 commit d390439
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 155 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# ChangeLog

## 0.1

### 0.1.1

- Configuring the global default through the FastAPILimiter.init method.
- Update status to 429 when too many requests.
- Update default_callback params and add `Retry-After` response header.
14 changes: 11 additions & 3 deletions fastapi_limiter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import aioredis
from fastapi import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
from starlette.status import HTTP_429_TOO_MANY_REQUESTS


async def default_identifier(request: Request):
Expand All @@ -13,8 +13,16 @@ async def default_identifier(request: Request):
return request.client.host


async def default_callback(request: Request):
raise HTTPException(HTTP_403_FORBIDDEN, "The request is frequent")
async def default_callback(request: Request, expire: int):
"""
default callback when too many requests
:param request:
:param expire: The remaining seconds
:return:
"""
raise HTTPException(
HTTP_429_TOO_MANY_REQUESTS, "Too Many Requests", headers={"Retry-After": str(expire)}
)


class FastAPILimiter:
Expand Down
19 changes: 13 additions & 6 deletions fastapi_limiter/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pydantic import conint
from starlette.requests import Request
from starlette.responses import Response

from fastapi_limiter import FastAPILimiter

Expand All @@ -18,17 +19,23 @@ def __init__(
):
self.times = times
self.seconds = seconds + 60 * minutes + 3600 * hours
self.identifier = identifier or FastAPILimiter.identifier
self.callback = callback or FastAPILimiter.callback
self.identifier = identifier
self.callback = callback

async def __call__(self, request: Request):
async def __call__(self, request: Request, response: Response):
if not FastAPILimiter.redis:
raise Exception("You must call FastAPILimiter.init in startup event of fastapi!")
# moved here because constructor run before app startup
identifier = self.identifier or FastAPILimiter.identifier
callback = self.callback or FastAPILimiter.callback
redis = FastAPILimiter.redis
rate_key = await self.identifier(request)
rate_key = await identifier(request)
key = FastAPILimiter.prefix + ":" + rate_key
num = await redis.incrby(key, 1)
p = redis.pipeline()
p.incrby(key, 1)
p.ttl(key)
num, expire = await p.execute()
if num == 1:
await redis.expire(key, self.seconds)
if num > self.times:
return await self.callback(request)
return await callback(request, expire)
Loading

0 comments on commit d390439

Please sign in to comment.