Métodos PUT y PATCH

Intermedio
FastAPI
FastAPI
Actualizado: 01/07/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

PUT para actualización completa

El método PUT está diseñado para reemplazar completamente un recurso existente. Cuando envías una petición PUT, estás indicando que quieres sustituir todos los datos del recurso con la información que proporcionas en el cuerpo de la petición.

En FastAPI, implementar endpoints PUT es similar a POST, pero con una diferencia conceptual importante: PUT actualiza recursos existentes en lugar de crear nuevos. Esto significa que normalmente necesitarás un identificador para localizar el recurso que quieres actualizar.

Implementación básica de PUT

Vamos a crear un ejemplo práctico con una lista de usuarios en memoria:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI()

class Usuario(BaseModel):
    nombre: str
    email: str
    edad: int

# Base de datos simulada en memoria
usuarios_db = [
    {"id": 1, "nombre": "Ana García", "email": "ana@email.com", "edad": 28},
    {"id": 2, "nombre": "Carlos López", "email": "carlos@email.com", "edad": 35}
]

@app.put("/usuarios/{usuario_id}")
def actualizar_usuario_completo(usuario_id: int, usuario: Usuario):
    # Buscar el usuario por ID
    for i, user in enumerate(usuarios_db):
        if user["id"] == usuario_id:
            # Reemplazar completamente el usuario
            usuarios_db[i] = {
                "id": usuario_id,
                "nombre": usuario.nombre,
                "email": usuario.email,
                "edad": usuario.edad
            }
            return usuarios_db[i]
    
    # Si no existe, devolver error 404
    raise HTTPException(status_code=404, detail="Usuario no encontrado")

En este ejemplo, el endpoint PUT recibe el ID del usuario en la URL y los nuevos datos completos en el cuerpo de la petición. El usuario existente se reemplaza completamente con la nueva información.

Características del método PUT

El comportamiento de PUT tiene varias características importantes que debes entender:

Reemplazo completo: Cuando usas PUT, todos los campos del recurso se actualizan, incluso si no han cambiado. Si omites un campo en la petición PUT, ese campo debería eliminarse o establecerse a un valor por defecto.

# Si envías esta petición PUT:
{
    "nombre": "Ana Martínez",
    "email": "ana.martinez@email.com"
    # Falta el campo "edad"
}

# El comportamiento correcto sería establecer edad a None o un valor por defecto

Identificación del recurso: PUT siempre requiere identificar claramente qué recurso estás actualizando, normalmente a través de un ID en la URL.

Ejemplo con validación mejorada

Aquí tienes un ejemplo más robusto que maneja mejor los casos edge:

@app.put("/usuarios/{usuario_id}")
def actualizar_usuario_completo(usuario_id: int, usuario: Usuario):
    if usuario_id <= 0:
        raise HTTPException(status_code=400, detail="ID de usuario inválido")
    
    # Buscar el índice del usuario
    usuario_index = None
    for i, user in enumerate(usuarios_db):
        if user["id"] == usuario_id:
            usuario_index = i
            break
    
    if usuario_index is None:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    
    # Crear el usuario actualizado
    usuario_actualizado = {
        "id": usuario_id,
        "nombre": usuario.nombre,
        "email": usuario.email,
        "edad": usuario.edad
    }
    
    # Reemplazar en la base de datos
    usuarios_db[usuario_index] = usuario_actualizado
    
    return {
        "mensaje": "Usuario actualizado completamente",
        "usuario": usuario_actualizado
    }

Endpoint para obtener usuarios

Para probar nuestro endpoint PUT, necesitamos también un endpoint GET que nos permita ver los usuarios:

@app.get("/usuarios")
def obtener_usuarios():
    return usuarios_db

@app.get("/usuarios/{usuario_id}")
def obtener_usuario(usuario_id: int):
    for user in usuarios_db:
        if user["id"] == usuario_id:
            return user
    raise HTTPException(status_code=404, detail="Usuario no encontrado")

Probando el endpoint PUT

Puedes probar el endpoint PUT enviando una petición como esta:

PUT /usuarios/1
Content-Type: application/json

{
    "nombre": "Ana Martínez",
    "email": "ana.martinez@email.com",
    "edad": 29
}

La respuesta será:

{
    "mensaje": "Usuario actualizado completamente",
    "usuario": {
        "id": 1,
        "nombre": "Ana Martínez",
        "email": "ana.martinez@email.com",
        "edad": 29
    }
}

Cuándo usar PUT

El método PUT es ideal cuando necesitas:

  • Actualizar todos los campos de un recurso de una vez
  • Reemplazar completamente la información existente
  • Garantizar consistencia en los datos del recurso
  • Simplificar la lógica de actualización cuando siempre trabajas con objetos completos

Es importante recordar que PUT está pensado para actualizaciones completas. Si solo necesitas cambiar algunos campos específicos, el método PATCH será más apropiado, como veremos en la siguiente sección.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

PATCH para actualización parcial

El método PATCH está diseñado para realizar actualizaciones parciales de un recurso existente. A diferencia de PUT, que reemplaza completamente el recurso, PATCH te permite modificar únicamente los campos específicos que necesitas cambiar, manteniendo el resto de la información intacta.

Esta característica hace que PATCH sea especialmente útil cuando trabajas con recursos que tienen muchos campos y solo necesitas actualizar algunos de ellos. Es más eficiente y reduce el riesgo de sobrescribir accidentalmente datos que no querías modificar.

Implementación básica de PATCH

Para implementar PATCH en FastAPI, necesitamos crear un modelo que permita campos opcionales. Utilizaremos la misma base de datos de usuarios del ejemplo anterior:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional

app = FastAPI()

class UsuarioPatch(BaseModel):
    nombre: Optional[str] = None
    email: Optional[str] = None
    edad: Optional[int] = None

# Base de datos simulada (la misma del ejemplo anterior)
usuarios_db = [
    {"id": 1, "nombre": "Ana García", "email": "ana@email.com", "edad": 28},
    {"id": 2, "nombre": "Carlos López", "email": "carlos@email.com", "edad": 35}
]

@app.patch("/usuarios/{usuario_id}")
def actualizar_usuario_parcial(usuario_id: int, usuario_patch: UsuarioPatch):
    # Buscar el usuario por ID
    for i, user in enumerate(usuarios_db):
        if user["id"] == usuario_id:
            # Actualizar solo los campos proporcionados
            if usuario_patch.nombre is not None:
                usuarios_db[i]["nombre"] = usuario_patch.nombre
            if usuario_patch.email is not None:
                usuarios_db[i]["email"] = usuario_patch.email
            if usuario_patch.edad is not None:
                usuarios_db[i]["edad"] = usuario_patch.edad
            
            return usuarios_db[i]
    
    raise HTTPException(status_code=404, detail="Usuario no encontrado")

El modelo UsuarioPatch define todos los campos como opcionales usando Optional[tipo] = None. Esto permite que el cliente envíe solo los campos que quiere actualizar.

Mejorando la implementación con exclude_unset

Pydantic ofrece una funcionalidad muy útil llamada exclude_unset que nos permite trabajar de forma más elegante con actualizaciones parciales:

@app.patch("/usuarios/{usuario_id}")
def actualizar_usuario_parcial(usuario_id: int, usuario_patch: UsuarioPatch):
    # Buscar el usuario
    usuario_index = None
    for i, user in enumerate(usuarios_db):
        if user["id"] == usuario_id:
            usuario_index = i
            break
    
    if usuario_index is None:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    
    # Obtener solo los campos que fueron enviados
    datos_actualizacion = usuario_patch.model_dump(exclude_unset=True)
    
    # Actualizar solo los campos proporcionados
    for campo, valor in datos_actualizacion.items():
        usuarios_db[usuario_index][campo] = valor
    
    return {
        "mensaje": "Usuario actualizado parcialmente",
        "usuario": usuarios_db[usuario_index]
    }

El método model_dump(exclude_unset=True) devuelve un diccionario que contiene únicamente los campos que fueron explícitamente establecidos en la petición, ignorando aquellos que mantienen su valor por defecto.

Validación específica para PATCH

Cuando implementas PATCH, es importante validar que al menos un campo sea proporcionado para la actualización:

@app.patch("/usuarios/{usuario_id}")
def actualizar_usuario_parcial(usuario_id: int, usuario_patch: UsuarioPatch):
    if usuario_id <= 0:
        raise HTTPException(status_code=400, detail="ID de usuario inválido")
    
    # Verificar que se proporcione al menos un campo para actualizar
    datos_actualizacion = usuario_patch.model_dump(exclude_unset=True)
    if not datos_actualizacion:
        raise HTTPException(
            status_code=400, 
            detail="Debe proporcionar al menos un campo para actualizar"
        )
    
    # Buscar el usuario
    usuario_index = None
    for i, user in enumerate(usuarios_db):
        if user["id"] == usuario_id:
            usuario_index = i
            break
    
    if usuario_index is None:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    
    # Aplicar las actualizaciones
    for campo, valor in datos_actualizacion.items():
        usuarios_db[usuario_index][campo] = valor
    
    return {
        "mensaje": f"Campos actualizados: {', '.join(datos_actualizacion.keys())}",
        "usuario": usuarios_db[usuario_index]
    }

Ejemplos de uso de PATCH

Aquí tienes varios ejemplos de cómo usar el endpoint PATCH:

Actualizar solo el nombre:

PATCH /usuarios/1
Content-Type: application/json

{
    "nombre": "Ana Martínez"
}

Actualizar email y edad:

PATCH /usuarios/1
Content-Type: application/json

{
    "email": "ana.nueva@email.com",
    "edad": 30
}

Actualizar solo la edad:

PATCH /usuarios/2
Content-Type: application/json

{
    "edad": 36
}

Validaciones adicionales con PATCH

Puedes agregar validaciones específicas para ciertos campos durante las actualizaciones parciales:

from pydantic import validator

class UsuarioPatch(BaseModel):
    nombre: Optional[str] = None
    email: Optional[str] = None
    edad: Optional[int] = None
    
    @validator('edad')
    def validar_edad(cls, v):
        if v is not None and (v < 0 or v > 120):
            raise ValueError('La edad debe estar entre 0 y 120 años')
        return v
    
    @validator('email')
    def validar_email(cls, v):
        if v is not None and '@' not in v:
            raise ValueError('El email debe contener el símbolo @')
        return v

Cuándo usar PATCH

El método PATCH es la opción ideal cuando:

  • Solo necesitas modificar algunos campos específicos de un recurso
  • Quieres preservar la información existente que no estás actualizando
  • Trabajas con recursos grandes donde enviar todos los datos sería ineficiente
  • Implementas funcionalidades como "cambiar solo la contraseña" o "actualizar solo el estado"

La principal ventaja de PATCH sobre PUT es su flexibilidad y eficiencia. Los clientes pueden enviar exactamente los datos que necesitan cambiar, sin preocuparse por el resto de la información del recurso.

Aprendizajes de esta lección

  • Comprender la diferencia conceptual entre los métodos PUT y PATCH.
  • Implementar un endpoint PUT para actualización completa de recursos en FastAPI.
  • Implementar un endpoint PATCH para actualización parcial de recursos con campos opcionales.
  • Aplicar validaciones específicas para cada método y manejar errores comunes.
  • Saber cuándo utilizar PUT o PATCH según el caso de uso y eficiencia deseada.

Completa FastAPI y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración