A rate limiter for Starlette and FastAPI

Overview

SlowApi

A rate limiting library for Starlette and FastAPI adapted from flask-limiter.

Note: this is alpha quality code still, the API may change, and things may fall apart while you try it.

The documentation is on read the docs.

Quick start

Installation

slowapi is available from pypi so you can install it as usual:

$ pip install slowapi

Features

Most feature are coming from (will come from) FlaskLimiter and the underlying limits.

Supported now:

  • Single and multiple limit decorator on endpoint functions to apply limits
  • redis, memcached and memory backends to track your limits (memory as a fallback)
  • support for sync and async HTTP endpoints
  • Support for shared limits across a set of routes

Limitations and known issues

  • The request argument must be explicitly passed to your endpoint, or slowapi won't be able to hook into it. In other words, write:
    @limiter.limit("5/minute")
    async def myendpoint(request: Request)
        pass

and not:

    @limiter.limit("5/minute")
    async def myendpoint()
        pass
  • websocket endpoints are not supported yet.

Developing and contributing

PRs are more than welcome! Please include tests for your changes :)

The package uses poetry to manage dependencies. To setup your dev env:

$ poetry install

To run the tests:

$ pytest

Credits

Credits go to flask-limiter of which SlowApi is a (still partial) adaptation to Starlette and FastAPI. It's also important to mention that the actual rate limiting work is done by limits, slowapi is just a wrapper around it.

Comments
  • new: :sparkles: add ASGI middleware alternative

    new: :sparkles: add ASGI middleware alternative

    fix https://github.com/laurentS/slowapi/issues/98

    Might be easier for people reviewing to explain the different commits:

    • first commit adds the new ASGI middleware
    • second one update tests so that it test both the HTTP and ASGI middlewares (using pytest parametrize and fixtures)
    • third one is a refactoring commit, to avoid duplicating too much code between the HTTP and the ASGI middleware

    Might be easier to first review the first two commits, then the refactoring one (to avoid seeing too many changes at once)

    Let me know what do you think about this :smile:

    Note: maybe I could do a bit of refactoring between _inject_headers and _inject_asgi_headers as well ?

    opened by thentgesMindee 13
  • Limit rate issue

    Limit rate issue

    I've tested limit rate locally and it works fine.

    After I deployed application on AWS, rates did't work at all until I set redis as storage.

    But even with redis, rate limit seems to be broken. Limit is exceeded after ~10th attempt, and I've set limit to 5.

    I've checked redis value for the key inserted by limiter, and I think it did not count every attempt.

    I'm using FastAPI 0.45.0 and slowapi 0.1.1

    opened by HereComesTheRainAgain 12
  • Move to ASGI middleware implementation?

    Move to ASGI middleware implementation?

    There's been an uptick in issues (1, 2, 3,etc.) around Starlette's BaseHTTPMiddleware class, so much so that some are proposing to deprecate it.

    Should we shift the implementation to be a completely ASGI-based implementation?

    opened by twcurrie 8
  • Documentation?

    Documentation?

    Hi, I was looking for a way to rate limit my production FastAPI backend and I stumbled upon this repo, which seems to meet my needs, but lacks documentation. I was able to grasp some stuff from the examples and by reading the source code, but is there any chance to find proper documentation for this project?

    Best Regards, and thanks for making this!

    opened by nocturn9x 8
  • Dynamic rate limit based on user type

    Dynamic rate limit based on user type

    I need a way to dynamically set the rate limit based on the user type.

    For example, I want to limit users without access token & have unlimited access to users with the access token.

    What I am currently using:

    
    limiter = Limiter(key_func=identify_my_user_func)
    app.state.limiter = limiter
    app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
    
    def identify_my_user_func(request: Request):
        if 'access_token' not in request.query_params:
            return request.client.host
        return "REGISTERED_USER"
    
    @limiter.limit("2/minute")
    def some_request(request: Request)):
         return data
    
    

    I am trying to find a way to conditionally limit 2/minute. Basically I want to increase the limit based on the user type.

    opened by sdklab007 7
  • Using slowapi in bigger application

    Using slowapi in bigger application

    In test.py from app is run:

    import uvicorn
    
    from app.main import app
    
    if __name__ == "__main__":
        uvicorn.run("test:app", host="0.0.0.0", port=8000, reload=True)
    
    

    In main.py

    from app.api.api_v1.api import router as api_router
    from fastapi import FastAPI
    from slowapi import Limiter, _rate_limit_exceeded_handler
    from slowapi.util import get_remote_address
    from slowapi.errors import RateLimitExceeded
    def get_application() -> FastAPI:
         application = FastAPI(title=PROJECT_NAME, debug=DEBUG, version=VERSION)
         application.add_event_handler(
            "startup", create_start_app_handler(application))
         application.add_event_handler(
            "shutdown", create_stop_app_handler(application))
        application.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
        application.include_router(api_router, prefix=API_PREFIX)
    
         return application
    app = get_application()
    

    In endpoint user.py, how to use @limiter.limit("5/minute") ?

    from starlette.requests import Request
    router = APIRouter()
    @router.post('/show',
                 tags=["show"],
                 name="show:show")
    async def homepage(request: Request):
            return PlainTextResponse("test")
    ***code****
    

    In this use case how to use slowapi in endpoint. I need to limit to 5 requests per minute per user only and block that user for a minute Sleep and retry after a minute

    In api.py

    from app.api.api_v1.endpoints.show import router as ShowRouter
    
    router = APIRouter()
    
    
    
    router.include_router(ShowRouter, tags=["show"], prefix="/show")
    opened by himalacharya 6
  • add redis as extra package

    add redis as extra package

    So Redis is not directly use in slowapi but is used by the dependency of it, limiter and is downgrading redis package ( this project has older version of it) which is already used in our project.

    So we can add redis as a extra package.

    This PR is for that @laurentS

    opened by ME-ON1 5
  • Migrate to async

    Migrate to async

    Relates to #55

    Changes

    • All methods are now async/await coroutines.
    • Synchronous routes are run in a threadpool from an async wrapper, like how Starlette does it.
    • Blocking calls to limits storage backends or limiters is also executed in a threadpool.

    NOTE: Decorated functions now always become async coroutines, which should not cause any issues unless developers are invoking their routes directly.

    opened by thearchitector 5
  • Limit Http Headers

    Limit Http Headers

    I'm setting a rate limit for a route as below

    from slowapi import Limiter, _rate_limit_exceeded_handler from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address, headers_enabled=True)

    @router.post("/send-verification-otp", response_model=schemas.Msg) @limiter.limit("1/1 minute") def send_verification_otp(

    Check the below error:

    AttributeError: 'dict' object has no attribute 'headers'

    opened by moayyadfaris 5
  • Return a custom JSON-like object when rate limit is hit

    Return a custom JSON-like object when rate limit is hit

    I know it is possible to specify the error message in the limit decorator, but I'm building a very complex API and all of my requests need to be consistent and follow a specific schema that I represented using a pydantic.BaseModel subclass (basically a dataclass on steroids). Is it possible to return such a custom object instead of the default starlette.responses.JSONResponse?

    My response looks like this (once converted to a dictionary)

    {"request_id" : "foobarbaz", "status_code": 416, "response_data": None, "error_message" : "Unsupported media type"}

    opened by nocturn9x 5
  • Encountered an error reporting: AttributeError: 'State' object has no attribute 'view_rate_limit'

    Encountered an error reporting: AttributeError: 'State' object has no attribute 'view_rate_limit'

    Code reproduction:

    slowapi code configuration

    from slowapi.errors import RateLimitExceeded
    from slowapi.middleware import SlowAPIMiddleware
    
    
    def limiter_key_func(request: Request) -> str:
        ip = request.headers.get("CF-Connecting-IP") or get_remote_address(request)
        return ip
        
    limiter = Limiter(key_func=limiter_key_func, default_limits=["1/second"])
    
    def rate_limit_exceeded_handler(request: Request, exc: RateLimitExceeded) -> Response:
        .
        .
        .
        response = JSONResponse(content={"code": 429, "data": data, "msg": msg}, status_code=429)
        response = request.app.state.limiter._inject_headers(response, request.state.view_rate_limit)
        return response
        
        
    
    
    app.state.limiter = limiter
    app.add_exception_handler(RateLimitExceeded, rate_limit_exceeded_handler)
    app.add_middleware(SlowAPIMiddleware)
    

    This is my interface code

    @app.get('/demo1')
    @limiter.limit("100/day", override_defaults=False)
    async def channel(request: Request):
        return Response("A")
      
    @app.get('/demo2')
    @limiter.exempt
    async def channel(request: Request):
        return Response("B")
    

    When I request the interface demo1 I get the error AttributeError: 'State' object has no attribute 'view_rate_limit', When I comment out the @limiter.exempt and then request the interface demo1, it works fine.

    The following is the complete log of errors reported.

    INFO:     127.0.0.1:12134 - "GET /demo1 HTTP/1.1" 500 Internal Server Error
    ERROR     2022-10-11 13:22:55.444 - uvicorn.protocols.http.httptools_impl:run_asgi - Exception in ASGI application
    Traceback (most recent call last):
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\anyio\streams\memory.py", line 81, in receive
        return self.receive_nowait()
               │    └ <function MemoryObjectReceiveStream.receive_nowait at 0x000001BAD1BD8280>
               └ MemoryObjectReceiveStream(_state=MemoryObjectStreamState(max_buffer_size=0, buffer=deque([]), open_send_channels=0, open_rece...
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\anyio\streams\memory.py", line 76, in receive_nowait
        raise WouldBlock
              └ <class 'anyio.WouldBlock'>
    
    anyio.WouldBlock
    
    
    During handling of the above exception, another exception occurred:
    
    
    Traceback (most recent call last):
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 43, in call_next
        message = await recv_stream.receive()
                        │           └ <function MemoryObjectReceiveStream.receive at 0x000001BAD1BD8310>
                        └ MemoryObjectReceiveStream(_state=MemoryObjectStreamState(max_buffer_size=0, buffer=deque([]), open_send_channels=0, open_rece...
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\anyio\streams\memory.py", line 101, in receive
        raise EndOfStream
              └ <class 'anyio.EndOfStream'>
    
    anyio.EndOfStream
    
    
    During handling of the above exception, another exception occurred:
    
    
    Traceback (most recent call last):
    
      File "xxx\PycharmProjects\public_service2\app\main.py", line 10, in <module>
        uvicorn.run(app=app, host="0.0.0.0", port=PORT, log_level="info", forwarded_allow_ips="*", access_log=True,
        │       │       │                         └ 8080
        │       │       └ <fastapi.applications.FastAPI object at 0x000001BAD1ADC8B0>
        │       └ <function run at 0x000001BACF787A30>
        └ <module 'uvicorn' from 'xxx\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packages\\uvicorn\\__init__....
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\main.py", line 447, in run
        server.run()
        │      └ <function Server.run at 0x000001BACF787D00>
        └ <uvicorn.server.Server object at 0x000001BAD275D960>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\server.py", line 68, in run
        return asyncio.run(self.serve(sockets=sockets))
               │       │   │    │             └ None
               │       │   │    └ <function Server.serve at 0x000001BACF787D90>
               │       │   └ <uvicorn.server.Server object at 0x000001BAD275D960>
               │       └ <function run at 0x000001BACF4FB250>
               └ <module 'asyncio' from 'xxx\\AppData\\Local\\Programs\\Python\\Python310\\lib\\asyncio\\__init__.py'>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run
        return loop.run_until_complete(main)
               │    │                  └ <coroutine object Server.serve at 0x000001BAD273E030>
               │    └ <function BaseEventLoop.run_until_complete at 0x000001BACF504CA0>
               └ <_WindowsSelectorEventLoop running=True closed=False debug=False>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 628, in run_until_complete
        self.run_forever()
        │    └ <function BaseEventLoop.run_forever at 0x000001BACF504C10>
        └ <_WindowsSelectorEventLoop running=True closed=False debug=False>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 595, in run_forever
        self._run_once()
        │    └ <function BaseEventLoop._run_once at 0x000001BACF506710>
        └ <_WindowsSelectorEventLoop running=True closed=False debug=False>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 1881, in _run_once
        handle._run()
        │      └ <function Handle._run at 0x000001BACF4A5E10>
        └ <Handle <TaskStepMethWrapper object at 0x000001BAD29004C0>()>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\asyncio\events.py", line 80, in _run
        self._context.run(self._callback, *self._args)
        │    │            │    │           │    └ <member '_args' of 'Handle' objects>
        │    │            │    │           └ <Handle <TaskStepMethWrapper object at 0x000001BAD29004C0>()>
        │    │            │    └ <member '_callback' of 'Handle' objects>
        │    │            └ <Handle <TaskStepMethWrapper object at 0x000001BAD29004C0>()>
        │    └ <member '_context' of 'Handle' objects>
        └ <Handle <TaskStepMethWrapper object at 0x000001BAD29004C0>()>
    
    > File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 375, in run_asgi
        result = await app(self.scope, self.receive, self.send)
                       │   │    │      │    │        │    └ <function RequestResponseCycle.send at 0x000001BAD27CC8B0>
                       │   │    │      │    │        └ <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2886920>
                       │   │    │      │    └ <function RequestResponseCycle.receive at 0x000001BAD27CC940>
                       │   │    │      └ <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2886920>
                       │   │    └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
                       │   └ <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2886920>
                       └ <uvicorn.middleware.proxy_headers.ProxyHeadersMiddleware object at 0x000001BAD278ECE0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__
        return await self.app(scope, receive, send)
                     │    │   │      │        └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2...
                     │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
                     │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
                     │    └ <fastapi.applications.FastAPI object at 0x000001BAD1ADC8B0>
                     └ <uvicorn.middleware.proxy_headers.ProxyHeadersMiddleware object at 0x000001BAD278ECE0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\fastapi\applications.py", line 269, in __call__
        await super().__call__(scope, receive, send)
                               │      │        └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2...
                               │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
                               └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\applications.py", line 124, in __call__
        await self.middleware_stack(scope, receive, send)
              │    │                │      │        └ <bound method RequestResponseCycle.send of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001BAD2...
              │    │                │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │                └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x000001BAD278E830>
              └ <fastapi.applications.FastAPI object at 0x000001BAD1ADC8B0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
        raise exc
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
        await self.app(scope, receive, _send)
              │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x000001BAD2848790>
              │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <starlette.middleware.cors.CORSMiddleware object at 0x000001BAD278E800>
              └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x000001BAD278E830>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\cors.py", line 84, in __call__
        await self.app(scope, receive, send)
              │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x000001BAD2848790>
              │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <starlette.middleware.base.BaseHTTPMiddleware object at 0x000001BAD278E7A0>
              └ <starlette.middleware.cors.CORSMiddleware object at 0x000001BAD278E800>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 68, in __call__
        response = await self.dispatch_func(request, call_next)
                         │    │             │        └ <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x000001BAD2848820>
                         │    │             └ <starlette.requests.Request object at 0x000001BAD2835CC0>
                         │    └ <function mid at 0x000001BAD277E4D0>
                         └ <starlette.middleware.base.BaseHTTPMiddleware object at 0x000001BAD278E7A0>
    
      File "xxx\PycharmProjects\public_service2\app\api\__init__.py", line 92, in mid
        response = await call_next(request)
                         │         └ <starlette.requests.Request object at 0x000001BAD2835CC0>
                         └ <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x000001BAD2848820>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 46, in call_next
        raise app_exc
              └ AttributeError("'State' object has no attribute 'view_rate_limit'")
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 36, in coro
        await self.app(scope, request.receive, send_stream.send)
              │    │   │      │       │        │           └ <function MemoryObjectSendStream.send at 0x000001BAD1BD8A60>
              │    │   │      │       │        └ MemoryObjectSendStream(_state=MemoryObjectStreamState(max_buffer_size=0, buffer=deque([]), open_send_channels=0, open_receive...
              │    │   │      │       └ <property object at 0x000001BAD265D170>
              │    │   │      └ <starlette.requests.Request object at 0x000001BAD2835CC0>
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <slowapi.middleware.SlowAPIMiddleware object at 0x000001BAD278E3B0>
              └ <starlette.middleware.base.BaseHTTPMiddleware object at 0x000001BAD278E7A0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 68, in __call__
        response = await self.dispatch_func(request, call_next)
                         │    │             │        └ <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x000001BAD2849630>
                         │    │             └ <starlette.requests.Request object at 0x000001BAD2900280>
                         │    └ <bound method SlowAPIMiddleware.dispatch of <slowapi.middleware.SlowAPIMiddleware object at 0x000001BAD278E3B0>>
                         └ <slowapi.middleware.SlowAPIMiddleware object at 0x000001BAD278E3B0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\slowapi\middleware.py", line 34, in dispatch
        return await call_next(request)
                     │         └ <starlette.requests.Request object at 0x000001BAD2900280>
                     └ <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x000001BAD2849630>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 46, in call_next
        raise app_exc
              └ AttributeError("'State' object has no attribute 'view_rate_limit'")
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\middleware\base.py", line 36, in coro
        await self.app(scope, request.receive, send_stream.send)
              │    │   │      │       │        │           └ <function MemoryObjectSendStream.send at 0x000001BAD1BD8A60>
              │    │   │      │       │        └ MemoryObjectSendStream(_state=MemoryObjectStreamState(max_buffer_size=0, buffer=deque([]), open_send_channels=0, open_receive...
              │    │   │      │       └ <property object at 0x000001BAD265D170>
              │    │   │      └ <starlette.requests.Request object at 0x000001BAD2900280>
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <starlette.exceptions.ExceptionMiddleware object at 0x000001BAD278E380>
              └ <slowapi.middleware.SlowAPIMiddleware object at 0x000001BAD278E3B0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\exceptions.py", line 93, in __call__
        raise exc
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\exceptions.py", line 82, in __call__
        await self.app(scope, receive, sender)
              │    │   │      │        └ <function ExceptionMiddleware.__call__.<locals>.sender at 0x000001BAD28FB880>
              │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <fastapi.middleware.asyncexitstack.AsyncExitStackMiddleware object at 0x000001BAD278E140>
              └ <starlette.exceptions.ExceptionMiddleware object at 0x000001BAD278E380>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__
        raise e
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
        await self.app(scope, receive, send)
              │    │   │      │        └ <function ExceptionMiddleware.__call__.<locals>.sender at 0x000001BAD28FB880>
              │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <fastapi.routing.APIRouter object at 0x000001BAD1ADC9A0>
              └ <fastapi.middleware.asyncexitstack.AsyncExitStackMiddleware object at 0x000001BAD278E140>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\routing.py", line 670, in __call__
        await route.handle(scope, receive, send)
              │     │      │      │        └ <function ExceptionMiddleware.__call__.<locals>.sender at 0x000001BAD28FB880>
              │     │      │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │     │      └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │     └ <function Route.handle at 0x000001BAD2685750>
              └ <fastapi.routing.APIRoute object at 0x000001BAD275DDE0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\routing.py", line 266, in handle
        await self.app(scope, receive, send)
              │    │   │      │        └ <function ExceptionMiddleware.__call__.<locals>.sender at 0x000001BAD28FB880>
              │    │   │      └ <bound method RequestResponseCycle.receive of <uvicorn.protocols.http.httptools_impl.RequestResponseCycle object at 0x000001B...
              │    │   └ {'type': 'http', 'asgi': {'version': '3.0', 'spec_version': '2.1'}, 'http_version': '1.1', 'server': ('127.0.0.1', 8080), 'cl...
              │    └ <function request_response.<locals>.app at 0x000001BAD277CB80>
              └ <fastapi.routing.APIRoute object at 0x000001BAD275DDE0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\routing.py", line 65, in app
        response = await func(request)
                         │    └ <starlette.requests.Request object at 0x000001BAD2900670>
                         └ <function get_request_handler.<locals>.app at 0x000001BAD277CAF0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\fastapi\routing.py", line 227, in app
        raw_response = await run_endpoint_function(
                             └ <function run_endpoint_function at 0x000001BAD26863B0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\fastapi\routing.py", line 160, in run_endpoint_function
        return await dependant.call(**values)
                     │         │      └ {'x': '', 'x': 'xxx', 'x': 'xxx', 'request': <starlette.requests.Request object at 0x000001BAD2900670>}
                     │         └ <function channel at 0x000001BAD2705B40>
                     └ <fastapi.dependencies.models.Dependant object at 0x000001BAD275DED0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\slowapi\extension.py", line 646, in async_wrapper
        response, request.state.view_rate_limit
        │         │       └ <property object at 0x000001BAD265D080>
        │         └ <starlette.requests.Request object at 0x000001BAD2900670>
        └ <starlette.responses.Response object at 0x000001BAD29008E0>
    
      File "xxx\AppData\Local\Programs\Python\Python310\lib\site-packages\starlette\datastructures.py", line 693, in __getattr__
        raise AttributeError(message.format(self.__class__.__name__, key))
                             │       │      │    │         │         └ 'view_rate_limit'
                             │       │      │    │         └ <member '__name__' of 'getset_descriptor' objects>
                             │       │      │    └ <attribute '__class__' of 'object' objects>
                             │       │      └ <starlette.datastructures.State object at 0x000001BAD29008B0>
                             │       └ <method 'format' of 'str' objects>
                             └ "'{}' object has no attribute '{}'"
    
    AttributeError: 'State' object has no attribute 'view_rate_limit'
    
    SUCCESS   2022-10-11 13:22:56.883 - app.utile:init - init final
    
    
    

    I don't know how to fix this error and I need help.

    opened by 239144498 4
  • Error in production

    Error in production

    Describe the bug Use Gunicorn in production

    To Reproduce Use gunicorn for start and call a endpoint with limit

    Expected behavior do nothing

    Screenshots If applicable, add screenshots to help explain your problem. Oct 25 20:16:46 gunicorn[12540]: return await dependant.call(**values) Oct 25 20:16:46 gunicorn[12540]: File "/home/ubuntu/proyect/api/env/lib/python3.10/site-packages/slowapi/extension.py", line 635, in async_wrapper Oct 25 20:16:46 gunicorn[12540]: self._check_request_limit(request, func, False) Oct 25 20:16:46 gunicorn[12540]: File "/home/ubuntu/proyect/api/env/lib/python3.10/site-packages/slowapi/extension.py", line 535, in _check_request_limit Oct 25 20:16:46 gunicorn[12540]: self.__evaluate_limits(request, endpoint, all_limits) Oct 25 20:16:46 gunicorn[12540]: File "/home/ubuntu/proyect/api/env/lib/python3.10/site-packages/slowapi/extension.py", line 413, in __evaluate_limits Oct 25 20:16:46 gunicorn[12540]: limit_key = lim.key_func(request) Oct 25 20:16:46 gunicorn[12540]: File "/home/ubuntu/proyect/api/env/lib/python3.10/site-packages/slowapi/util.py", line 21, in get_remote_address Oct 25 20:16:46 gunicorn[12540]: return request.client.host or "127.0.0.1" Oct 25 20:16:46 gunicorn[12540]: AttributeError: 'NoneType' object has no attribute 'host'

    Your app (please complete the following information):

    • fastapi or starlette? use fastapi
    • Version? - 0.79.0 and 0.85.1
    • slowapi version (have you tried with the latest version)? yes, is 0.85.1

    Additional context y set the api in production, and get this error

    opened by juanretamales 5
  • Information on ratelimit-string

    Information on ratelimit-string

    Throughout the code and docs, it says to refer to ratelimit-string for more information on what are valid inputs. However, I am unable to find information on this and have just guessed so far for my usage. I would appreciate information on all the options

    opened by mallorbc 3
  • Publish release to testpypi from github actions

    Publish release to testpypi from github actions

    This is a draft of what an automatic package publishing workflow could look like.

    TODO:

    • [ ] Add automatic changelogs
    • [ ] Allow publishing only from master branch
    • [ ] Restrict publishing to allowed contributors
    • [ ] switch from testpypi to production pypi once everything else is done
    opened by laurentS 2
  • Can slowapi be used in production?

    Can slowapi be used in production?

    The documention says: Note: this is alpha quality code still, the API may change, and things may fall apart while you try it.

    Because of that I am unsure if it can be used in production.

    opened by krissik 1
Owner
Laurent Savaete
Core dev mapswipe/mapswipe Core team madada.fr author of slowapi
Laurent Savaete
FastAPI Admin Dashboard based on FastAPI and Tortoise ORM.

FastAPI ADMIN 中文文档 Introduction FastAPI-Admin is a admin dashboard based on fastapi and tortoise-orm. FastAPI-Admin provide crud feature out-of-the-bo

long2ice 1.6k Dec 31, 2022
ASGI middleware for authentication, rate limiting, and building CRUD endpoints.

Piccolo API Utilities for easily exposing Piccolo models as REST endpoints in ASGI apps, such as Starlette and FastAPI. Includes a bunch of useful ASG

null 81 Dec 9, 2022
Backend, modern REST API for obtaining match and odds data crawled from multiple sites. Using FastAPI, MongoDB as database, Motor as async MongoDB client, Scrapy as crawler and Docker.

Introduction Apiestas is a project composed of a backend powered by the awesome framework FastAPI and a crawler powered by Scrapy. This project has fo

Fran Lozano 54 Dec 13, 2022
Minimal example utilizing fastapi and celery with RabbitMQ for task queue, Redis for celery backend and flower for monitoring the celery tasks.

FastAPI with Celery Minimal example utilizing FastAPI and Celery with RabbitMQ for task queue, Redis for Celery backend and flower for monitoring the

Grega Vrbančič 371 Jan 1, 2023
Example app using FastAPI and JWT

FastAPI-Auth Example app using FastAPI and JWT virtualenv -p python3 venv source venv/bin/activate pip3 install -r requirements.txt mv config.yaml.exa

Sander 28 Oct 25, 2022
Backend Skeleton using FastAPI and Sqlalchemy ORM

Backend API Skeleton Based on @tiangolo's full stack postgres template, with some things added, some things removed, and some things changed. This is

David Montague 18 Oct 31, 2022
A simple docker-compose app for orchestrating a fastapi application, a celery queue with rabbitmq(broker) and redis(backend)

fastapi - celery - rabbitmq - redis -> Docker A simple docker-compose app for orchestrating a fastapi application, a celery queue with rabbitmq(broker

Kartheekasasanka Kaipa 83 Dec 19, 2022
The template for building scalable web APIs based on FastAPI, Tortoise ORM and other.

FastAPI and Tortoise ORM. Powerful but simple template for web APIs w/ FastAPI (as web framework) and Tortoise-ORM (for working via database without h

prostomarkeloff 95 Jan 8, 2023
Ready-to-use and customizable users management for FastAPI

FastAPI Users Ready-to-use and customizable users management for FastAPI Documentation: https://frankie567.github.io/fastapi-users/ Source Code: https

François Voron 2.4k Jan 1, 2023
TODO aplication made with Python's FastAPI framework and Hexagonal Architecture

FastAPI Todolist Description Todolist aplication made with Python's FastAPI framework and Hexagonal Architecture. This is a test repository for the pu

Giovanni Armane 91 Dec 31, 2022
Deploy an inference API on AWS (EC2) using FastAPI Docker and Github Actions

Deploy an inference API on AWS (EC2) using FastAPI Docker and Github Actions To learn more about this project: medium blog post The goal of this proje

Ahmed BESBES 60 Dec 17, 2022
REST API with FastAPI and SQLite3.

REST API with FastAPI and SQLite3

Luis Quiñones Requelme 2 Mar 14, 2022
Example of using FastAPI and MongoDB database.

FastAPI Todo Application Example of using FastAPI and MangoDB database. ?? Prerequisites Python ⚙️ Build & Run The first thing to do is to clone the r

Bobynets Ivan 1 Oct 29, 2021
Async and Sync wrapper client around httpx, fastapi, date stuff

lazyapi Async and Sync wrapper client around httpx, fastapi, and datetime stuff. Motivation This library is forked from an internal project that works

null 2 Apr 19, 2022
Basic FastAPI starter with GraphQL, Docker, and MongoDB configurations.

FastAPI + GraphQL Starter A python starter project using FastAPI and GraphQL. This project leverages docker for containerization and provides the scri

Cloud Bytes Collection 1 Nov 24, 2022
FastAPI Learning Example,对应中文视频学习教程:https://space.bilibili.com/396891097

视频教学地址 中文学习教程 1、本教程每一个案例都可以独立跑,前提是安装好依赖包。 2、本教程并未按照官方教程顺序,而是按照实际使用顺序编排。 Video Teaching Address FastAPI Learning Example 1.Each case in this tutorial c

null 381 Dec 11, 2022
🤪 FastAPI + Vue构建的Mall项目后台管理

Mall项目后台管理 前段时间学习Vue写了一个移动端项目 https://www.charmcode.cn/app/mall/home 然后教程到此就结束了, 我就总感觉少点什么,计划自己着手写一套后台管理。 相关项目 移动端Mall项目源码(Vue构建): https://github.com/

王小右 131 Jan 1, 2023
FastAPI on Google Cloud Run

cloudrun-fastapi Boilerplate for running FastAPI on Google Cloud Run with Google Cloud Build for deployment. For all documentation visit the docs fold

Anthony Corletti 139 Dec 27, 2022
FastAPI + Django experiment

django-fastapi-example This is an experiment to demonstrate one potential way of running FastAPI with Django. It won't be actively maintained. If you'

Jordan Eremieff 78 Jan 3, 2023