Si estás empezando con FastAPI, podrías no necesitar esto.
Puedes declarar respuestas adicionales, con códigos de estado adicionales, tipos de medios, descripciones, etc.
Esas respuestas adicionales se incluirán en el esquema de OpenAPI, por lo que también aparecerán en la documentación de la API.
Pero para esas respuestas adicionales tienes que asegurarte de devolver una Response como JSONResponse directamente, con tu código de estado y contenido.
Puedes pasar a tus decoradores de path operation un parámetro responses.
Recibe un dict: las claves son códigos de estado para cada respuesta (como 200), y los valores son otros dicts con la información de cada uno.
Cada uno de esos dicts de respuesta puede tener una clave model, que contiene un modelo de Pydantic, al igual que response_model.
FastAPI tomará ese modelo, generará su JSON Schema y lo incluirá en el lugar correcto en OpenAPI.
Por ejemplo, para declarar otra respuesta con un código de estado 404 y un modelo de Pydantic Message, puedes escribir:
fromfastapiimportFastAPIfromfastapi.responsesimportJSONResponsefrompydanticimportBaseModelclassItem(BaseModel):id:strvalue:strclassMessage(BaseModel):message:strapp=FastAPI()@app.get("/items/{item_id}",response_model=Item,responses={404:{"model":Message}})asyncdefread_item(item_id:str):ifitem_id=="foo":return{"id":"foo","value":"there goes my hero"}returnJSONResponse(status_code=404,content={"message":"Item not found"})
Nota
Ten en cuenta que tienes que devolver el JSONResponse directamente.
Nota
La clave model no es parte de OpenAPI.
FastAPI tomará el modelo de Pydantic de ahí, generará el JSON Schema, y lo colocará en el lugar correcto.
El lugar correcto es:
In the key content, that has as value another JSON object (dict) that contains:
A key with the media type, e.g. application/json, that contains as value another JSON object, that contains:
A key schema, that has as the value the JSON Schema from the model, here's the correct place.
FastAPI añade una referencia aquí a los JSON Schemas globales en otro lugar de tu OpenAPI en lugar de incluirlo directamente. De esta manera, otras aplicaciones y clientes pueden usar esos JSON Schemas directamente, proporcionar mejores herramientas de generación de código, etc.
Las respuestas generadas en OpenAPI para esta path operation serán:
Tipos de medios adicionales para la respuesta principal¶
Puedes usar este mismo parámetro responses para añadir diferentes tipos de medios para la misma respuesta principal.
Por ejemplo, puedes añadir un tipo de medio adicional de image/png, declarando que tu path operation puede devolver un objeto JSON (con tipo de medio application/json) o una imagen PNG:
fromfastapiimportFastAPIfromfastapi.responsesimportFileResponsefrompydanticimportBaseModelclassItem(BaseModel):id:strvalue:strapp=FastAPI()@app.get("/items/{item_id}",response_model=Item,responses={200:{"content":{"image/png":{}},"description":"Return the JSON item or an image.",}},)asyncdefread_item(item_id:str,img:bool|None=None):ifimg:returnFileResponse("image.png",media_type="image/png")else:return{"id":"foo","value":"there goes my hero"}
Nota
Ten en cuenta que tienes que devolver la imagen usando un FileResponse directamente.
Nota
A menos que especifiques un tipo de medio diferente explícitamente en tu parámetro responses, FastAPI asumirá que la respuesta tiene el mismo tipo de medio que la clase de respuesta principal (por defecto application/json).
Pero si has especificado una clase de respuesta personalizada con None como tipo de medio, FastAPI usará application/json para cualquier respuesta adicional que tenga un modelo asociado.
También puedes combinar información de respuesta de múltiples lugares, incluyendo los parámetros response_model, status_code, y responses.
Puedes declarar un response_model, usando el código de estado por defecto 200 (o uno personalizado si lo necesitas), y luego declarar información adicional para esa misma respuesta en responses, directamente en el esquema de OpenAPI.
FastAPI mantendrá la información adicional de responses, y la combinará con el JSON Schema de tu modelo.
Por ejemplo, puedes declarar una respuesta con un código de estado 404 que usa un modelo de Pydantic y tiene una description personalizada.
Y una respuesta con un código de estado 200 que usa tu response_model, pero incluye un example personalizado:
fromfastapiimportFastAPIfromfastapi.responsesimportJSONResponsefrompydanticimportBaseModelclassItem(BaseModel):id:strvalue:strclassMessage(BaseModel):message:strapp=FastAPI()@app.get("/items/{item_id}",response_model=Item,responses={404:{"model":Message,"description":"The item was not found"},200:{"description":"Item requested by ID","content":{"application/json":{"example":{"id":"bar","value":"The bar tenders"}}},},},)asyncdefread_item(item_id:str):ifitem_id=="foo":return{"id":"foo","value":"there goes my hero"}else:returnJSONResponse(status_code=404,content={"message":"Item not found"})
Todo se combinará e incluirá en tu OpenAPI, y se mostrará en la documentación de la API:
Combinar respuestas predefinidas y personalizadas¶
Podrías querer tener algunas respuestas predefinidas que apliquen a muchas path operations, pero quieres combinarlas con respuestas personalizadas necesarias para cada path operation.
Para esos casos, puedes usar la técnica de Python de "desempaquetar" un dict con **dict_to_unpack:
old_dict={"old key":"old value","second old key":"second old value",}new_dict={**old_dict,"new key":"new value"}
Aquí, new_dict contendrá todos los pares clave-valor de old_dict más el nuevo par clave-valor:
{"old key":"old value","second old key":"second old value","new key":"new value",}
Puedes usar esa técnica para reutilizar algunas respuestas predefinidas en tus path operations y combinarlas con otras personalizadas adicionales.
Por ejemplo:
fromfastapiimportFastAPIfromfastapi.responsesimportFileResponsefrompydanticimportBaseModelclassItem(BaseModel):id:strvalue:strresponses={404:{"description":"Item not found"},302:{"description":"The item was moved"},403:{"description":"Not enough privileges"},}app=FastAPI()@app.get("/items/{item_id}",response_model=Item,responses={**responses,200:{"content":{"image/png":{}}}},)asyncdefread_item(item_id:str,img:bool|None=None):ifimg:returnFileResponse("image.png",media_type="image/png")else:return{"id":"foo","value":"there goes my hero"}
OpenAPI Response Object, puedes incluir cualquier cosa de esto directamente en cada respuesta dentro de tu parámetro responses. Incluyendo description, headers, content (dentro de esto es donde declaras diferentes tipos de medios y JSON Schemas), y links.