mirror of https://github.com/tiangolo/fastapi.git
✨ Deep merge OpenAPI responses (#1577)
* override successful response * ✨ Add deep_dict_udpate * ✨ Merge additional responses with generated responses * 🍱 Update docs screenshot Co-authored-by: rkbeatss <rkaus053@uottawa.ca>
This commit is contained in:
parent
1f54a8e0a1
commit
181a32236a
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 71 KiB |
|
|
@ -14,6 +14,7 @@ from fastapi.openapi.constants import (
|
|||
from fastapi.openapi.models import OpenAPI
|
||||
from fastapi.params import Body, Param
|
||||
from fastapi.utils import (
|
||||
deep_dict_update,
|
||||
generate_operation_id_for_path,
|
||||
get_field_info,
|
||||
get_model_definitions,
|
||||
|
|
@ -201,33 +202,6 @@ def get_openapi_path(
|
|||
)
|
||||
callbacks[callback.name] = {callback.path: cb_path}
|
||||
operation["callbacks"] = callbacks
|
||||
if route.responses:
|
||||
for (additional_status_code, response) in route.responses.items():
|
||||
process_response = response.copy()
|
||||
assert isinstance(
|
||||
process_response, dict
|
||||
), "An additional response must be a dict"
|
||||
field = route.response_fields.get(additional_status_code)
|
||||
if field:
|
||||
response_schema, _, _ = field_schema(
|
||||
field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
||||
)
|
||||
process_response.setdefault("content", {}).setdefault(
|
||||
route_response_media_type or "application/json", {}
|
||||
)["schema"] = response_schema
|
||||
status_text: Optional[str] = status_code_ranges.get(
|
||||
str(additional_status_code).upper()
|
||||
) or http.client.responses.get(int(additional_status_code))
|
||||
process_response.setdefault(
|
||||
"description", status_text or "Additional Response"
|
||||
)
|
||||
status_code_key = str(additional_status_code).upper()
|
||||
if status_code_key == "DEFAULT":
|
||||
status_code_key = "default"
|
||||
process_response.pop("model", None)
|
||||
operation.setdefault("responses", {})[
|
||||
status_code_key
|
||||
] = process_response
|
||||
status_code = str(route.status_code)
|
||||
operation.setdefault("responses", {}).setdefault(status_code, {})[
|
||||
"description"
|
||||
|
|
@ -251,7 +225,47 @@ def get_openapi_path(
|
|||
).setdefault("content", {}).setdefault(route_response_media_type, {})[
|
||||
"schema"
|
||||
] = response_schema
|
||||
|
||||
if route.responses:
|
||||
operation_responses = operation.setdefault("responses", {})
|
||||
for (
|
||||
additional_status_code,
|
||||
additional_response,
|
||||
) in route.responses.items():
|
||||
process_response = additional_response.copy()
|
||||
process_response.pop("model", None)
|
||||
status_code_key = str(additional_status_code).upper()
|
||||
if status_code_key == "DEFAULT":
|
||||
status_code_key = "default"
|
||||
openapi_response = operation_responses.setdefault(
|
||||
status_code_key, {}
|
||||
)
|
||||
assert isinstance(
|
||||
process_response, dict
|
||||
), "An additional response must be a dict"
|
||||
field = route.response_fields.get(additional_status_code)
|
||||
additional_field_schema: Optional[Dict[str, Any]] = None
|
||||
if field:
|
||||
additional_field_schema, _, _ = field_schema(
|
||||
field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
||||
)
|
||||
media_type = route_response_media_type or "application/json"
|
||||
additional_schema = (
|
||||
process_response.setdefault("content", {})
|
||||
.setdefault(media_type, {})
|
||||
.setdefault("schema", {})
|
||||
)
|
||||
deep_dict_update(additional_schema, additional_field_schema)
|
||||
status_text: Optional[str] = status_code_ranges.get(
|
||||
str(additional_status_code).upper()
|
||||
) or http.client.responses.get(int(additional_status_code))
|
||||
description = (
|
||||
process_response.get("description")
|
||||
or openapi_response.get("description")
|
||||
or status_text
|
||||
or "Additional Response"
|
||||
)
|
||||
deep_dict_update(openapi_response, process_response)
|
||||
openapi_response["description"] = description
|
||||
http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
|
||||
if (all_route_params or route.body_field) and not any(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -172,3 +172,15 @@ def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str:
|
|||
operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id)
|
||||
operation_id = operation_id + "_" + method.lower()
|
||||
return operation_id
|
||||
|
||||
|
||||
def deep_dict_update(main_dict: dict, update_dict: dict) -> None:
|
||||
for key in update_dict:
|
||||
if (
|
||||
key in main_dict
|
||||
and isinstance(main_dict[key], dict)
|
||||
and isinstance(update_dict[key], dict)
|
||||
):
|
||||
deep_dict_update(main_dict[key], update_dict[key])
|
||||
else:
|
||||
main_dict[key] = update_dict[key]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ openapi_schema = {
|
|||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"description": "Return the JSON item or an image.",
|
||||
"content": {
|
||||
"image/png": {},
|
||||
"application/json": {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ openapi_schema = {
|
|||
},
|
||||
},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"description": "Item requested by ID",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/Item"},
|
||||
|
|
|
|||
Loading…
Reference in New Issue