{"id":16105096,"url":"https://github.com/uriyyo/fastapi-async-safe-dependencies","last_synced_at":"2025-03-18T08:31:38.146Z","repository":{"id":218036205,"uuid":"745424260","full_name":"uriyyo/fastapi-async-safe-dependencies","owner":"uriyyo","description":"FastAPI async safe dependencies 🪢","archived":false,"fork":false,"pushed_at":"2024-10-30T03:09:33.000Z","size":1462,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-30T08:28:23.269Z","etag":null,"topics":["asyncio","fastapi","fastapi-boilerplate","fastapi-extension","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uriyyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-19T09:59:17.000Z","updated_at":"2024-10-30T03:09:30.000Z","dependencies_parsed_at":"2024-03-25T04:33:08.019Z","dependency_job_id":"c4bb4aa6-54be-41d5-8437-dd31f73cc7c7","html_url":"https://github.com/uriyyo/fastapi-async-safe-dependencies","commit_stats":null,"previous_names":["uriyyo/fastapi-async-safe-dependencies"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-async-safe-dependencies","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-async-safe-dependencies/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-async-safe-dependencies/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-async-safe-dependencies/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uriyyo","download_url":"https://codeload.github.com/uriyyo/fastapi-async-safe-dependencies/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243910749,"owners_count":20367545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","fastapi","fastapi-boilerplate","fastapi-extension","python"],"created_at":"2024-10-09T19:08:23.885Z","updated_at":"2025-03-18T08:31:37.522Z","avatar_url":"https://github.com/uriyyo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FastAPI Async Safe Dependencies\n\n# Installation\n\n```bash\npip install fastapi-async-safe-dependencies\n```\n\n# Introduction\n\nFastAPI is a great framework for building APIs and the main purpose of this library is to make it a little bit better.\nI guess someone (as I do) has a lot of class-based dependencies in your project.\nBut FastAPI comes with one little problem that will make your application slower than it could be.\n\nLet's take a look at the following example from FastAPI documentation:\n\n```python\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\nfake_items_db = [\n    {\"item_name\": \"Foo\"},\n    {\"item_name\": \"Bar\"},\n    {\"item_name\": \"Baz\"},\n]\n\nclass CommonQueryParams:\n    def __init__(\n        self,\n        q: str | None = None,\n        skip: int = 0,\n        limit: int = 100,\n    ) -\u003e None:\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonQueryParams = Depends()):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip: commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n```\n\nThis example is pretty simple and it works fine, but it has one little problem.\nWhenever FastAPI tries to resolve `CommonQueryParams` dependency it will delegate object creation to\nthe thread-pool executor, which is not good for performance. It will happen with every request.\n\nFastAPI logic is pretty simple, if `asyncio.iscoroutinefunction` returns `True` for the dependency, it will be called\nas a simple coroutine, otherwise, it will be delegated to a thread-pool executor.\n\nFastAPI is using `anyio.to_thread.run_sync` function to delegate object creation to the thread-pool executor.\n`anyio` thread-pool executor has a limited number of threads (40 by default) which means that if you have more than 40\nrequests at the same time, some of them might be blocked until one of the threads from the pool is released.\nThread will be blocked by simple class instantiation, this is not CPU intensive operation,\nthat is not the type of task you want to delegate to the thread-pool executor.\n\nThis library provides a simple solution for this problem, that will avoid unnecessary thread-pool executor usage\nfor class-based dependencies and it should improve your application performance.\n\n# Usage\n\nLet's take a look at the same example, but with `fastapi-async-safe-dependencies` library:\n\n```python\nfrom fastapi import Depends, FastAPI\nfrom fastapi_async_safe import async_safe, init_app\n\napp = FastAPI()\ninit_app(app)   # don't forget to initialize application\n\nfake_items_db = [\n    {\"item_name\": \"Foo\"},\n    {\"item_name\": \"Bar\"},\n    {\"item_name\": \"Baz\"},\n]\n\n@async_safe  # you just need to add this decorator to your dependency\nclass CommonQueryParams:\n    def __init__(\n        self,\n        q: str | None = None,\n        skip: int = 0,\n        limit: int = 100,\n    ) -\u003e None:\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonQueryParams = Depends()):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip: commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n```\n\nThat's it, now your dependency will be called as simple coroutine, and it will not be delegated to the thread-pool.\n\nCode above is equivalent to the following code:\n\n```python\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\nfake_items_db = [\n    {\"item_name\": \"Foo\"},\n    {\"item_name\": \"Bar\"},\n    {\"item_name\": \"Baz\"},\n]\n\nclass CommonQueryParams:\n    def __init__(\n        self,\n        q: str | None = None,\n        skip: int = 0,\n        limit: int = 100,\n    ) -\u003e None:\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\nasync def _common_query_params(\n    q: str | None = None,\n    skip: int = 0,\n    limit: int = 100,\n) -\u003e CommonQueryParams:\n    return CommonQueryParams(q=q, skip=skip, limit=limit)\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonQueryParams = Depends(_common_query_params)):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip: commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n```\n\n# Documentation\n\nAll you need to do is to add `@async_safe` decorator to your dependency class or synchronous function that\nshould not be delegated to the thread-pool executor.\n\n```python\nfrom typing import Any\nfrom dataclasses import dataclass\n\nfrom fastapi_async_safe import async_safe\n\n@dataclass\n@async_safe\nclass CommonQueryParams:\n    q: str | None = None\n    skip: int = 0\n    limit: int = 100\n\n\n@async_safe\ndef common_query_params(\n    q: str | None = None,\n    skip: int = 0,\n    limit: int = 100,\n) -\u003e dict[str, Any]:\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n```\n\nBoth `CommonQueryParams` class and `common_query_params` function will not be delegated to the thread-pool executor.\n\nIf your class inherits from a class that is decorated with `@async_safe` decorator then this class will be `async-safe` too.\n\n```python\nfrom dataclasses import dataclass\n\nfrom fastapi_async_safe import async_safe\n\n@dataclass\n@async_safe\nclass BaseQueryParams:\n    q: str | None = None\n\n\n@dataclass  # this class will be async-safe too\nclass CommonQueryParams(BaseQueryParams):\n    skip: int = 0\n    limit: int = 100\n```\n\nIf you don't want your inherited class to be `async-safe` you can use `@async_unsafe` decorator.\n\n```python\nfrom dataclasses import dataclass\n\nfrom fastapi_async_safe import async_safe, async_unsafe\n\n@dataclass\n@async_safe\nclass BaseQueryParams:\n    q: str | None = None\n\n\n@dataclass\n@async_unsafe  # this class no longer will be async-safe\nclass CommonQueryParams(BaseQueryParams):\n    skip: int = 0\n    limit: int = 100\n```\n\nAlso, don't forget to initialize your application with `init_app` function, otherwise, `@async_safe` decorator will not\nhave any effect. `init_app` function will monkey-patch `Dependant` instances on application startup.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi_async_safe import init_app\n\napp = FastAPI()\ninit_app(app)  # don't forget to initialize application !!!\n```\n\nIf you want to wrap all your class-based dependencies with `@async_safe` decorator you can pass `all_classes_safe=True`\nargument to `init_app` function. It will wrap all your class-based dependencies expect those that are decorated with\n`@async_unsafe` decorator.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi_async_safe import init_app\n\napp = FastAPI()\ninit_app(app, all_classes_safe=True)\n```\n\n# Benchmarks\n\nPlease take a look at the [benchmark](https://github.com/uriyyo/fastapi-async-safe-dependencies/tree/main/benchmark) directory for more details.\n\nPerformance boost depends on the number of class-based dependencies in your application, the more dependencies you have,\nthe more performance boost you will get.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furiyyo%2Ffastapi-async-safe-dependencies","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furiyyo%2Ffastapi-async-safe-dependencies","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furiyyo%2Ffastapi-async-safe-dependencies/lists"}