mirror of https://github.com/tiangolo/fastapi.git
Merge b8b89ca7ed into 272204c0c7
This commit is contained in:
commit
0a9eef94c0
|
|
@ -1,3 +1,4 @@
|
||||||
|
import copy
|
||||||
import http.client
|
import http.client
|
||||||
import inspect
|
import inspect
|
||||||
import warnings
|
import warnings
|
||||||
|
|
@ -378,7 +379,7 @@ def get_openapi_path(
|
||||||
additional_status_code,
|
additional_status_code,
|
||||||
additional_response,
|
additional_response,
|
||||||
) in route.responses.items():
|
) in route.responses.items():
|
||||||
process_response = additional_response.copy()
|
process_response = copy.deepcopy(additional_response)
|
||||||
process_response.pop("model", None)
|
process_response.pop("model", None)
|
||||||
status_code_key = str(additional_status_code).upper()
|
status_code_key = str(additional_status_code).upper()
|
||||||
if status_code_key == "DEFAULT":
|
if status_code_key == "DEFAULT":
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
"""
|
||||||
|
Regression test: Ensure app-level responses with Union models and content/examples
|
||||||
|
don't accumulate duplicate $ref entries in anyOf arrays.
|
||||||
|
See https://github.com/fastapi/fastapi/pull/14463
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class ModelA(BaseModel):
|
||||||
|
a: str
|
||||||
|
|
||||||
|
|
||||||
|
class ModelB(BaseModel):
|
||||||
|
b: str
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
responses={
|
||||||
|
500: {
|
||||||
|
"model": Union[ModelA, ModelB],
|
||||||
|
"content": {"application/json": {"examples": {"Case A": {"value": "a"}}}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/route1")
|
||||||
|
async def route1():
|
||||||
|
pass # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/route2")
|
||||||
|
async def route2():
|
||||||
|
pass # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_openapi_schema():
|
||||||
|
response = client.get("/openapi.json")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert response.json() == {
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||||
|
"paths": {
|
||||||
|
"/route1": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Route1",
|
||||||
|
"operationId": "route1_route1_get",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {"application/json": {"schema": {}}},
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"anyOf": [
|
||||||
|
{"$ref": "#/components/schemas/ModelA"},
|
||||||
|
{"$ref": "#/components/schemas/ModelB"},
|
||||||
|
],
|
||||||
|
"title": "Response 500 Route1 Route1 Get",
|
||||||
|
},
|
||||||
|
"examples": {"Case A": {"value": "a"}},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/route2": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Route2",
|
||||||
|
"operationId": "route2_route2_get",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {"application/json": {"schema": {}}},
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"anyOf": [
|
||||||
|
{"$ref": "#/components/schemas/ModelA"},
|
||||||
|
{"$ref": "#/components/schemas/ModelB"},
|
||||||
|
],
|
||||||
|
"title": "Response 500 Route2 Route2 Get",
|
||||||
|
},
|
||||||
|
"examples": {"Case A": {"value": "a"}},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"ModelA": {
|
||||||
|
"properties": {"a": {"type": "string", "title": "A"}},
|
||||||
|
"type": "object",
|
||||||
|
"required": ["a"],
|
||||||
|
"title": "ModelA",
|
||||||
|
},
|
||||||
|
"ModelB": {
|
||||||
|
"properties": {"b": {"type": "string", "title": "B"}},
|
||||||
|
"type": "object",
|
||||||
|
"required": ["b"],
|
||||||
|
"title": "ModelB",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue