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

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

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

setup_kwargs = {
    'name': 'throttled',
    'version': '0.2.1',
    '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. The code base is 99% covered by unit and integration tests. It is also full type checked with type hints, assuring code with great 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 backends (different implementations for `BaseStorage`) for each limiter.\n  - Want to limit 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](https://github.com/redis/redis-py) package. Other implementations + asyncio support are coming...\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\nThe package is in an early development stage. This means the API can change a lot along the way, before hitting 1.0.0,\ngiven community feedback. I recommend you pin the latest version that works for you when using the library for now.\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   Disclaimer: generalize getting IP from the `Request` object is not easy, because there is [too many variations in the community](https://en.wikipedia.org/wiki/Talk:X-Forwarded-For#Variations). The `IPLimiter` works when hitting the API running on `uvicorn` from another docker container. However, reverse proxies can complicate things. Notwithstanding, the `ThrottledAPI` archtecture allows creating limiters as you like, so there is nothing stopping you from creating an IP limiter that fits your infrastructure. You can also submit it here as a PR, and I will be glad to merge it in the codebase, given instructions for when to use it. \n\n### Implement custom limiters\n\nYou can implement new limiters easily extending from `FastAPILimiter` or `MiddlewareLimiter`\n\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: 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\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 powerful, 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\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: Limiting 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 limiting 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\n## Contributing\n\nIssues, suggestions, PRs are welcome!\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)
