# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['throttled', 'throttled.fastapi', 'throttled.storage']

package_data = \
{'': ['*']}

setup_kwargs = {
    'name': 'throttled',
    'version': '0.2.0',
    'description': 'A rate limiter for FastAPI',
    'long_description': '# ThrottledAPI\n\nThrottledAPI is a rate limiter for FastAPI. \nCheck [our features](tests/acceptance/features/fastapi_limiter.feature) to see the use-cases already tested.\nDespite only a few acceptance tests, the code base is 99% tested by unit and integration tests. It is also full checked with \ntype hints, assuring code great code quality.\n\n## Why another rate limiter for FastAPI?\n\nWhy another rate limiter for FastAPI, if we already have \n[slowapi](https://github.com/laurentS/slowapi) and \n[fastapi-limiter](https://github.com/long2ice/fastapi-limiter)? This limiter glues what is good from both projects and \nadds a bit more. Here is a list of reasons:\n\n- The `throttled-api` rate limiter takes full advantage from the composable dependency injection system in FastAPI. \nThat means you can also create limiters per resource.\n    - Want to limit requests per IP or per user? Got it! \n    - Want to limit requests based on another weird parameter you are receiving? Just extend our `FastAPILimiter` and you\nare good to go!\n- You can use different storage storages backends (different implementations for `BaseStorage`) for each limiter.\n    - Want to each API instance to 2000 requests per second? You don´t need more than a *in-memory* counter.\nJust use `MemoryStorage` for the task.\n    - Want to limit calls to all your API instances by user or IP? A shared cache is what you need. \nOur `RedisStorage` implementation is an adapter for the famous `redis` package. Other implementations + asyncio support are comming...\n\n## Install\n\nJust use your favorite python package manager. Here are two examples:\n\n- With pip: `pip install throttled`\n- With poetry: `poetry add throttled`\n\n## Use\n\n### Use existing limiters\n\nWe already implemented `TotalLimiter` and `IPLimiter` for you:\n\n- `TotalLimiter`: limits all calls to your API, so you can assure it won\'t suffocate with too many requests.\n- `IPLimiter`: as the name suggests, limits requests by IP.\n\n### Implement custom limiters\n\nYou can implement new limiters easily extending from `FastAPILimiter` or `MiddlewareLimiter`\n```python\n# Your IDE will help you find the imports\n\nclass UserLimiter(FastAPILimiter):\n    """Client specific limiter"""\n\n    def __call__(self, request: Request, user: Optional[UserID] = Depends(get_current_user)):\n        # The request parameter is mandatory\n        self.limit(key=f"username={user.username}")\n```\n\n### Attach to the API\n\nThere are two options when using the limiters in your API\n\n#### All limiters as dependencies\n\nThis is the simplest usage, requiring less code\n```python\ndef create_limiters() -> Sequence[FastAPILimiter]:\n    memory = MemoryStorage(cache={})\n    api_limiter = TotalLimiter(limit=Rate(2000, 1), storage=memory)\n    \n    redis = RedisStorage(client=Redis.from_url("redis://localhost:0"))\n    ip_limiter = IPLimiter(limit=Rate(10, 1), storage=redis)\n    user_limiter = UserLimiter(limit=Rate(2, 5), storage=redis)\n    \n    return api_limiter, ip_limiter, user_limiter\n\n\ndef create_app(limiters: Sequence[FastAPILimiter] = tuple()) -> FastAPI:\n    """Creates a FastAPI app with attached limiters and routes"""\n    api = FastAPI(title="Snacks bar", dependencies=limiters)\n\n    api.include_router(products_router, prefix="/products")\n    api.include_router(users_router, prefix="/users")\n    return api\n\n\napp = create_app(limiters=create_limiters())\n```\n\n#### Some limiters as middlewares\n\nAlthough FastAPI dependency injection is really powerfull, some limiters doesn´t require any special resource in \nother to do their job. In that case you cut some latency if using the limiter as a Middleware. \n```python\ndef create_app(limiters: Sequence[FastAPILimiter] = tuple()) -> FastAPI:\n    """Creates a FastAPI app with attached limiters and routes"""\n    dependencies, middlewares = split_dependencies_and_middlewares(*limiters)\n\n    api = FastAPI(title="Snacks bar", dependencies=dependencies)\n\n    api.include_router(products_router, prefix="/products")\n    api.include_router(users_router, prefix="/users")\n\n    for mid in middlewares:\n        api.add_middleware(BaseHTTPMiddleware, dispatch=mid)\n        \n    return api\n\n\napp = create_app(limiters=create_limiters())  # create_limiter: same function above\n```\n\n## Middleware vs Dependency\n\nWhen implementing a custom limiter, how to choose between extending `FastAPILimiter` or `MiddlewareLimiter`?\n\n```mermaid\nstateDiagram-v2\n    state FirstCondition <<choice>>\n    state SecondCondition <<choice>>\n    \n    FirstQuestion: What type of limiter should I choose?\n    FirstQuestion --> FirstCondition\n    \n    FirstCondition: Limitting depends on resources other\\nthan Request object from Starlette?\n    FirstCondition --> FastAPILimiter: yes\n    FirstCondition --> MiddlewareLimiter : no\n    FastAPILimiter --> SecondQuestion\n    MiddlewareLimiter --> SecondQuestion\n    \n    SecondQuestion: What storage should I pick?\n    SecondQuestion --> SecondCondition\n    SecondCondition: The parameters you are limitting spams a parameter space.\\n Is that space too large?\n    SecondCondition --> RedisStorage : yes\n    SecondCondition --> ThirdCondition : no\n    \n    ThirdCondition: You want to share the limiter\\nbetween different API instances (pods)?\n    ThirdCondition --> RedisStorage : yes\n    ThirdCondition --> MemoryStorage : no\n    \n    RedisStorage --> End\n    MemoryStorage --> End\n    End: Attach the limiter to your API     \n```\n',
    'author': 'Vinícius Vargas',
    'author_email': 'santunionivinicius@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/santunioni/ThrottledAPI',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
