fastapi
Frameworkfastapi/fastapi
High-performance Python web framework for building APIs with type hints.
Overview
FastAPI is a modern, high-performance web framework for building APIs with Python based on standard type hints. It offers automatic interactive documentation via OpenAPI and JSON Schema, data validation through Pydantic, and async support via Starlette. Designed to be easy to learn, fast to code, and ready for production.
README Preview
\n \n\n\n FastAPI framework, high performance, easy to learn, fast to code, ready for production\n\n\n\n \n\n\n \n\n\n \n\n\n \n\n\n\n---\n\n**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)\n\n**Source Code**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.\n\nThe key features are:\n\n* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).\n* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *\n* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *\n* **Intuitive**: Great editor support. Completion everywhere. Less time debugging.\n* **Easy**: Designed to be easy to use and learn. Less time reading docs.\n* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.\n* **Robust**: Get production-ready code. With automatic interactive documentation.\n* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (previously known as Swagger) and [JSON Schema](https://json-schema.org/).\n\n* estimation based on tests conducted by an internal development team, building production applications.\n\n## Sponsors\n\n\n### Keystone Sponsor\n\n\n\n### Gold Sponsors\n\n\n\n\n\n\n\n\n\n### Silver Sponsors\n\n\n\n\n\n\n\n\n\n[Other sponsors](https://fastapi.tiangolo.com/fastapi-people/#sponsors)\n\n## Opinions\n\n\n\n\n\n"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"\n\nKabir Khan - Microsoft (ref)\n\n---\
FAQ (4)
TroubleshootingWhy does FastAPI 0.142.0 fail to start when OTEL_EXPORTER_OTLP_ENDPOINT is set, and how to fix it?
This is a bug in FastAPI 0.142.0: if the OTEL_EXPORTER_OTLP_ENDPOINT environment variable is set (common on hosting platforms) but the OpenTelemetry extra is not installed, the app crashes at startup with 'Automatic OpenTelemetry export requires fastapi[opentelemetry]'. **Fix: upgrade to FastAPI 0.142.2 or later**, which resolves this (PR #16418). Alternative workarounds if you must stay on 0.142.0: (1) install the extra with pip install fastapi[opentelemetry] or fastapi[standard], (2) disable auto-configuration by passing telemetry={'auto_configure': False} to FastAPI(), or (3) downgrade to FastAPI 0.141.0.
TroubleshootingHow to fix "Object of type 'APIRoute' has no attribute 'tags'" type checker error in FastAPI generate_unique_id_function?
This is a type-annotation regression in FastAPI 0.137.0 (introduced by PR #15745), where APIRoute lost its class-level tags annotation, so type checkers (ty, Pyright strict) report unresolved-attribute on route.tags inside a custom generate_unique_id_function — even though the code works at runtime. Fix: upgrade to FastAPI 0.137.1 or later, which restores the annotation (PR #15765):
pip install -U "fastapi>=0.137.1"
The documented pattern then type-checks correctly:
from fastapi import FastAPI
from fastapi.routing import APIRoute
def custom_generate_unique_id(route: APIRoute) -> str:
return f"{route.tags[0]}-{route.name}"
app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
If you must stay on 0.137.0 temporarily, silence the error with a # type: ignore[attr-defined] comment on the route.tags line, or access it via getattr(route, "tags", []).
TroubleshootingWhy do routes added directly to FastAPI APIRouter.routes return 404 (and removed routes still respond) after the router is included?
FastAPI (since the lazy router-inclusion rewrite, #15745) caches each included router's resolved routes, keyed by an internal version counter (APIRouter._routes_version). Directly mutating router.routes with append(), remove(), clear(), slice assignment, or reassignment never bumps that counter, so the parent router keeps serving the stale cached list: new routes 404, deleted routes keep responding as 'ghost' routes.
Workarounds:
1. Mutate routes only through the tracked official methods, which correctly invalidate the cache:
# instead of child.routes.append(APIRoute("/child2", handler, methods=["GET"]))
child.add_api_route("/child2", handler, methods=["GET"])
# or: child.add_route(...), child.include_router(...)2. If you must mutate
router.routes directly (e.g., app.router.routes = [...] to strip routes), manually invalidate the cache right after:child.routes.append(new_route)
child._mark_routes_changed() # private API; may change in future releases3. Perform all direct mutations before the router is included and before the app serves its first request, since the cache is only built on first dispatch.
A proper fix making .routes mutation-aware is being discussed in fastapi issue #16301.
TroubleshootingWhy does FastAPI iter_route_contexts() return an empty path for WebSocket routes?
This is a confirmed bug in FastAPI 0.137.2+ (still present in 0.141.1): iter_route_contexts() applies the include_router() prefix to HTTP routes but yields ctx.path == "" for APIWebSocketRoute, while ctx.route.path only holds the un-prefixed path. No fixed release exists yet. Workaround: special-case websocket routes and rebuild the full path yourself by prepending the prefix you passed to include_router().
from fastapi.routing import APIWebSocketRoute, iter_route_contexts
PREFIX = "/api/v1" # the prefix used in app.include_router(router, prefix=PREFIX)
for ctx in iter_route_contexts(app.routes):
if isinstance(ctx.route, APIWebSocketRoute) and not ctx.path:
full_path = PREFIX + ctx.route.path # e.g. /api/v1/stream/{job_id}
else:
full_path = ctx.path
If you don't know the prefix statically, it is stored on the private _IncludedRouter.include_context.prefix, but that API is internal and may change, so tracking your own include_router() prefixes is the safer option until the fix lands.