Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Validaciones: Request Body

15/20
Recursos

Aportes 18

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Tambien podemos usar la built-in funcion dict() en lugar del metodo .dict() (el cual es propio de la clase BaseModel si no estoy mal). Esto se debe a que los programadores de Pydantic se ocuparon de que hacerle override al metodo __ dict __

@app.put('/person/{person_id}')
def update_person(
    person_id: int = Path(
        ...,
        ge=1,
        title='Person id',
        description='Id of the person you want to update'
    ),
    person: Person = Body(...),
    location: Location = Body(...)
):
    result = dict(person)
    result.update(dict(location))

    return result

Por si quieren que el endpoint retorne person y location, exactamente igual como se los mandamos, se puede hacer:

return {
    'person': person,
    'location': location
}

Otra forma de ejecutar la misma tarea es:

# Validations: Request Body
@app.put("/person/{person_id}")
def update_person(
    person_id: int = Path(
        ...,
        title="Person ID",
        description="This is the person ID",
        gt=0
    ),
    person: Person = Body(...),
    location: Location = Body(...)
):
    return person.dict() | location.dict()

Se debe tener cuidado con el metodo update ya que si ambos diccionarios tienen una misma key, perderemos la primera es decir

a = {'a': 1, 'b': 2}
b = {'a': 3, 'c': 4}
c = a.update(b)

>> {'a': 3, 'b': 2, 'c': 4'}

In this video we see how validate and mix two bodies and models

results = person.dict()
results.update(location.dict()
return results

Para los JSONs de PUT y POST, yo no usaria snake_case para los parametros, en lugar de eso, usaria camelCase.
Por qué: Aunque en la especificacion de JSON no especifica algun case, es mas usado en general el camelCase.
Google usa camelCase: https://google.github.io/styleguide/jsoncstyleguide.xml?showone=Property_Name_Format#Property_Name_Format

Algo curioso que intente, es que si intentas concatenar dos diccionarios usando el operador +, FastAPI lo tomará como correcto.

Es probable que por debajo del código este usando alguna excepción y corrija esté error.

@app.put("/person/{person_id}")
def update_person(
    person_id: int = Path(
        ...,
        title="Person ID",
        description="This is the person ID",
        gt=0
    ),
    person: Person = Body(...),
    location: Location = Body(...)
): 
    results = person.dict()
    results.update(location.dict())
    return results

Para reducir la unión de ambos modelos, se puede unir dos diccionarios de la siguiente forma

new_dict = {**dict1, **dict2}

Para este caso de uso, es necesario castear (usar el constructor de diccionario) en ambos modelos y aplicar la propiedad anterior expuesta:

results = {**dict(person),**dict(location)}

El Bodigo de esta Clase

# Python
from typing import Optional # Sirve para definir tipos de datos en python y volver a python como un lenguaje de programación estatico

#Pydantic
from pydantic import BaseModel # Sirve para definir los modelos de datos que se usaran en la aplicacion

# FastAPI
from fastapi import FastAPI  # Sirve para definir la API de la aplicacion
from fastapi import Body, Query, Path # Sirve para definir el tipo de dato que se usara en la API

app = FastAPI()

# Models
class Location(BaseModel):
    city: str
    country: str
    state: str
    lat: float
    lon: float

class Person(BaseModel): # Sirve para definir los modelos de datos que se usaran en la aplicacion
    first_name: str
    last_name: str
    age: int
    hair_color: Optional[str] = None
    is_married: Optional[bool] = None
    

@app.get("/")
def home(): # Sirve para definir la ruta de la API
    return {"message": "Hello World"}

# Requests and responses Body

@app.post("/person/new") 
def create_person(person: Person = Body(...)): # Sirve para definir el tipo de dato que se usara en la API
    return person

# Validaciones; Query Parametros

@app.get("/person/detail")
def show_person(
    person_id: int = Query(
        ...,
        gt = 0,
        lt = 100000000,
        title = "Id de la persona",
        description = "Id de la persona a consultar y es un parametro requerido"

        ), # Sirve para definir el tipo de dato que se usara en la API
    first_name: str = Query(
        ...,
        min_length = 1,
        max_length = 50,
        title = "Nombre de la Persona",
        description = " Este es el nombre de la persona como minimo 1 a 50 caracteres"

        ), # Sirve para definir el tipo de dato que se usara en la API
    last_name: str = Query(
        ...,
        min_length = 1,
        max_length = 50,
        title = "Apellido de la Persona",
        description = " Este es el apellido de la persona como minimo 1 a 50 caracteres"

        ), # Sirve para definir el tipo de dato que se usara en la API
        
    age: int = Query(
        ...,
        gt = 0,
        lt = 100,
        title = "Edad de la Persona",
        description = " Este es la edad de la persona y es un paramtero requerido"
        
        ), # Sirve para definir el tipo de dato que se usara en la API
        
    hair_color: Optional[str] = Query(
        None,
        min_length = 3,
        max_length = 50,
        title = "Color de pelo de la Persona",
        description = " Este es el color de pelo de la persona como minimo 3 a 50 caracteres"
        ),

    is_married: Optional[bool] = Query(
        None,
        title = "Estado civil de la Persona",
        description = " Este es el estado civil de la persona Treu Si esta Casada, Fals Si no esta Casada"
        )
):
    return {
        "person_id": person_id,
        "first_name": first_name,
        "last_name": last_name,
        "age": age,
        "hair_color": hair_color,
        "is_married": is_married
    }

# Valadaciones: Pach Parametros

@app.get("/person/detail/{person_id}/{first_name}/{last_name}")
def show_person(
    person_id: int = Path(
        ...,
        gt = 0,
        lt = 100000000,
        title = "Id de la persona",
        description = "Id de la persona a consultar y es un parametro requerido"
        ), # Sirve para definir el tipo de dato que se usara en la API
    
    first_name: str = Query(
        ...,
        min_length = 1,
        max_length = 50,
        title = "Nombre de la Persona",
        description = " Este es el nombre de la persona como minimo 1 a 50 caracteres"
        ), # Sirve para definir el tipo de dato que se usara en la API

    last_name: str = Query(
        ...,
        min_length = 1,
        max_length = 50,
        title = "Apellido de la Persona",
        description =" Este es el apellido de la persona como minimo 1 a 50 caracteres"
        ),

    age: int = Query(
        ...,
        gt = 0,
        lt = 100,
        title = "Edad de la Persona",
        description = " Este es la edad de la persona y es un paramtero requerido"
        ),

    hair_color: Optional[str] = Query(
        None,
        min_length = 3,
        max_length = 50,
        title = "Color de pelo de la Persona",
        description = " Este es el color de pelo de la persona como minimo 3 a 50 caracteres"
        ),

    is_married: Optional[bool] = Query(
        None,
        title = "Estado civil de la Persona",
        description = " Este es el estado civil de la persona"
        ),
):
    return {
        "person_id": person_id,
        "first_name": first_name,
        "last_name": last_name,
        "age": age,
        "hair_color": hair_color,
        "is_married": is_married
    }

#  Valadaciones: Body Parametros 

@app.put("/person/{person_id}")
def update_person(
    person_id: int = Path(
        ...,
        gt = 0,
        lt = 100000000,
        title = "Id de la persona",
        description = "Id de la persona a consultar y es un parametro requerido"
        ), # Sirve para definir el tipo de dato que se usara en la API

    person: Person = Body(...,
    title = "Persona a actualizar",
    description = "Persona a actualizar"
    ),

    location: Location = Body(
        ...,
        title = "Ubicacion de la persona",
        description = "Ubicacion de la persona"
        )
       
):
    result = person.dict()
    result.update(location.dict())
    return result

PUT

class Location(BaseModeL):
	city: str
	state: str
	country: str


@app.put("/person/{person_id}")
def update_person(
	person_id: = Path(
	...,
	title="Person ID"
	description="This is the person ID",
	gt=0
	),
	person: = Person = Body(...)
	Location: Location = Body (...)
):
	results = person.dict(),
	results.update(location.dict())
	return person

También se puede hacer así…
return {**person.dict(), **location.dict()}

Validaciones: Request Body

Creamos una nueva clase:

class Location(BaseModel):
    city: str
    state: str
    country: str

Creamos un nuevo endpoint:

# Validations: Request Body

@app.put("/person/{person_id}")
def update_person(
    person_id: int = Path(
        ...,
        title="Person ID",
        description="This is the person ID.",
        gt=0
    ),
    person: Person = Body(...),
    location: Location = Body(...),
):
    return {
        "person_id": person_id,
        "person:": person,
        "location": location,
    }

Al enviar los valores, obtenemos por ejemplo este JSON:

{
  "person:": {
    "first_name": "Miguel",
    "last_name": "Reyes",
    "age": 23,
    "hair_color": "brown",
    "is_married": false
  },
  "person_id": 1,
  "location": {
    "city": "Piedras Negras",
    "state": "Coahuila",
    "country": "México"
  }
}

Vamos con todo. Esta me costó un poco más de entender. La verdad es que fue un tema importante. Ahora si a seguir:

#Python
from typing import Optional
from fastapi.params import Path

#Pydantic
from pydantic import BaseModel

# FastAPI
from fastapi import FastAPI
from fastapi import Body, Query, Path

app = FastAPI()

# Models
class Location(BaseModel):
    city: str
    state: str
    country: str

class Person(BaseModel): # Person parameters
    first_name: str
    last_name: str
    age_person: int
    colos_eye: Optional[str] = None
    married: Optional[bool] = None

@app.get("/") #Path operation decorator
def home(): #Path operation function
    return {"First API": "Congratulation"} #JSON

# Request and Response Bondy

@app.post("/person/new") # Acces a new person
def create_person(person: Person = Body(...)): # acces to the parameters of person
    return person

# Validations: Query Parameters

@app.get("/person/detail")
def show_person(
    name: Optional[str] = Query(
        None, 
        min_length=3, 
        max_length=35,
        title="Person Name",
        description="This is the person name. It's between 3 and 35 characters."
        ),
    age: str = Query(
        ...,
        title="Person Age",
        description="This is the person age. It's required."
        )
):
    return {name: age}

# Validations: Path Parameters
@app.get("/person/detail/{person_id}")
def show_person(
    person_id: int = Path(
        ..., 
        gt=0,
        title="Person ID",
        description="This is the person ID. It's reqiuired and it's more than 0."
        )
):
    return {person_id: "it_exist!"}

# Validations: Request Body
@app.put("/person/{person_id}")
def update_person(
    person_id: int = Path(
        ...,
        title="Person ID",
        description="This is the person ID",
        gt=0
    ),
    person: Person = Body(...),
    location: Location = Body(...)
):
    results = person.dict()
    results.update(location.dict())
    return results 

Modelos == Sets

Por eso también es válida esta línea:

return person.dict() | location.dict()

otra forma de validar los datos que pasan del cliente al servidor

Estaría bien así también?

return  {'results':person.dict() | location.dict() }