FastAPI Modelo de Respuesta

El modelo de respuesta se utiliza para declarar la estructura de datos devuelta por la API. Al declarar el modelo de respuesta, FastAPI realiza automáticamente la validación, serialización y filtrado de los datos de salida, asegurando que el cliente solo reciba los datos esperados.


Usar anotaciones de tipo de retorno

La forma más sencilla es anotar directamente el tipo de retorno de la función de operación de ruta:

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float


@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: int):
    # Los datos devueltos se filtran y validan automáticamente según el modelo Item
    return {
        "name": "Foo",
        "description": "A very nice Item",
        "price": 22.2,
        "secret": "this should not be visible",  # Los campos que no están en Item serán filtrados
    }

FastAPI utiliza el modelo de respuesta para realizar las siguientes tareas:

FunciónDescripción
Validación de datosSi los datos devueltos no coinciden con el modelo, significa que hay un problema en el código de la aplicación.
Filtrado de datosSolo devuelve los campos definidos en el modelo y filtra los campos sobrantes (esto es importante para la seguridad).
Generación de documentaciónMostrar la estructura de respuesta en la documentación de OpenAPI.
SerializaciónUtiliza Pydantic (implementado en Rust) para convertir datos a JSON de forma eficiente.

Parámetro response_model

Cuando el tipo de retorno no coincide con el modelo de respuesta, usa elresponse_modelparámetro del decorador:

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


# Modelo de entrada (incluye contraseña)
class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr


# Modelo de salida (no incluye contraseña)
class UserOut(BaseModel):
    username: str
    email: EmailStr


# La función recibe UserIn, pero la respuesta usa UserOut
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn):
    # El user devuelto incluye la contraseña, pero response_model=UserOut la filtrará
    return user

Esta es una medida importante para proteger datos sensibles. Usar diferentes modelos de entrada y salida garantiza que campos sensibles como contraseñas nunca aparezcan en la respuesta de la API.


Tipo de retorno y filtrado de datos

Se recomienda usar herencia de clases para separar los modelos de entrada/salida. De esta manera, tanto el editor como mypy pueden entender correctamente los tipos, y FastAPI puede filtrar los datos.

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


# Modelo de usuario base
class BaseUser(BaseModel):
    username: str
    email: EmailStr


# Modelo de entrada: hereda del modelo base y agrega el campo de contraseña
class UserIn(BaseUser):
    password: str


@app.post("/users/")
async def create_user(user: UserIn) -> BaseUser:
    # El tipo de retorno se anota como BaseUser; FastAPI filtrará el campo password
    # El editor y mypy también están satisfechos porque UserIn es una subclase de BaseUser
    return user

Excluir valores predeterminados no establecidos

Usandoresponse_model_exclude_unset=True, solo se devuelven los campos cuyo valor se ha establecido realmente:

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]

Comparación de respuestas para diferentes item_id:

item_idRespuestaDescripción
foo{"name": "Foo", "price": 50.2}Solo devuelve los campos establecidos explícitamente, omitiendo los valores predeterminados.
bar{"name": "Bar", "description": "...", "price": 62, "tax": 20.2}Todos los campos tienen valores reales, se devuelven todos.

Parámetros de filtrado relacionados:

ParámetroDescripción
response_model_exclude_unsetExcluir campos sin valor establecido
response_model_exclude_defaultsExcluir campos con valor predeterminado
response_model_exclude_noneExcluir campos con valor None

Incluir/Excluir campos específicos

Usaresponse_model_includeyresponse_model_excludepara controlar con precisión los campos de salida:

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5


# Solo incluir name y description
@app.get("/items/{item_id}", response_model=Item, response_model_include={"name", "description"})
async def read_item_name(item_id: str):
    return items[item_id]


# Excluir tax
@app.get("/items/{item_id}/no-tax", response_model=Item, response_model_exclude={"tax"})
async def read_item_no_tax(item_id: str):
    return items[item_id]

Aunqueresponse_model_includeyresponse_model_excludepueden filtrar campos rápidamente, se recomienda usar múltiples clases de modelos en su lugar, porque no pueden eliminar los campos excluidos de la documentación de OpenAPI.


Resumen

  • Usaresponse_modelel parámetro o las anotaciones de tipo de retorno para declarar el modelo de respuesta.
  • La función principal del modelo de respuesta es el filtrado de datos, protegiendo los datos sensibles de ser expuestos.
  • Usa diferentes modelos para entrada y salida, asegurando que campos como contraseñas no aparezcan en la respuesta.
  • response_model_exclude_unsetSolo devuelve los campos realmente establecidos.
  • Se recomienda usar herencia de modelos + anotaciones de tipo de retorno, en lugar deresponse_model_include/exclude
otras extensiones.