fastapi-depgraph
Introspection of a FastAPI app's Depends() tree: which dependencies each
route resolves, which are shared across routes, which aren't cached, and
export to ASCII or Mermaid.
Reads route.dependant — the structure FastAPI already builds internally
when each route is registered — instead of reparsing signatures by hand.
Install
pip install fastapi-depgraph
Usage — CLI
depgraph show myapp.main:app
depgraph show myapp.main:app --shared --uncached
depgraph export myapp.main:app --format mermaid > graph.mmd
Usage — API
from fastapi_depgraph import inspect_app
report = inspect_app(app)
report.shared_dependencies() # {callable: ["/route1", "/route2"]}
report.uncached_dependencies() # ["module.get_request_id", ...]
for route in report.routes:
print(route.path, route.root.name)
Example
$ depgraph show examples/basic_app.py:app --shared --uncached
GET /users/me
basic_app.read_current_user (sync)
└── basic_app.get_current_user (sync)
├── basic_app.get_db (async)
│ └── basic_app.get_settings (sync)
└── basic_app.get_request_id (sync) [no-cache]
...
Dependencies shared across routes:
get_current_user: /orders, /orders/{order_id}, /users/me
get_db: /orders, /orders/{order_id}, /users, /users/me
get_settings: /orders, /orders/{order_id}, /users, /users/me
get_request_id: /orders, /orders/{order_id}, /users/me
get_orders_service: /orders, /orders/{order_id}
Dependencies with use_cache=False:
basic_app.get_request_id
At a glance: get_db and get_settings get resolved on four different
routes — if one gets expensive, that's where to look first. And
get_request_id is intentionally marked as uncached (it comes from a
per-request header), but in a real case that's the flag that warns you
about a use_cache=False someone forgot or added by mistake.
What patterns it handles
Tested, with regression coverage, against the real patterns that broke early versions of this package:
APIRouter+include_router(), at any level of nesting and with any prefix (/api→/v1→/itemscorrectly accumulates in the path).- Dependencies declared on
include_router(router, dependencies=[...])orFastAPI(dependencies=[...])— an auth guard for an entire router shows up in the tree of every route it covers. - Apps mounted with
app.mount(sub_app)(path caveat below). - Dependencies parametrized by a factory (
def make_limiter(n): def check(): ...; return check) orfunctools.partial(fn, role="admin"): two instances with different captured/bound values show up as distinct nodes (check{n=5}vs.check{n=10},require_role(role='admin')vs.require_role(role='editor')) instead of collapsing into one name. Depends(SomeClass())(instance) andDepends(SomeClass)(the class itself) — both "class as a dependency" patterns documented by FastAPI.
Known limitations
- Apps mounted with
app.mount(sub_app)are walked (Starlette exposes the sub-app's routes throughMount.routes), but the reportedpathis relative to the sub-app, without the mount's prefix. - Only HTTP routes are inspected; WebSocket routes aren't part of the tree
(intentionally —
Depends()on WebSocket doesn't have per-request caching or the same resolution model, see DESIGN.md §2). - If two different instances of the same class are used as dependencies on
different routes,
shared_dependencies()correctly treats them as not shared (it compares by identity), but they're shown with the same label in the tree/Mermaid unless the class itself is a closure — there's no generic way to give an arbitrary instance a readable name. app.dependency_overrides(the standard mechanism for injecting test doubles) isn't reflected: the tree shows the dependency as declared in the code, not the one that would actually run under an active override — it's a static graph, see DESIGN.md §2.- The name of a parametrized dependency includes the
repr()of its captured/bound values — if those values are secrets (tokens, API keys passed as defaults), they'll show up indepgraph show/exportoutput. Don't paste that output into public channels without checking what parametrized dependencies your app has. - Merging the path/dependencies for included routers (
include_router) uses, when available, an internal method with no public contract that Starlette exposes to resolve routes at request time; if that shape changes in a future version, the package silently degrades to the previous behavior (no accumulated prefix or inclusion dependencies) instead of failing — the CI matrix runs against several FastAPI versions to catch it early if that happens.
Why
FastAPI's DI system is implicit: nested Depends() resolve with no native
way to see the tree. Two questions this package answers that today have no
direct way to answer:
- Which expensive dependencies are being recomputed instead of cached
(
use_cache=False)? - Which routes share an expensive dependency, so you know where to optimize once instead of in five different places?
See DESIGN.md for the rest of the scope and design decisions.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_depgraph-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_depgraph-0.1.0.tar.gz
- Upload date:
- Size: 812.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f593e58b0fc33489d1461ff4ccf93b77ff7dbea6876acb04b45c44adbb9dc99
|
|
| MD5 |
cc7377700b6a409a9f8b644d59f2d68a
|
|
| BLAKE2b-256 |
292eaef328c1d0f0bb4be181664d5d78371c1137b59262db8b5d150a49037f76
|
Provenance
The following attestation bundles were made for fastapi_depgraph-0.1.0.tar.gz:
Publisher:
release.yml on jmiguelmangas/fastapi-depgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_depgraph-0.1.0.tar.gz -
Subject digest:
5f593e58b0fc33489d1461ff4ccf93b77ff7dbea6876acb04b45c44adbb9dc99 - Sigstore transparency entry: 2490023714
- Sigstore integration time:
-
Permalink:
jmiguelmangas/fastapi-depgraph@b5f6cd20c4523cbff7e1e0de648f67b8fd701865 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jmiguelmangas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5f6cd20c4523cbff7e1e0de648f67b8fd701865 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fastapi_depgraph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_depgraph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f83b2221e4affb0d174f9efc5a3cf276ba2f26fb82af6731f1f63c3a4ea1b54
|
|
| MD5 |
23352c04c4e23f4515fe9c1480e67255
|
|
| BLAKE2b-256 |
4d98a5d7950586de49ba07c41c29b1f3af83ec73425b8821bc1f49d9115fe8f8
|
Provenance
The following attestation bundles were made for fastapi_depgraph-0.1.0-py3-none-any.whl:
Publisher:
release.yml on jmiguelmangas/fastapi-depgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_depgraph-0.1.0-py3-none-any.whl -
Subject digest:
7f83b2221e4affb0d174f9efc5a3cf276ba2f26fb82af6731f1f63c3a4ea1b54 - Sigstore transparency entry: 2490023743
- Sigstore integration time:
-
Permalink:
jmiguelmangas/fastapi-depgraph@b5f6cd20c4523cbff7e1e0de648f67b8fd701865 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jmiguelmangas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5f6cd20c4523cbff7e1e0de648f67b8fd701865 -
Trigger Event:
push
-
Statement type: