Esquemas de OpenAPI Separados para Entrada y Salida o No¶
Desde que se lanzó Pydantic v2, el OpenAPI generado es un poco más exacto y correcto que antes. 😎
De hecho, en algunos casos, incluso tendrá dos JSON Schemas en OpenAPI para el mismo modelo de Pydantic, para entrada y salida, dependiendo de si tienen valores por defecto.
Veamos cómo funciona eso y cómo cambiarlo si necesitas hacerlo.
fromfastapiimportFastAPIfrompydanticimportBaseModelclassItem(BaseModel):name:strdescription:str|None=Noneapp=FastAPI()@app.post("/items/")defcreate_item(item:Item):returnitem@app.get("/items/")defread_items()->list[Item]:return[Item(name="Portal Gun",description="Device to travel through the multi-rick-verse",),Item(name="Plumbus"),]
fromfastapiimportFastAPIfrompydanticimportBaseModelclassItem(BaseModel):name:strdescription:str|None=Noneapp=FastAPI()@app.post("/items/")defcreate_item(item:Item):returnitem@app.get("/items/")defread_items()->list[Item]:return[Item(name="Portal Gun",description="Device to travel through the multi-rick-verse",),Item(name="Plumbus"),]
...entonces el campo descriptionno será requerido. Porque tiene un valor por defecto de None.
Pero si usas el mismo modelo como salida, como aquí:
fromfastapiimportFastAPIfrompydanticimportBaseModelclassItem(BaseModel):name:strdescription:str|None=Noneapp=FastAPI()@app.post("/items/")defcreate_item(item:Item):returnitem@app.get("/items/")defread_items()->list[Item]:return[Item(name="Portal Gun",description="Device to travel through the multi-rick-verse",),Item(name="Plumbus"),]
...entonces como description tiene un valor por defecto, si no devuelves nada para ese campo, aún tendrá ese valor por defecto.
Si interactúas con la documentación y revisas la respuesta, aunque el código no añadió nada en uno de los campos description, la respuesta JSON contiene el valor por defecto (null):
Esto significa que siempre tendrá un valor, solo que a veces el valor podría ser None (o null en JSON).
Eso significa que los clientes que usan tu API no tienen que verificar si el valor existe o no, pueden asumir que el campo siempre estará ahí, solo que en algunos casos tendrá el valor por defecto de None.
La forma de describir esto en OpenAPI es marcar ese campo como requerido, porque siempre estará ahí.
Por eso, el JSON Schema de un modelo puede ser diferente dependiendo de si se usa para entrada o salida:
para entradadescriptionno será requerido
para salida será requerido (y posiblemente None, o en términos de JSON, null)
Y si revisas todos los Esquemas disponibles (JSON Schemas) en OpenAPI, verás que hay dos, uno Item-Input y uno Item-Output.
Para Item-Input, description es no requerido, no tiene un asterisco rojo.
Pero para Item-Output, description es requerido, tiene un asterisco rojo.
Con esta característica de Pydantic v2, la documentación de tu API es más precisa, y si tienes clientes y SDKs autogenerados, también serán más precisos, con una mejor experiencia de desarrollador y consistencia. 🎉
Ahora, hay algunos casos en los que podrías querer tener el mismo esquema para entrada y salida.
Probablemente el principal caso de uso para esto es si ya tienes código/SDKs autogenerados y no quieres actualizar todo el código/SDKs autogenerados todavía, probablemente querrás hacerlo en algún momento, pero quizás no ahora.
En ese caso, puedes deshabilitar esta característica en FastAPI, con el parámetro separate_input_output_schemas=False.
Nota
El soporte para separate_input_output_schemas fue añadido en FastAPI 0.102.0. 🤓
fromfastapiimportFastAPIfrompydanticimportBaseModelclassItem(BaseModel):name:strdescription:str|None=Noneapp=FastAPI(separate_input_output_schemas=False)@app.post("/items/")defcreate_item(item:Item):returnitem@app.get("/items/")defread_items()->list[Item]:return[Item(name="Portal Gun",description="Device to travel through the multi-rick-verse",),Item(name="Plumbus"),]
Mismo Esquema para Modelos de Entrada y Salida en Docs¶
Y ahora habrá un único esquema para entrada y salida para el modelo, solo Item, y tendrá description como no requerido: