fix(api): changed rate limit library, now play well with testing
This commit is contained in:
parent
ec6e39bd7c
commit
7cfd05dd96
108
backend/pdm.lock
generated
108
backend/pdm.lock
generated
@ -5,7 +5,7 @@
|
||||
groups = ["default", "dev"]
|
||||
strategy = ["cross_platform"]
|
||||
lock_version = "4.4.1"
|
||||
content_hash = "sha256:c967cac24f6f70dbbca2f704a73e986d1e00e940145b4dc6471c8bfd85440e79"
|
||||
content_hash = "sha256:a15732e99160a9c0463d7809d12e0405520e386b75c8cabcf9ce911abd4c1001"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
@ -134,6 +134,19 @@ files = [
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deprecated"
|
||||
version = "1.2.14"
|
||||
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
summary = "Python @deprecated decorator to deprecate old python classes, functions or methods."
|
||||
dependencies = [
|
||||
"wrapt<2,>=1.10",
|
||||
]
|
||||
files = [
|
||||
{file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
|
||||
{file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.5.0"
|
||||
@ -173,20 +186,6 @@ files = [
|
||||
{file = "fastapi-0.109.0.tar.gz", hash = "sha256:b978095b9ee01a5cf49b19f4bc1ac9b8ca83aa076e770ef8fd9af09a2b88d191"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-limiter"
|
||||
version = "0.1.6"
|
||||
requires_python = ">=3.9,<4.0"
|
||||
summary = "A request rate limiter for fastapi"
|
||||
dependencies = [
|
||||
"fastapi",
|
||||
"redis>=4.2.0rc1",
|
||||
]
|
||||
files = [
|
||||
{file = "fastapi_limiter-0.1.6-py3-none-any.whl", hash = "sha256:2e53179a4208b8f2c8795e38bb001324d3dc37d2800ff49fd28ec5caabf7a240"},
|
||||
{file = "fastapi_limiter-0.1.6.tar.gz", hash = "sha256:6f5fde8efebe12eb33861bdffb91009f699369a3c2862cdc7c1d9acf912ff443"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freezegun"
|
||||
version = "1.4.0"
|
||||
@ -267,6 +266,16 @@ files = [
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-resources"
|
||||
version = "6.1.1"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Read resources from Python packages"
|
||||
files = [
|
||||
{file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"},
|
||||
{file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
@ -287,6 +296,22 @@ files = [
|
||||
{file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "limits"
|
||||
version = "3.7.0"
|
||||
requires_python = ">=3.7"
|
||||
summary = "Rate limiting utilities"
|
||||
dependencies = [
|
||||
"deprecated>=1.2",
|
||||
"importlib-resources>=1.3",
|
||||
"packaging<24,>=21",
|
||||
"typing-extensions",
|
||||
]
|
||||
files = [
|
||||
{file = "limits-3.7.0-py3-none-any.whl", hash = "sha256:c528817b7fc15f3e86ad091ba3e40231f6430a91b753db864767684cda8a7f2e"},
|
||||
{file = "limits-3.7.0.tar.gz", hash = "sha256:124c6a04d2f4b20990fb1de019eec9474d6c1346c70d8fd0561609b86998b64a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
@ -512,15 +537,15 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "5.1.0b3"
|
||||
requires_python = ">=3.8"
|
||||
version = "5.0.1"
|
||||
requires_python = ">=3.7"
|
||||
summary = "Python client for Redis database and key-value store"
|
||||
dependencies = [
|
||||
"async-timeout>=4.0.3",
|
||||
"async-timeout>=4.0.2; python_full_version <= \"3.11.2\"",
|
||||
]
|
||||
files = [
|
||||
{file = "redis-5.1.0b3-py3-none-any.whl", hash = "sha256:8e83465ce69eb7b86b96d4e793ad1a8888d368815e47f1f6081d2d65d655a89c"},
|
||||
{file = "redis-5.1.0b3.tar.gz", hash = "sha256:e5386f40168f16e4b136aa03a74cb13bccfb042280fd443f81482fc10548aae6"},
|
||||
{file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"},
|
||||
{file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -558,6 +583,19 @@ files = [
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slowapi"
|
||||
version = "0.1.8"
|
||||
requires_python = ">=3.7,<4.0"
|
||||
summary = "A rate limiting extension for Starlette and Fastapi"
|
||||
dependencies = [
|
||||
"limits>=2.3",
|
||||
]
|
||||
files = [
|
||||
{file = "slowapi-0.1.8-py3-none-any.whl", hash = "sha256:629fc415575bbffcd9d8621cc3ce326a78402c5f9b7b50b127979118d485c72e"},
|
||||
{file = "slowapi-0.1.8.tar.gz", hash = "sha256:8cc268f5a7e3624efa3f7bd2859b895f9f2376c4ed4e0378dd2f7f3343ca608e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.0"
|
||||
@ -710,6 +748,36 @@ files = [
|
||||
{file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrapt"
|
||||
version = "1.16.0"
|
||||
requires_python = ">=3.6"
|
||||
summary = "Module for decorators, wrappers and monkey patching."
|
||||
files = [
|
||||
{file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"},
|
||||
{file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"},
|
||||
{file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"},
|
||||
{file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"},
|
||||
{file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zxcvbn"
|
||||
version = "4.4.28"
|
||||
|
@ -13,7 +13,8 @@ dependencies = [
|
||||
"bcrypt>=4.1.2", # hashing passwords
|
||||
"zxcvbn>=4.4.28", # rate password strength
|
||||
"itsdangerous>=2.1.2", # signing user tokens
|
||||
"fastapi-limiter>=0.1.6",
|
||||
"slowapi>=0.1.8",
|
||||
"redis>=5.0.1",
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
readme = "README.md"
|
||||
|
@ -1,4 +1,7 @@
|
||||
from fastapi import APIRouter
|
||||
from starlette.requests import Request
|
||||
|
||||
from src.neo_neo_todo.utils.rate_limit import limiter
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/control",
|
||||
@ -7,5 +10,6 @@ router = APIRouter(
|
||||
|
||||
|
||||
@router.get("/ping")
|
||||
async def ping():
|
||||
@limiter.exempt
|
||||
async def ping(request: Request):
|
||||
return {"ping": "pong"}
|
||||
|
@ -1,20 +1,14 @@
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import redis.asyncio as redis
|
||||
from fastapi import FastAPI
|
||||
from fastapi_limiter import FastAPILimiter
|
||||
from slowapi import _rate_limit_exceeded_handler
|
||||
from slowapi.errors import RateLimitExceeded
|
||||
from slowapi.middleware import SlowAPIMiddleware
|
||||
|
||||
from src.neo_neo_todo.control import control
|
||||
from src.neo_neo_todo.utils.rate_limit import limiter
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(_: FastAPI):
|
||||
redis_connection = redis.from_url("redis://localhost:6379", encoding="utf8")
|
||||
await FastAPILimiter.init(redis_connection)
|
||||
yield
|
||||
await FastAPILimiter.close()
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(control.router)
|
||||
|
||||
app.state.limiter = limiter
|
||||
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # type: ignore
|
||||
app.add_middleware(SlowAPIMiddleware)
|
||||
|
8
backend/src/neo_neo_todo/utils/rate_limit.py
Normal file
8
backend/src/neo_neo_todo/utils/rate_limit.py
Normal file
@ -0,0 +1,8 @@
|
||||
from slowapi import Limiter
|
||||
from slowapi.util import get_remote_address
|
||||
|
||||
limiter = Limiter(
|
||||
key_func=get_remote_address,
|
||||
default_limits=["70/minute"],
|
||||
storage_uri="redis://localhost:6379/1",
|
||||
)
|
@ -1,11 +1,8 @@
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from src.neo_neo_todo.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_ping():
|
||||
|
Loading…
x
Reference in New Issue
Block a user