return sub_dependant
-def get_flat_dependant(dependant: Dependant) -> Dependant:
+CacheKey = Tuple[Optional[Callable], Tuple[str, ...]]
+
+
+def get_flat_dependant(
+ dependant: Dependant, *, skip_repeats: bool = False, visited: List[CacheKey] = None
+) -> Dependant:
+ if visited is None:
+ visited = []
+ visited.append(dependant.cache_key)
+
flat_dependant = Dependant(
path_params=dependant.path_params.copy(),
query_params=dependant.query_params.copy(),
path=dependant.path,
)
for sub_dependant in dependant.dependencies:
- flat_sub = get_flat_dependant(sub_dependant)
+ if skip_repeats and sub_dependant.cache_key in visited:
+ continue
+ flat_sub = get_flat_dependant(
+ sub_dependant, skip_repeats=skip_repeats, visited=visited
+ )
flat_dependant.path_params.extend(flat_sub.path_params)
flat_dependant.query_params.extend(flat_sub.query_params)
flat_dependant.header_params.extend(flat_sub.header_params)
def get_openapi_params(dependant: Dependant) -> List[Field]:
- flat_dependant = get_flat_dependant(dependant)
+ flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
return (
flat_dependant.path_params
+ flat_dependant.query_params
for method in route.methods:
operation = get_openapi_operation_metadata(route=route, method=method)
parameters: List[Dict] = []
- flat_dependant = get_flat_dependant(route.dependant)
+ flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
security_definitions, operation_security = get_openapi_security_definitions(
flat_dependant=flat_dependant
)
--- /dev/null
+from fastapi import Depends, FastAPI, Header
+from starlette.status import HTTP_200_OK
+from starlette.testclient import TestClient
+
+app = FastAPI()
+
+
+def get_header(*, someheader: str = Header(...)):
+ return someheader
+
+
+def get_something_else(*, someheader: str = Depends(get_header)):
+ return f"{someheader}123"
+
+
+@app.get("/")
+def get_deps(dep1: str = Depends(get_header), dep2: str = Depends(get_something_else)):
+ return {"dep1": dep1, "dep2": dep2}
+
+
+client = TestClient(app)
+
+schema = {
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "properties": {
+ "detail": {
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ "title": "Detail",
+ "type": "array",
+ }
+ },
+ "title": "HTTPValidationError",
+ "type": "object",
+ },
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": {"type": "string"},
+ "title": "Location",
+ "type": "array",
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error " "Type", "type": "string"},
+ },
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError",
+ "type": "object",
+ },
+ }
+ },
+ "info": {"title": "Fast API", "version": "0.1.0"},
+ "openapi": "3.0.2",
+ "paths": {
+ "/": {
+ "get": {
+ "operationId": "get_deps__get",
+ "parameters": [
+ {
+ "in": "header",
+ "name": "someheader",
+ "required": True,
+ "schema": {"title": "Someheader", "type": "string"},
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful " "Response",
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ "description": "Validation " "Error",
+ },
+ },
+ "summary": "Get Deps",
+ }
+ }
+ },
+}
+
+
+def test_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == HTTP_200_OK
+ actual_schema = response.json()
+ assert actual_schema == schema
+ assert (
+ len(actual_schema["paths"]["/"]["get"]["parameters"]) == 1
+ ) # primary goal of this test
+
+
+def test_response():
+ response = client.get("/", headers={"someheader": "hello"})
+ assert response.status_code == HTTP_200_OK
+ assert response.json() == {"dep1": "hello", "dep2": "hello123"}