Declarar datos de ejemplo del Request en FastAPI

Video thumbnail

Poder configurar algunos datos de prueba es ideal cuando nuestras entidades van creciendo de tamaño y ya con nuestro Hola Mundo en FastAPI; ya tenemos las bases para seguir el siguiente paso y generar data de prueba; con esto, ganamos unos pocos segundos cada vez que realizamos pruebas en la API mediante la documentación automática.

Desde parámetros como el body pero también lo puedes aplicar para los que puedes ver: 

  • Path()
  • Query()
  • Header()
  • Cookie()
  • Body()
  • Form()
  • File()

Datos de ejemplos en modelos

Para crear datos de prueba mediante un modelo tenemos la siguiente estructura:

models.py

class Task(MyBaseModel):
    ***
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                "id" : 123,
                "name": "Salvar al mundo",
                "description": "Hola Mundo Desc",
                "status": StatusType.PENDING,
                "tag":["tag 1", "tag 2"],
            ]
        }
    }

Con esto, veremos desde la documentación al momento de crear (o procesos similares) el formato definido anteriormente:

Datos de ejemplo en el esquema

Relaciones anidadas

Si existen relaciones en la entidad, como lo es en nuestro caso con la relación de tareas basta especificarlas como puedes ver en el siguiente ejemplo:

models.py

class Task(MyBaseModel):
    ***
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                "id" : 123,
                "name": "Salvar al mundo",
                "description": "Hola Mundo Desc",
                "status": StatusType.PENDING,
                "tag":["tag 1", "tag 2"],
                "category": {
                    "id":1234,
                    "name":"Cate 1"
                },
                "user": {
                    "id":12,
                    "name":"Andres",
                    "email":"admin@admin.com",
                    "surname":"Cruz",
                    "website":"http://desarrollolibre.net",
                }
                }
            ]
        }
    }

Y tendremos:

Datos de ejemplo en el body

Datos de ejemplos desde el argumento

También podemos definir datos de ejemplos en este video vamos a ver es utilizando el examples y en la siguiente empleando el open examples así que para eso es estructura muy similar a la que ya tenemos también es importante acotar de que si la definimos a nivel del modelo y luego la definimos a nivel del argumento estas sobre escriben las que se encuentren definidas a nivel del modelo:

@task_router.put("/",status_code=status.HTTP_200_OK)
def update(index: int, task: Task = Body(
    examples=[
                {
                   "id" : 123,
                    "name": "Salvar al mundo",
                    "description": "Hola Mundo Desc",
                    "status": 'PENDING',
                    "tag":["tag 1", "tag 2"],
                },
                {
                    "name": "Bar",
                },
                {
                    "name": "Baz",
                },
            ],
)):
    ***

O definir un solo valor en la clase:

class Task(MyBaseModel):
    name: str #= Field(examples=['MyUserAdmin'])
    description: Optional[str] = Field("No description",min_length=5, examples=['Descrip'])

Datos de ejemplos desde el argumento

En este apartado, veremos cómo agregar los datos de ejemplo directamente desde los argumentos de las funciones de la API.

Ejemplo simple

También podemos declarar datos de prueba para los Body(), Path() y Query(); por ejemplo:

@app.get("/ep_phone/{phone}") # +34 111 12-34-56
def phone(phone: str = Path(pattern=r"^(\(?\+[\d]{1,3}\)?)\s?([\d]{1,5})\s?([\d][\s\.-]?){6,7}$", example="+34 111 12-34-56")):
    return {"phone": phone}

O

@app.get("/e_phone/") # +34 111 12-34-56
def phone(phone: str = Query(pattern=r"^(\(?\+[\d]{1,3}\)?)\s?([\d]{1,5})\s?([\d][\s\.-]?){6,7}$", example="+34 111 12-34-56")):
    return {"phone": phone}

Listado de datos de ejemplos: OpenAPI

Video thumbnail

Si queremos ofrecer un listado de opciones de ejemplo en nuestra documentación, podemos emplear la funcionalidad de OpenAPI Examples. Para ello, debemos variar un poco la estructura tradicional y organizar la información dentro del parámetro examples de Body.

Cada ejemplo dentro del diccionario debe contener:

  • Key (Clave): Un identificador único (ej. "example1").
  • Summary: El texto que servirá como label (etiqueta) en el menú desplegable (Select).
  • Description (Opcional): Una explicación más detallada del caso de uso.
  • Value: El diccionario con los datos reales que se enviarán en la petición.
@task_router.put("/", status_code=status.HTTP_200_OK)
def update(index: int, task: Task = Body(
   openapi_examples={
       "Ejemplo 1": {
           "summary": "Primer ejemplo",
           "description": "Carga una tarea con todos los campos completos.",
           "value": {
               "id": 123,
               "name": "Salvar al mundo",
               "description": "Descripción de prueba",
               "status": "PENDING",
               "tag": ["tag 1", "tag 2"],
           },
       },
       "Ejemplo 2": {
           "summary": "Segundo ejemplo (Simplificado)",
           "value": {
               "name": "Sacar la basura",
               "tag": ["etiqueta 4"],
           },
       },
   }
)):

Otro ejemplo:

task.py

@task_router.put("/", status_code=status.HTTP_200_OK)
def update(index: int, task: Task = Body(
    # examples=[
    #     {
    #         "id": 1234,
    #         "name": "Salvar al mundo",
    #         "description": "Hola Mundo Desc 2",
    #         "tag":["tag 1", "tag 2"],
    #     }
    # ]
    openapi_examples={
        "example1": {
            "summary": '1 Example',
            "value": {
                "id": 123,
                "name": "Salvar al mundo",
                "description": "Hola Mundo",
                "tag": ["tag 1", "tag 4"],
            }
        },
        "example2": {
            "summary": '2 Example',
            "value": {
                "id": 1234,
                "name": "Salvar al mundo",
                "description": "Hola Mundo Desc 2",
                "tag": ["tag 1", "tag 2"],
            }
        }
    }
)):

En donde summary, corresponde al nombre del label del select:

Datos de ejemplo desde el listado

Verificación en la Interfaz (Swagger)

Al comentar el ejemplo que definimos anteriormente a nivel de modelo y utilizar openapi_examples dentro de Body, la documentación de FastAPI se actualiza automáticamente.

En lugar de mostrar un único JSON estático, ahora aparecerá un selector (Select). Al desplegarlo, verás los nombres que definimos en los campos summary. Dependiendo de la opción que elijas, el cuerpo de la petición (Value) cambiará dinámicamente, facilitando las pruebas para diferentes escenarios de datos.

El siguiente paso, aprende a ejecutar de Código al Iniciar o finalizar mediante el evento Lifespan en FastAPI

Aprende a generar datos de ejemplo en FastAPI para enriquecer tu documentación. Descubre cómo usar `json_schema_extra` en modelos y `openapi_examples` en `Body`, `Path` y `Query` para facilitar las pruebas de tu API.

Acepto recibir anuncios de interes sobre este Blog.

Andrés Cruz

EN In english