:::warning 警告
这是一个颇为高级的话题
如果刚刚接触fastapi,你可能不需要了解它 :::
您可以声明额外的响应,包括额外的状态代码、媒体类型和描述等。
这些额外的响应将被包含在OpenAPI模式中,因此它们也将出现在API文档中。
但是对于那些额外的响应,你必须确保你直接返回一个类似JSONResponse的响应,并附上你的状态码和内容。

附带model的额外响应

你可以通过路径操作装饰器传递一个参数responses
他接收一个dict,key是每个响应的状态码,比如200,value是另一个dict,包含每个响应的信息。
每一个响应dict都可以有一个key model,包含一个Pydantic模型,就像response_model
FastAPI将采用该模型,生成JSON Schema,并将其包含在OpenAPI的正确位置。

例如,要使用状态代码404和Pydantic模型Message声明一个响应,可以编写:

  1. from fastapi import FastAPI
  2. from fastapi.responses import JSONResponse
  3. from pydantic import BaseModel
  4. class Item(BaseModel):
  5. id: str
  6. value: str
  7. class Message(BaseModel):
  8. message: str
  9. app = FastAPI()
  10. @app.get("/items/{item_id}", response_model=Item, responses={404: {"model": Message}})
  11. async def read_item(item_id: str):
  12. if item_id == "foo":
  13. return {"id": "foo", "value": "there goes my hero"}
  14. else:
  15. return JSONResponse(status_code=404, content={"message": "Item not found"})

:::info 注释
请记住,您必须直接返回JSONResponse :::

:::info Info
model key不是FastAPI的一部分
FastAPI将从那里获取Pydantic模型,生成JSON,并将其放置在正确的位置
正确的位置:

  • 在key content中,其值为另一个JSON对象(dict),该对象包含:
    • 具有媒体类型(例如application/json)的键,其中包含另一个json对象作为值,该对象包含:
      • 一个key chema,它的值是模型中的JSON
      • FastAPI在OpenAPI的另一个地方添加了对全局JSON模式的引用,而不是直接包含它。这样,其他应用程序和客户机就可以直接使用这些JSON模式,提供更好的代码生成工具等等。 :::
        OpenAPI中为此路径操作生成的响应将是:
        1. {
        2. "responses": {
        3. "404": {
        4. "description": "Additional Response",
        5. "content": {
        6. "application/json": {
        7. "schema": {
        8. "$ref": "#/components/schemas/Message"
        9. }
        10. }
        11. }
        12. },
        13. "200": {
        14. "description": "Successful Response",
        15. "content": {
        16. "application/json": {
        17. "schema": {
        18. "$ref": "#/components/schemas/Item"
        19. }
        20. }
        21. }
        22. },
        23. "422": {
        24. "description": "Validation Error",
        25. "content": {
        26. "application/json": {
        27. "schema": {
        28. "$ref": "#/components/schemas/HTTPValidationError"
        29. }
        30. }
        31. }
        32. }
        33. }
        34. }

        这些模式被引用到OpenAPI模式内部的另一个地方。
        1. {
        2. "components": {
        3. "schemas": {
        4. "Message": {
        5. "title": "Message",
        6. "required": [
        7. "message"
        8. ],
        9. "type": "object",
        10. "properties": {
        11. "message": {
        12. "title": "Message",
        13. "type": "string"
        14. }
        15. }
        16. },
        17. "Item": {
        18. "title": "Item",
        19. "required": [
        20. "id",
        21. "value"
        22. ],
        23. "type": "object",
        24. "properties": {
        25. "id": {
        26. "title": "Id",
        27. "type": "string"
        28. },
        29. "value": {
        30. "title": "Value",
        31. "type": "string"
        32. }
        33. }
        34. },
        35. "ValidationError": {
        36. "title": "ValidationError",
        37. "required": [
        38. "loc",
        39. "msg",
        40. "type"
        41. ],
        42. "type": "object",
        43. "properties": {
        44. "loc": {
        45. "title": "Location",
        46. "type": "array",
        47. "items": {
        48. "type": "string"
        49. }
        50. },
        51. "msg": {
        52. "title": "Message",
        53. "type": "string"
        54. },
        55. "type": {
        56. "title": "Error Type",
        57. "type": "string"
        58. }
        59. }
        60. },
        61. "HTTPValidationError": {
        62. "title": "HTTPValidationError",
        63. "type": "object",
        64. "properties": {
        65. "detail": {
        66. "title": "Detail",
        67. "type": "array",
        68. "items": {
        69. "$ref": "#/components/schemas/ValidationError"
        70. }
        71. }
        72. }
        73. }
        74. }
        75. }
        76. }

主响应额外的媒体类型

可以使用相同的response 参数为相同主response添加不同的媒体类型
例如,添加了一个额外的image/png媒体类型,声明路径操作能返回一个JSON对象(使用media类型 application/json)或一个PNG image:

  1. from typing import Optional
  2. from fastapi import FastAPI
  3. from fastapi.responses import FileResponse
  4. from pydantic import BaseModel
  5. class Item(BaseModel):
  6. id: str
  7. value: str
  8. app = FastAPI()
  9. @app.get(
  10. "/items/{item_id}",
  11. response_model=Item,
  12. responses={
  13. 200: {
  14. "content": {"image/png": {}},
  15. "description": "Return the JSON item or an image.",
  16. }
  17. },
  18. )
  19. async def read_item(item_id: str, img: Optional[bool] = None):
  20. if img:
  21. return FileResponse("image.png", media_type="image/png")
  22. else:
  23. return {"id": "foo", "value": "there goes my hero"}

:::info 注意
必须使用FileResponse 返回image :::

:::info info
除非在responses 参数中明确指定了一个不同的媒体类型,否则FastAPI将认为响应与主响应有一个相同的媒体类型(默认 application/json)
但是如果指定了一个自定义的None响应类作为媒体类型,FastAPI将使用application/json处理任何具有关联模型的额外响应 :::

组合信息

也可以组合多个地方的响应信息,包括response_model, status_code, 和 responses 参数
可以声明一个response_model,使用默认状态码200(或自定义一个),在OpenAPI模式中为相同的responses响应声明一个额外的信息

FastAPI将保留响应中的附加信息,并将其与模型中的JSON模式相结合。
例如,您可以声明一个状态代码为404的响应,该响应使用Pydantic模型并具有自定义描述。

一个200状态码的相应,该响应使用response_model,一个自定义的例子:

  1. from fastapi import FastAPI
  2. from fastapi.responses import JSONResponse
  3. from pydantic import BaseModel
  4. class Item(BaseModel):
  5. id: str
  6. value: str
  7. class Message(BaseModel):
  8. message: str
  9. app = FastAPI()
  10. @app.get(
  11. "/items/{item_id}",
  12. response_model=Item,
  13. responses={
  14. 404: {"model": Message, "description": "The item was not found"},
  15. 200: {
  16. "description": "Item requested by ID",
  17. "content": {
  18. "application/json": {
  19. "example": {"id": "bar", "value": "The bar tenders"}
  20. }
  21. },
  22. },
  23. },
  24. )
  25. async def read_item(item_id: str):
  26. if item_id == "foo":
  27. return {"id": "foo", "value": "there goes my hero"}
  28. else:
  29. return JSONResponse(status_code=404, content={"message": "Item not found"})


它将被组合并包含在OpenAPI,并且显示在API docs:
OpenAPI额外的响应 - 图1

组合预定义响应和自定义响应

您可能希望有一些应用于许多路径操作的预定义响应,但是您希望将它们与每个路径操作所需的自定义响应结合起来。

对于这些情况,可以使用Python字典“解包”**dict_to_unpack:

  1. old_dict = {
  2. "old key": "old value",
  3. "second old key": "second old value",
  4. }
  5. new_dict = {**old_dict, "new key": "new value"}

new_dict ,将包含old_dict 所有的键值对加上新的键值对:

  1. {
  2. "old key": "old value",
  3. "second old key": "second old value",
  4. "new key": "new value",
  5. }


您可以使用该技术在路径操作中重用一些预定义的响应,并将它们与其他自定义响应组合起来

例如:

  1. from typing import Optional
  2. from fastapi import FastAPI
  3. from fastapi.responses import FileResponse
  4. from pydantic import BaseModel
  5. class Item(BaseModel):
  6. id: str
  7. value: str
  8. responses = {
  9. 404: {"description": "Item not found"},
  10. 302: {"description": "The item was moved"},
  11. 403: {"description": "Not enough privileges"},
  12. }
  13. app = FastAPI()
  14. @app.get(
  15. "/items/{item_id}",
  16. response_model=Item,
  17. responses={**responses, 200: {"content": {"image/png": {}}}},
  18. )
  19. async def read_item(item_id: str, img: Optional[bool] = None):
  20. if img:
  21. return FileResponse("image.png", media_type="image/png")
  22. else:
  23. return {"id": "foo", "value": "there goes my hero"}

关于OpenAPI 响应的更多信息

要查看响应中可以包含哪些内容,可以查看OpenAPI规范中的以下部分:

  • OpenAPI Responses Object, 它包括 Response Object.
  • OpenAPI Response Object, 您可以在responses参数内的每个响应中直接包含任何内容。包括描述、头、内容(其中声明了不同的媒体类型和JSON模式)和链接