Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusDiferencias PUT vs PATCH
Los métodos PUT y PATCH representan dos enfoques distintos para actualizar recursos en una API REST, cada uno con características específicas que determinan cuándo y cómo utilizarlos en Express.
Naturaleza de la actualización
El método PUT está diseñado para realizar actualizaciones completas de un recurso. Cuando utilizas PUT, el servidor espera recibir una representación completa del recurso que reemplazará totalmente la versión existente. Si omites algún campo en la petición PUT, ese campo debería eliminarse o establecerse a su valor por defecto.
app.put('/usuarios/:id', (req, res) => {
const { id } = req.params;
const datosCompletos = req.body;
// PUT espera todos los campos del usuario
const usuarioActualizado = {
nombre: datosCompletos.nombre,
email: datosCompletos.email,
edad: datosCompletos.edad,
telefono: datosCompletos.telefono
};
// Reemplaza completamente el recurso
usuarios[id] = usuarioActualizado;
res.json(usuarioActualizado);
});
Por el contrario, PATCH permite actualizaciones parciales. Solo necesitas enviar los campos que deseas modificar, manteniendo intactos el resto de atributos del recurso.
app.patch('/usuarios/:id', (req, res) => {
const { id } = req.params;
const cambiosParciales = req.body;
// PATCH solo modifica los campos enviados
const usuarioExistente = usuarios[id];
const usuarioActualizado = {
...usuarioExistente,
...cambiosParciales
};
usuarios[id] = usuarioActualizado;
res.json(usuarioActualizado);
});
Idempotencia y comportamiento
Ambos métodos son idempotentes, lo que significa que realizar la misma operación múltiples veces produce el mismo resultado. Sin embargo, su implementación práctica difiere significativamente.
PUT mantiene la idempotencia de forma más estricta porque siempre reemplaza el recurso completo:
// Primera llamada PUT
PUT /productos/123
{
"nombre": "Laptop Gaming",
"precio": 1200,
"categoria": "Electrónicos"
}
// Segunda llamada PUT idéntica produce el mismo resultado
PUT /productos/123
{
"nombre": "Laptop Gaming",
"precio": 1200,
"categoria": "Electrónicos"
}
PATCH puede ser idempotente dependiendo de la implementación, especialmente cuando se utilizan operaciones de asignación directa:
app.patch('/productos/:id', (req, res) => {
const { id } = req.params;
const producto = productos[id];
// Operación idempotente: asignación directa
if (req.body.precio) {
producto.precio = req.body.precio;
}
// Operación no idempotente: incremento
if (req.body.incrementarStock) {
producto.stock += req.body.incrementarStock;
}
res.json(producto);
});
Validación y estructura de datos
La validación en PUT debe ser más estricta porque requiere una representación completa del recurso:
app.put('/articulos/:id', (req, res) => {
const camposRequeridos = ['titulo', 'contenido', 'autor', 'fechaPublicacion'];
// PUT requiere validación completa
const camposFaltantes = camposRequeridos.filter(campo => !req.body[campo]);
if (camposFaltantes.length > 0) {
return res.status(400).json({
error: `Campos requeridos faltantes: ${camposFaltantes.join(', ')}`
});
}
// Proceder con la actualización completa
articulos[req.params.id] = req.body;
res.json(req.body);
});
PATCH permite una validación más flexible, enfocándose únicamente en los campos proporcionados:
app.patch('/articulos/:id', (req, res) => {
const camposPermitidos = ['titulo', 'contenido', 'tags'];
const actualizacion = {};
// PATCH valida solo los campos enviados
for (const campo of camposPermitidos) {
if (req.body[campo] !== undefined) {
actualizacion[campo] = req.body[campo];
}
}
if (Object.keys(actualizacion).length === 0) {
return res.status(400).json({
error: 'No se proporcionaron campos válidos para actualizar'
});
}
Object.assign(articulos[req.params.id], actualizacion);
res.json(articulos[req.params.id]);
});
Casos de uso prácticos
PUT resulta ideal cuando necesitas reemplazar completamente un recurso o cuando trabajas con formularios que capturan todos los datos del recurso:
// Actualización completa de perfil de usuario
app.put('/perfiles/:userId', (req, res) => {
const perfilCompleto = {
nombre: req.body.nombre,
apellido: req.body.apellido,
email: req.body.email,
biografia: req.body.biografia || '',
configuracionPrivacidad: req.body.configuracionPrivacidad || {}
};
perfiles[req.params.userId] = perfilCompleto;
res.json(perfilCompleto);
});
PATCH es más apropiado para actualizaciones específicas, como cambiar el estado de un pedido o actualizar campos individuales:
// Actualización parcial del estado de pedido
app.patch('/pedidos/:id/estado', (req, res) => {
const pedido = pedidos[req.params.id];
if (req.body.estado) {
pedido.estado = req.body.estado;
pedido.fechaActualizacion = new Date();
}
res.json(pedido);
});
La elección entre PUT y PATCH depende fundamentalmente de si necesitas una actualización completa o parcial del recurso, así como de los requisitos específicos de tu aplicación en términos de validación y comportamiento esperado por los clientes de tu API.
Actualización de recursos
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
La actualización de recursos en Express requiere una implementación cuidadosa que considere tanto la integridad de los datos como la experiencia del usuario. Los métodos PUT y PATCH proporcionan diferentes estrategias para modificar recursos existentes, cada una con patrones específicos de implementación.
Manejo de recursos inexistentes
Antes de actualizar cualquier recurso, es fundamental verificar su existencia. Esta validación debe realizarse de forma consistente en ambos métodos:
const verificarRecursoExiste = (coleccion, id) => {
return coleccion[id] !== undefined;
};
app.put('/productos/:id', (req, res) => {
const { id } = req.params;
if (!verificarRecursoExiste(productos, id)) {
return res.status(404).json({
error: 'Producto no encontrado',
id: id
});
}
// Proceder con la actualización
productos[id] = req.body;
res.json(productos[id]);
});
Preservación de metadatos
Durante las actualizaciones, ciertos campos del sistema deben preservarse o actualizarse automáticamente. Estos metadatos proporcionan trazabilidad y control de versiones:
app.patch('/documentos/:id', (req, res) => {
const { id } = req.params;
const documento = documentos[id];
// Preservar metadatos del sistema
const documentoActualizado = {
...documento,
...req.body,
id: documento.id, // ID inmutable
fechaCreacion: documento.fechaCreacion, // Preservar fecha original
fechaModificacion: new Date(), // Actualizar timestamp
version: documento.version + 1 // Incrementar versión
};
documentos[id] = documentoActualizado;
res.json(documentoActualizado);
});
Validación de tipos y formatos
La validación de datos debe adaptarse al tipo de actualización. PUT requiere validación completa, mientras que PATCH valida solo los campos proporcionados:
const validarEmail = (email) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
};
app.patch('/usuarios/:id', (req, res) => {
const { id } = req.params;
const usuario = usuarios[id];
// Validar solo campos presentes en la actualización
if (req.body.email && !validarEmail(req.body.email)) {
return res.status(400).json({
error: 'Formato de email inválido'
});
}
if (req.body.edad && (req.body.edad < 0 || req.body.edad > 120)) {
return res.status(400).json({
error: 'Edad debe estar entre 0 y 120 años'
});
}
// Aplicar cambios validados
Object.assign(usuario, req.body);
res.json(usuario);
});
Manejo de relaciones entre recursos
Cuando un recurso tiene relaciones con otros recursos, las actualizaciones deben mantener la integridad referencial:
app.put('/proyectos/:id', (req, res) => {
const { id } = req.params;
const proyecto = proyectos[id];
// Validar que los usuarios asignados existen
if (req.body.equipoAsignado) {
const usuariosInvalidos = req.body.equipoAsignado.filter(
userId => !usuarios[userId]
);
if (usuariosInvalidos.length > 0) {
return res.status(400).json({
error: 'Usuarios no encontrados',
usuariosInvalidos
});
}
}
// Actualizar proyecto manteniendo integridad
proyectos[id] = {
...req.body,
id: proyecto.id,
fechaCreacion: proyecto.fechaCreacion,
fechaModificacion: new Date()
};
res.json(proyectos[id]);
});
Respuestas diferenciadas por tipo de actualización
Las respuestas HTTP deben reflejar el tipo de operación realizada y proporcionar información útil al cliente:
app.put('/configuraciones/:id', (req, res) => {
const { id } = req.params;
const configuracionAnterior = { ...configuraciones[id] };
// Reemplazo completo
configuraciones[id] = {
...req.body,
id,
fechaActualizacion: new Date()
};
res.json({
mensaje: 'Configuración reemplazada completamente',
anterior: configuracionAnterior,
actual: configuraciones[id],
cambiosRealizados: Object.keys(req.body).length
});
});
app.patch('/configuraciones/:id', (req, res) => {
const { id } = req.params;
const configuracion = configuraciones[id];
const camposModificados = Object.keys(req.body);
// Actualización parcial
Object.assign(configuracion, req.body);
configuracion.fechaActualizacion = new Date();
res.json({
mensaje: 'Configuración actualizada parcialmente',
recurso: configuracion,
camposModificados,
totalCampos: camposModificados.length
});
});
Optimización de actualizaciones masivas
Para actualizaciones que afectan múltiples campos o requieren procesamiento adicional, es importante optimizar las operaciones:
app.patch('/inventario/:id', (req, res) => {
const { id } = req.params;
const producto = inventario[id];
const actualizaciones = req.body;
// Procesar actualizaciones en lotes
const cambiosAplicados = {};
// Actualizar stock si se proporciona
if (actualizaciones.ajusteStock !== undefined) {
producto.stock += actualizaciones.ajusteStock;
cambiosAplicados.stockAnterior = producto.stock - actualizaciones.ajusteStock;
cambiosAplicados.stockActual = producto.stock;
}
// Actualizar precio con historial
if (actualizaciones.precio !== undefined) {
if (!producto.historialPrecios) {
producto.historialPrecios = [];
}
producto.historialPrecios.push({
precio: producto.precio,
fecha: new Date()
});
producto.precio = actualizaciones.precio;
cambiosAplicados.precioActualizado = true;
}
// Actualizar otros campos directamente
const camposDirectos = ['nombre', 'descripcion', 'categoria'];
camposDirectos.forEach(campo => {
if (actualizaciones[campo] !== undefined) {
producto[campo] = actualizaciones[campo];
cambiosAplicados[campo] = true;
}
});
res.json({
producto,
cambiosAplicados,
timestamp: new Date()
});
});
La implementación efectiva de actualizaciones de recursos en Express requiere considerar la consistencia de datos, la validación apropiada y el manejo de errores, asegurando que cada operación mantenga la integridad del sistema mientras proporciona retroalimentación clara al cliente sobre los cambios realizados.
Aprendizajes de esta lección de Express
- Comprender la diferencia entre actualizaciones completas (PUT) y parciales (PATCH).
- Aprender a implementar validaciones específicas para cada método.
- Conocer la importancia de la idempotencia en las operaciones de actualización.
- Saber manejar la existencia previa de recursos y preservar metadatos durante la actualización.
- Aplicar buenas prácticas para mantener la integridad y consistencia de datos en actualizaciones REST.
Completa este curso de Express y certifícate
Únete a nuestra plataforma de cursos de programación 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