# OpenAPI 中的額外回應 { #additional-responses-in-openapi }

/// warning | 警告

這是一個偏進階的主題。

如果你剛開始使用 **FastAPI**，大多情況下不需要用到它。

///

你可以宣告額外的回應，包含額外的狀態碼、媒體型別、描述等。

這些額外回應會被包含在 OpenAPI 中，因此也會顯示在 API 文件裡。

但對於這些額外回應，你必須直接回傳像 `JSONResponse` 這樣的 `Response`，並包含你的狀態碼與內容。

## 使用 `model` 的額外回應 { #additional-response-with-model }

你可以在你的「路徑操作裝飾器」中傳入參數 `responses`。

它接收一個 `dict`：鍵是各回應的狀態碼（例如 `200`），值是另一個 `dict`，其中包含每個回應的資訊。

每個回應的 `dict` 都可以有一個鍵 `model`，包含一個 Pydantic 模型，與 `response_model` 類似。

**FastAPI** 會取用該模型、產生其 JSON Schema，並把它放到 OpenAPI 中正確的位置。

例如，要宣告一個狀態碼為 `404` 的額外回應，並使用 Pydantic 模型 `Message`，你可以這樣寫：

{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}

/// note | 注意

請記住你必須直接回傳 `JSONResponse`。

///

/// info | 說明

`model` 這個鍵不屬於 OpenAPI。

**FastAPI** 會從這裡取出 Pydantic 模型，產生 JSON Schema，並放到正確位置。

正確的位置是：

* 在 `content` 這個鍵中，其值是一個 JSON 物件（`dict`），包含：
    * 一個媒體型別作為鍵，例如 `application/json`，其值是另一個 JSON 物件，當中包含：
        * 鍵 `schema`，其值是該模型的 JSON Schema，這裡就是正確的位置。
            * **FastAPI** 會在這裡加入一個指向你 OpenAPI 中全域 JSON Schemas 的參照，而不是直接把它嵌入。如此一來，其他應用與用戶端可以直接使用那些 JSON Schemas，提供更好的程式碼產生工具等。

///

這個路徑操作在 OpenAPI 中產生的回應將會是：

```JSON hl_lines="3-12"
{
    "responses": {
        "404": {
            "description": "Additional Response",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/Message"
                    }
                }
            }
        },
        "200": {
            "description": "Successful Response",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/Item"
                    }
                }
            }
        },
        "422": {
            "description": "Validation Error",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/HTTPValidationError"
                    }
                }
            }
        }
    }
}
```

這些 Schemas 會在 OpenAPI 中以參照的方式指向其他位置：

```JSON hl_lines="4-16"
{
    "components": {
        "schemas": {
            "Message": {
                "title": "Message",
                "required": [
                    "message"
                ],
                "type": "object",
                "properties": {
                    "message": {
                        "title": "Message",
                        "type": "string"
                    }
                }
            },
            "Item": {
                "title": "Item",
                "required": [
                    "id",
                    "value"
                ],
                "type": "object",
                "properties": {
                    "id": {
                        "title": "Id",
                        "type": "string"
                    },
                    "value": {
                        "title": "Value",
                        "type": "string"
                    }
                }
            },
            "ValidationError": {
                "title": "ValidationError",
                "required": [
                    "loc",
                    "msg",
                    "type"
                ],
                "type": "object",
                "properties": {
                    "loc": {
                        "title": "Location",
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "msg": {
                        "title": "Message",
                        "type": "string"
                    },
                    "type": {
                        "title": "Error Type",
                        "type": "string"
                    }
                }
            },
            "HTTPValidationError": {
                "title": "HTTPValidationError",
                "type": "object",
                "properties": {
                    "detail": {
                        "title": "Detail",
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ValidationError"
                        }
                    }
                }
            }
        }
    }
}
```

## 主回應的其他媒體型別 { #additional-media-types-for-the-main-response }

你可以用同一個 `responses` 參數，替相同的主回應新增不同的媒體型別。

例如，你可以新增 `image/png` 這種媒體型別，宣告你的「路徑操作」可以回傳 JSON 物件（媒體型別為 `application/json`）或一張 PNG 圖片：

{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}

/// note | 注意

請注意你必須直接用 `FileResponse` 回傳圖片。

///

/// info | 說明

除非你在 `responses` 參數中明確指定不同的媒體型別，否則 FastAPI 會假設回應的媒體型別與主回應類別相同（預設為 `application/json`）。

但如果你指定了一個自訂的回應類別，且其媒體型別為 `None`，那麼對於任何具關聯模型的額外回應，FastAPI 會使用 `application/json`。

///

## 結合資訊 { #combining-information }

你也可以從多個地方結合回應資訊，包括 `response_model`、`status_code` 與 `responses` 參數。

你可以宣告一個 `response_model`，使用預設狀態碼 `200`（或你需要的自訂狀態碼），然後在 `responses` 中直接於 OpenAPI Schema 為相同的回應宣告額外資訊。

**FastAPI** 會保留 `responses` 提供的額外資訊，並把它和你模型的 JSON Schema 結合。

例如，你可以宣告一個狀態碼為 `404` 的回應，使用一個 Pydantic 模型，並帶有自訂的 `description`。

以及一個狀態碼為 `200` 的回應，使用你的 `response_model`，但包含自訂的 `example`：

{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}

以上都會被結合並包含在你的 OpenAPI 中，並顯示在 API 文件：

<img src="/img/tutorial/additional-responses/image01.png">

## 結合預先定義與自訂的回應 { #combine-predefined-responses-and-custom-ones }

你可能想要有一些適用於多個「路徑操作」的預先定義回應，但也想與每個「路徑操作」所需的自訂回應結合。

在這些情況下，你可以使用 Python 的「解包」`dict` 技巧，透過 `**dict_to_unpack`：

```Python
old_dict = {
    "old key": "old value",
    "second old key": "second old value",
}
new_dict = {**old_dict, "new key": "new value"}
```

此處，`new_dict` 會包含 `old_dict` 的所有鍵值配對，再加上新的鍵值配對：

```Python
{
    "old key": "old value",
    "second old key": "second old value",
    "new key": "new value",
}
```

你可以用這個技巧在「路徑操作」中重用一些預先定義的回應，並與其他自訂回應結合。

例如：

{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}

## 關於 OpenAPI 回應的更多資訊 { #more-information-about-openapi-responses }

若要查看回應中究竟可以包含哪些內容，你可以參考 OpenAPI 規範中的這些章節：

* [OpenAPI Responses 物件](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object)，其中包含 `Response Object`。
* [OpenAPI Response 物件](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object)，你可以把這裡的任何內容直接放到 `responses` 參數內各個回應中。包含 `description`、`headers`、`content`（在其中宣告不同的媒體型別與 JSON Schemas）、以及 `links`。
