Beispiel
fastapi 0.141.1: Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path precedence
Verifiziertes Beispiel für pypi fastapi 0.141.1: Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path…
sha256:f0072757a2777940751ef402b9be2ab1a50015019493ad42d2c8972723843885
Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen.
Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen.
MIT-0
Ausführungsbelege
Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.
- Beleggrundlage
- Signierter Vertrag bestanden
- Verifizierungsbelege
- 1
- Signaturschlüssel, die es gebaut haben
- 1
Deklarierte Umgebung
python linux 24 · ubuntu · glibc 2.39 x64 python python pip
Umgebungen der Verifizierungsläufe
| Umgebung | Contract | Stufen | Lauf |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1python:3.12-alpine@sha256:d09d15e60962… |
2026-08-27 |
Fall
HOW- Ziel
- Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path precedence
- Symbole
-
- fastapi.APIRouter
- fastapi.FastAPI
- fastapi.Depends
- fastapi.HTTPException
- fastapi.testclient.TestClient
- Umgebung
- python
- Erstellt
- 2026-08-27T21:40:39Z
Contract
- assert APIRouter prefix concatenates with include_router prefix so child router routes are exposed under parent and app prefixes
- assert router-level dependencies execute before endpoint-level dependencies and block unauthorized requests with HTTPException
- assert nested routers inherit parent router dependencies and execute them in top-down hierarchical order
- assert static route registered before parameterized route matches exact path instead of capturing parameter
- assert route response_model on APIRouter filters dictionary output to declared Pydantic schema fields
- assert APIRouter status_code parameter sets HTTP status code on response
- assert app.dependency_overrides intercepts dependencies declared at the APIRouter level
- assert direct endpoint function call bypasses APIRouter dependency resolution and routing decorators
Dateien
- NOTES.md
- PROMPT.md
- csx.json
- requirements.txt
- spec.json
- src/__init__.py
- src/app.py
- test/contract.py
Quelltext
# FastAPI APIRouter Modular Routing, Dependency Cascading, and Path Precedence
## Search Results
`search_known_solution` returned `NO_SAFE_MATCH` for `fastapi.APIRouter` modular routing with nested router hierarchies, router-level dependency cascading, and path evaluation precedence. Existing samples for `pkg:pypi/fastapi@0.141.1` covered general TestClient error payloads, query parameter binding, header validation, and generator dependency lifecycles, but lacked modular APIRouter composition contracts.
## What a Model Would Have Written
A model writing FastAPI APIRouter applications often assumes:
1. Static routes defined after dynamic path parameter routes (e.g. `/users/{user_id}` placed before `/users/me`) will still resolve `/users/me` specifically to the `/me` handler.
2. Router-level dependencies (`APIRouter(dependencies=[...])`) only apply to direct routes, not cascaded down to child routers attached via `parent_router.include_router(child_router)`.
3. Dependency overrides via `app.dependency_overrides` only intercept endpoint-level `Depends(...)` declarations and miss router-level `dependencies` lists.
## How the Wrong Version Fails
- Placing dynamic path parameter routes before static routes causes FastAPI to eagerly match `/users/me` against `/users/{user_id}` with `user_id="me"`, either returning unexpected data or failing type validation (e.g. 422 Unprocessable Entity if `user_id: int`).
- In nested routers, assuming parent dependencies are not inherited leads to missing authentication/authorization checks on sub-router endpoints if they aren't explicitly duplicated.
- Direct endpoint function invocation outside the ASGI pipeline bypasses APIRouter dependency verification and response schema filtering entirely.
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path precedence
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:pypi/fastapi@0.141.1
Demonstrate these symbols/APIs:
- fastapi.APIRouter
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:3775d81e18907b504305ec9c9b9ba9538e28585019469743385bbe397a307c74","contract":["assert APIRouter prefix concatenates with include_router prefix so child router routes are exposed under parent and app prefixes","assert router-level dependencies execute before endpoint-level dependencies and block unauthorized requests with HTTPException","assert nested routers inherit parent router dependencies and execute them in top-down hierarchical order","assert static route registered before parameterized route matches exact path instead of capturing parameter","assert route response_model on APIRouter filters dictionary output to declared Pydantic schema fields","assert APIRouter status_code parameter sets HTTP status code on response","assert app.dependency_overrides intercepts dependencies declared at the APIRouter level","assert direct endpoint function call bypasses APIRouter dependency resolution and routing decorators"],"goal":"Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path precedence","kind":"HOW","packages":["pkg:pypi/fastapi@0.141.1","pkg:pypi/starlette@1.6.0","pkg:pypi/pydantic@2.13.4","pkg:pypi/httpx@0.28.1"],"schemaVersion":1,"symbols":["fastapi.APIRouter","fastapi.FastAPI","fastapi.Depends","fastapi.HTTPException","fastapi.testclient.TestClient"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"pypi","executionContext":"python","language":"python","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/fastapi@0.141.1","pkg:pypi/starlette@1.6.0","pkg:pypi/pydantic@2.13.4","pkg:pypi/httpx@0.28.1"],"schemaVersion":1,"subject":"pkg:pypi/fastapi@0.141.1","symbols":["fastapi.APIRouter","fastapi.FastAPI","fastapi.Depends","fastapi.HTTPException","fastapi.testclient.TestClient"],"verifierAdapter":"python@1"}
fastapi==0.141.1
starlette==1.6.0
annotated-doc==0.0.5
pydantic==2.13.4
pydantic-core==2.46.4
typing-extensions==4.16.0
typing-inspection==0.4.4
annotated-types==0.8.0
anyio==4.14.2
idna==3.18
httpx2==2.10.0
httpcore2==2.10.0
truststore==0.10.4
httpx==0.28.1
httpcore==1.0.9
h11==0.16.0
certifi==2026.7.22
{
"schemaVersion": 1,
"goal": "Modular routing with FastAPI APIRouter prefix nesting route dependencies response models and path precedence",
"kind": "HOW",
"packages": [
"pkg:pypi/fastapi@0.141.1"
],
"symbols": [
"fastapi.APIRouter"
]
}
"""Package root for src."""
"""FastAPI application demonstrating APIRouter modular routing, dependency cascading, and path precedence."""
from typing import Any
from fastapi import APIRouter, Depends, FastAPI, HTTPException, Header, status
from pydantic import BaseModel
app = FastAPI()
AUDIT_TRAIL: list[str] = []
# --- Router & Endpoint Dependencies ---
def verify_api_key(x_api_key: str = Header(default="")) -> str:
AUDIT_TRAIL.append(f"auth:api_key:{x_api_key}")
if x_api_key != "secret-token":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing API key",
)
return x_api_key
def verify_admin_role(x_role: str = Header(default="user")) -> str:
AUDIT_TRAIL.append(f"auth:role:{x_role}")
if x_role != "admin":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin role required",
)
return x_role
# --- Pydantic Models for Response Filtering ---
class ItemCreate(BaseModel):
name: str
price: float
secret_code: str
class ItemResponse(BaseModel):
id: int
name: str
price: float
# --- Root / Base Routers ---
# 1. Parent API Router with router-level dependency
api_v1_router = APIRouter(
prefix="/api/v1",
dependencies=[Depends(verify_api_key)],
tags=["v1"],
)
# 2. Child Router for Items, nested inside api_v1_router
items_router = APIRouter(prefix="/items", tags=["items"])
# Path Precedence: Static route "/me" registered BEFORE parameterized route "/{item_id}"
@items_router.get("/me")
def get_current_user_items() -> dict[str, str]:
AUDIT_TRAIL.append("endpoint:get_current_user_items")
return {"owner": "current_user", "status": "active"}
@items_router.get("/{item_id}")
def get_item_by_id(item_id: int) -> dict[str, Any]:
AUDIT_TRAIL.append(f"endpoint:get_item_by_id:{item_id}")
return {"id": item_id, "name": f"Item-{item_id}"}
@items_router.post(
"",
response_model=ItemResponse,
status_code=status.HTTP_201_CREATED,
)
def create_item(item: ItemCreate) -> dict[str, Any]:
AUDIT_TRAIL.append(f"endpoint:create_item:{item.name}")
return {
"id": 101,
"name": item.name,
"price": item.price,
"secret_code": item.secret_code,
}
# 3. Admin Child Router with additional router-level dependency
admin_router = APIRouter(
prefix="/admin",
dependencies=[Depends(verify_admin_role)],
tags=["admin"],
)
@admin_router.get("/dashboard")
def get_admin_dashboard() -> dict[str, str]:
AUDIT_TRAIL.append("endpoint:get_admin_dashboard")
return {"status": "ok", "panel": "admin_main"}
# Mount child routers onto parent router
api_v1_router.include_router(items_router)
api_v1_router.include_router(admin_router)
# Include parent router into the main FastAPI application
app.include_router(api_v1_router)
# 4. Standalone Public Router without auth
public_router = APIRouter(prefix="/public")
@public_router.get("/health")
def health_check() -> dict[str, str]:
return {"status": "healthy"}
app.include_router(public_router)
import sys
from pathlib import Path
# Insert project root for module imports
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import fastapi
from fastapi import __version__ as fastapi_version
from fastapi.testclient import TestClient
from src.app import (
AUDIT_TRAIL,
app,
get_item_by_id,
verify_api_key,
)
client = TestClient(app)
# 1. Router prefix concatenation and sub-router routing
# Routes should be available under /api/v1/items/...
AUDIT_TRAIL.clear()
res_health = client.get("/public/health")
assert res_health.status_code == 200
assert res_health.json() == {"status": "healthy"}
# 2. Router-level dependencies block unauthorized requests
# /api/v1/... requires X-API-Key header defined at api_v1_router level
res_unauth = client.get("/api/v1/items/42")
assert res_unauth.status_code == 401
assert res_unauth.json()["detail"] == "Invalid or missing API key"
# Authorized request executes router-level dependency before route handler
AUDIT_TRAIL.clear()
res_auth = client.get("/api/v1/items/42", headers={"x-api-key": "secret-token"})
assert res_auth.status_code == 200
assert res_auth.json() == {"id": 42, "name": "Item-42"}
assert AUDIT_TRAIL == [
"auth:api_key:secret-token",
"endpoint:get_item_by_id:42",
], "Router dependency must execute before endpoint handler"
# 3. Nested router dependency cascading (parent dependency + child dependency)
# /api/v1/admin/dashboard inherits api_v1_router auth and adds admin_router auth
AUDIT_TRAIL.clear()
res_admin_no_role = client.get(
"/api/v1/admin/dashboard",
headers={"x-api-key": "secret-token", "x-role": "user"},
)
assert res_admin_no_role.status_code == 403
assert res_admin_no_role.json()["detail"] == "Admin role required"
assert AUDIT_TRAIL == [
"auth:api_key:secret-token",
"auth:role:user",
], "Parent router dependency executes first, followed by nested router dependency"
AUDIT_TRAIL.clear()
res_admin_ok = client.get(
"/api/v1/admin/dashboard",
headers={"x-api-key": "secret-token", "x-role": "admin"},
)
assert res_admin_ok.status_code == 200
assert res_admin_ok.json() == {"status": "ok", "panel": "admin_main"}
assert AUDIT_TRAIL == [
"auth:api_key:secret-token",
"auth:role:admin",
"endpoint:get_admin_dashboard",
]
# 4. Path precedence: static route before parameterized route
# /api/v1/items/me matches get_current_user_items, NOT get_item_by_id with item_id="me"
AUDIT_TRAIL.clear()
res_me = client.get("/api/v1/items/me", headers={"x-api-key": "secret-token"})
assert res_me.status_code == 200
assert res_me.json() == {"owner": "current_user", "status": "active"}
assert AUDIT_TRAIL == [
"auth:api_key:secret-token",
"endpoint:get_current_user_items",
]
# Parameterized route with invalid type triggers 422
res_invalid_id = client.get(
"/api/v1/items/invalid-number",
headers={"x-api-key": "secret-token"},
)
assert res_invalid_id.status_code == 422
# 5. Response model filtering and status_code on APIRouter endpoints
AUDIT_TRAIL.clear()
res_create = client.post(
"/api/v1/items",
headers={"x-api-key": "secret-token"},
json={"name": "Widget", "price": 19.99, "secret_code": "TOP_SECRET"},
)
assert res_create.status_code == 201
body = res_create.json()
assert body == {"id": 101, "name": "Widget", "price": 19.99}
assert "secret_code" not in body, "response_model must filter out undeclared secret fields"
# 6. Dependency overrides intercept router-level dependencies
app.dependency_overrides[verify_api_key] = lambda: "mocked-key"
AUDIT_TRAIL.clear()
res_overridden = client.get("/api/v1/items/99")
assert res_overridden.status_code == 200
assert res_overridden.json() == {"id": 99, "name": "Item-99"}
app.dependency_overrides.clear()
# 7. Direct function invocation bypasses APIRouter dependency and routing pipeline
direct_val = get_item_by_id(item_id=7)
assert direct_val == {"id": 7, "name": "Item-7"}
print(f"APIRouter contract verified successfully against fastapi {fastapi_version}")
Ursprungs-Seeder
anonym