{"id":31635045,"url":"https://github.com/uriyyo/fastapi-backports","last_synced_at":"2026-05-15T22:31:18.385Z","repository":{"id":318150598,"uuid":"1070110358","full_name":"uriyyo/fastapi-backports","owner":"uriyyo","description":"Helpful backports for fastapi 🔄","archived":false,"fork":false,"pushed_at":"2025-10-05T13:13:23.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-05T13:26:44.681Z","etag":null,"topics":["asgi","backport","backports","fastapi","fastapi-extension","fastapi-utilities","fastapi-utils","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-05T09:39:11.000Z","updated_at":"2025-10-05T13:13:26.000Z","dependencies_parsed_at":"2025-10-05T13:26:48.711Z","dependency_job_id":null,"html_url":"https://github.com/uriyyo/fastapi-backports","commit_stats":null,"previous_names":["uriyyo/fastapi-backports"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/uriyyo/fastapi-backports","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-backports","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-backports/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-backports/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-backports/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uriyyo","download_url":"https://codeload.github.com/uriyyo/fastapi-backports/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uriyyo%2Ffastapi-backports/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278464314,"owners_count":25991176,"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","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["asgi","backport","backports","fastapi","fastapi-extension","fastapi-utilities","fastapi-utils","python"],"created_at":"2025-10-07T00:28:22.217Z","updated_at":"2026-05-15T22:31:18.378Z","avatar_url":"https://github.com/uriyyo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FastAPI Backports\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![FastAPI 0.115.0+](https://img.shields.io/badge/fastapi-0.115.0+-green.svg)](https://fastapi.tiangolo.com/)\n\nA Python library that provides backports for FastAPI features, allowing you to use newer FastAPI functionality on older\nversions. This includes both unreleased fixes and experimental features based on FastAPI community discussions that might be included in future FastAPI releases.\n\n## Features\n\nThis library includes backports for:\n\n### 🔄 Multiple Query Models Support\n\n- **Issue**: [Support multiple Query() in a single endpoint](https://github.com/fastapi/fastapi/discussions/12212)\n- **Description**: Enables using multiple Pydantic models as query parameters in a single FastAPI endpoint\n- **Benefits**: Better organization of query parameters and improved API design\n\n**What this fixes:**\n\n```python\nimport fastapi_backports.apply  # noqa: F401\n\nfrom dataclasses import dataclass\nfrom fastapi import Query, FastAPI\nfrom typing import Annotated, Any\n\n\n@dataclass\nclass FilterParams:\n    category: str | None = None\n    min_price: float | None = None\n\n\n@dataclass\nclass PaginationParams:\n    page: int = 1\n    size: int = 10\n\n\napp = FastAPI()\n\n\n# ❌ Without backport: This would not work as expected\n@app.get(\"/items\")\nasync def get_items(\n    filters: Annotated[FilterParams, Query()],\n    pagination: Annotated[PaginationParams, Query()],\n) -\u003e dict[str, Any]:\n    return {\"filters\": filters, \"pagination\": pagination}\n\n# ✅ With backport: This works perfectly!\n# Query parameters are properly flattened and validated\n# Example: /items?category=electronics\u0026min_price=10\u0026page=2\u0026size=20\n```\n\n### 🏷️ PEP 695 Type Alias Support\n\n- **Issue**: [Annotated dependencies are interpreted incorrectly when using PEP 695-style type alias](https://github.com/fastapi/fastapi/issues/10719)\n- **Description**: Fixes handling of modern Python type aliases (PEP 695) in FastAPI dependencies\n- **Benefits**: Full compatibility with modern Python typing features\n\n**What this fixes:**\n\n```python\nimport fastapi_backports.apply  # noqa: F401\n\nfrom typing import Annotated\nfrom fastapi import Depends, FastAPI\n\n\nasync def get_current_user_id() -\u003e int:\n    return 123\n\n\n# PEP 695 style type alias (Python 3.12+)\ntype UserId = Annotated[int, Depends(get_current_user_id)]\n\napp = FastAPI()\n\n\n# ❌ Without backport: FastAPI doesn't recognize the type alias properly\n# ✅ With backport: Type aliases work seamlessly in dependencies\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: UserId):\n    return {\"user_id\": user_id}\n```\n\n### 🕵️ Add middleware parameter to APIRouter\n\n- **Issue**: [Add middleware parameter to APIRouter](https://github.com/fastapi/fastapi/pull/11010)\n- **Description**: Enables adding middleware directly to APIRouter instances and individual routes\n- **Benefits**: Better middleware organization and route-specific middleware support\n\n**What this fixes:**\n\n```python\nimport fastapi_backports.apply  # noqa: F401\n\nfrom typing import Any\n\nfrom fastapi_backports import FastAPI, APIRouter\nfrom fastapi import Request\nfrom fastapi.middleware import Middleware\nfrom starlette.types import ASGIApp, Receive, Scope, Send\n\n\ndef add_header_middleware(_app: ASGIApp, header_name: str, header_value: str) -\u003e ASGIApp:\n    async def _middleware(scope: Scope, receive: Receive, send: Send) -\u003e None:\n        async def send_wrapper(message):\n            if message[\"type\"] == \"http.response.start\":\n                headers = message.setdefault(\"headers\", [])\n                headers.append((header_name.encode(), header_value.encode()))\n            await send(message)\n\n        await _app(scope, receive, send_wrapper)\n\n    return _middleware\n\n\napp = FastAPI()\n\n# ❌ Without backport: APIRouter doesn't accept middleware parameter\n# ✅ With backport: You can now add middleware to routers\nrouter = APIRouter(\n    prefix=\"/api/v1\",\n    middleware=[\n        Middleware(add_header_middleware, header_name=\"X-Custom-Header\", header_value=\"Value\")\n    ]\n)\n\n\n@router.get(\"/items\")\nasync def get_items() -\u003e dict[str, Any]:\n    return {\"items\": [\"item1\", \"item2\"]}\n\n\n# Middleware will be applied to all routes in this router\napp.include_router(router)\n```\n\n### 🔍 QUERY HTTP method support\n\n- **Issue**: [Will FastAPI support QUERY http method? \"app.query\"](https://github.com/fastapi/fastapi/issues/12965)\n- **Description**: Adds support for the QUERY HTTP method, allowing safe query operations with request bodies\n- **Benefits**: Enables complex queries with large payloads while maintaining REST semantics\n\n**What this fixes:**\n\n```python\nimport fastapi_backports.apply  # noqa: F401\n\nfrom typing import Any\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\nclass SearchQuery(BaseModel):\n    filters: dict[str, Any]\n    sort_by: str | None = None\n    limit: int = 100\n\napp = FastAPI()\n\n# ❌ Without backport: QUERY method not supported\n# ✅ With backport: You can now use the QUERY HTTP method\n@app.query(\"/search\")\nasync def search_items(query: SearchQuery) -\u003e dict[str, Any]:\n    return {\n        \"results\": [\"item1\", \"item2\", \"item3\"],\n        \"filters_applied\": query.filters,\n        \"sorted_by\": query.sort_by,\n        \"total\": 150\n    }\n\n# QUERY method allows complex search parameters in request body\n# while maintaining safe, idempotent semantics\n# Usage: QUERY /search with JSON body containing SearchQuery data\n```\n\n### 📝 Postponed Type Annotations Support\n\n- **Issue**: [Can't use Annotated with ForwardRef](https://github.com/fastapi/fastapi/issues/13056)\n- **Description**: Fixes handling of postponed type annotations (PEP 563) and forward references in FastAPI\n- **Benefits**: Enables proper type checking and dependency injection with complex type hierarchies\n\n**What this fixes:**\n\n```python\nfrom __future__ import annotations\n\nimport fastapi_backports.apply  # noqa: F401\n\nfrom dataclasses import dataclass\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\n# Forward reference to a class defined later\ndef get_potato() -\u003e Potato:\n    return Potato(color='red', size=10)\n\n\n# ❌ Without backport: ForwardRef causes issues with dependency injection\n# ✅ With backport: Forward references work seamlessly\n@app.get('/')\nasync def read_root(potato: Annotated[Potato, Depends(get_potato)]) -\u003e Potato:\n    return potato\n\n\n@dataclass\nclass Potato:\n    color: str\n    size: int\n```\n\n### 🔄 Multiple Lifespans Support\n\n- **Issue**: [Support multiple Lifespan in FastAPI app](https://github.com/fastapi/fastapi/discussions/9397)\n- **Description**: Enables adding multiple lifespan context managers to FastAPI applications and routers\n- **Benefits**: Better organization of startup/shutdown logic and modular lifespan management\n\n**What this fixes:**\n\n```python\nfrom contextlib import asynccontextmanager\nfrom typing import AsyncIterator, Any\n\nimport fastapi_backports.apply  # noqa: F401\n\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n# ❌ Without backport: Only one lifespan context is supported\n# ✅ With backport: You can add multiple lifespan contexts\n\n@app.add_lifespan\n@asynccontextmanager\nasync def database_lifespan(_app: FastAPI) -\u003e AsyncIterator[dict[str, Any]]:\n    print(\"Starting database connection\")\n    yield {\"db\": \"connection\"}\n    print(\"Closing database connection\")\n\n\n@app.add_lifespan\n@asynccontextmanager\nasync def cache_lifespan(_app: FastAPI) -\u003e AsyncIterator[dict[str, Any]]:\n    print(\"Starting cache\")\n    yield {\"cache\": \"connection\"}\n    print(\"Stopping cache\")\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"message\": \"Hello World\"}\n\n# Both lifespans will be executed in order during startup/shutdown\n```\n\n## Installation\n\n```bash\npip install fastapi-backports\n```\n\n## Usage\n\n### Basic Usage\n\nImport the backport module before using FastAPI:\n\n```python\nimport fastapi_backports.apply  # noqa: F401\nfrom fastapi import FastAPI, APIRouter\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n```\n\nThe backports are automatically applied when you import `fastapi_backports.apply`.\n\n\u003e [!NOTE]\n\u003e The `# noqa: F401` comment is needed to prevent linters from complaining about an \"unused import\". While\n\u003e the import appears unused, it actually applies the backports through side effects when imported.\n\n### Manual Backport Control\n\nFor more control over when backports are applied:\n\n```python\nimport fastapi_backports\nfrom fastapi import FastAPI\n\n# ⚠️ IMPORTANT: Apply backports BEFORE creating FastAPI app or routes\nfastapi_backports.backport()\n\n# Now create your app\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n```\n\n\u003e [!IMPORTANT]\n\u003e Always call `fastapi_backports.backport()` **before** creating your FastAPI application instance or\n\u003e defining any routes. The backports modify FastAPI's internal behavior and must be applied before FastAPI processes \n\u003e your route definitions.\n\n### Free Backport Control\n\nBoth `import fastapi_backports.apply` and `fastapi_backports.backport()` will directly apply all Backports in\nfastapi_backports. If you want to apply a specific Backport, do as follows:\n\n```python\nimport fastapi_backports\nfrom fastapi import FastAPI\n\n# ⚠️ IMPORTANT: Apply backports BEFORE creating FastAPI app or routes\nfastapi_backports.backport(\n    backports=[\n        fastapi_backports.MultipleQueryModelsBackporter,\n        fastapi_backports.TypeAliasTypeBackporter,\n    ]\n)\n\n# Now create your app\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furiyyo%2Ffastapi-backports","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furiyyo%2Ffastapi-backports","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furiyyo%2Ffastapi-backports/lists"}