Express
Tutorial Express: Métodos DELETE
Aprende a implementar rutas DELETE en Express para eliminar recursos con validación, manejo de errores y confirmaciones seguras.
Aprende Express y certifícateEliminación de recursos
El método DELETE en Express está específicamente diseñado para eliminar recursos del servidor. A diferencia de otros métodos HTTP, DELETE tiene una semántica clara: su propósito es remover completamente un recurso identificado por la URL solicitada.
La sintaxis básica para definir una ruta DELETE en Express sigue el mismo patrón que otros métodos HTTP:
app.delete('/ruta', (req, res) => {
// Lógica de eliminación
});
Eliminación por identificador
La forma más común de implementar eliminación de recursos es mediante un identificador único en la URL. Este patrón permite especificar exactamente qué recurso debe ser eliminado:
app.delete('/usuarios/:id', (req, res) => {
const userId = req.params.id;
// Simulación de eliminación de base de datos
const usuarioEliminado = eliminarUsuario(userId);
if (usuarioEliminado) {
res.status(204).send(); // 204 No Content - eliminación exitosa
} else {
res.status(404).json({ error: 'Usuario no encontrado' });
}
});
El código de estado 204 (No Content) es la respuesta estándar para eliminaciones exitosas, ya que indica que la operación se completó correctamente pero no hay contenido que devolver.
Eliminación con validación de existencia
Antes de eliminar un recurso, es fundamental verificar su existencia para proporcionar respuestas apropiadas al cliente:
app.delete('/productos/:id', async (req, res) => {
const productId = parseInt(req.params.id);
// Verificar si el producto existe
const producto = await buscarProducto(productId);
if (!producto) {
return res.status(404).json({
error: 'Producto no encontrado',
id: productId
});
}
// Proceder con la eliminación
await eliminarProducto(productId);
res.status(204).send();
});
Eliminación con información de respuesta
Aunque el estándar sugiere usar 204 No Content, en algunos casos puede ser útil devolver información sobre el recurso eliminado:
app.delete('/tareas/:id', (req, res) => {
const tareaId = req.params.id;
const tarea = buscarTarea(tareaId);
if (!tarea) {
return res.status(404).json({ error: 'Tarea no encontrada' });
}
eliminarTarea(tareaId);
// Devolver información del recurso eliminado
res.status(200).json({
mensaje: 'Tarea eliminada correctamente',
tarea: {
id: tarea.id,
titulo: tarea.titulo,
fechaEliminacion: new Date().toISOString()
}
});
});
Eliminación múltiple
Express permite implementar eliminación de múltiples recursos mediante diferentes enfoques. Una opción es usar parámetros de consulta:
app.delete('/archivos', (req, res) => {
const ids = req.query.ids;
if (!ids) {
return res.status(400).json({
error: 'Se requiere especificar los IDs a eliminar'
});
}
// Convertir string de IDs separados por coma a array
const idsArray = ids.split(',').map(id => parseInt(id.trim()));
const resultados = [];
idsArray.forEach(id => {
const eliminado = eliminarArchivo(id);
resultados.push({ id, eliminado });
});
res.status(200).json({
mensaje: 'Proceso de eliminación completado',
resultados
});
});
Manejo de errores en eliminación
La gestión de errores en operaciones DELETE debe contemplar diferentes escenarios que pueden ocurrir durante el proceso:
app.delete('/comentarios/:id', async (req, res) => {
try {
const comentarioId = req.params.id;
// Validar formato del ID
if (!comentarioId.match(/^\d+$/)) {
return res.status(400).json({
error: 'ID de comentario inválido'
});
}
const resultado = await eliminarComentario(comentarioId);
if (resultado.error) {
return res.status(500).json({
error: 'Error interno del servidor',
detalle: resultado.error
});
}
res.status(204).send();
} catch (error) {
console.error('Error eliminando comentario:', error);
res.status(500).json({
error: 'Error interno del servidor'
});
}
});
Eliminación condicional
En algunos casos, la eliminación debe estar condicionada a ciertos criterios o permisos:
app.delete('/posts/:id', (req, res) => {
const postId = req.params.id;
const usuarioId = req.headers['user-id']; // Simulando autenticación
const post = buscarPost(postId);
if (!post) {
return res.status(404).json({ error: 'Post no encontrado' });
}
// Verificar permisos de eliminación
if (post.autorId !== usuarioId) {
return res.status(403).json({
error: 'No tienes permisos para eliminar este post'
});
}
eliminarPost(postId);
res.status(204).send();
});
La implementación correcta de rutas DELETE requiere considerar la validación de datos, el manejo de errores y la respuesta apropiada según el resultado de la operación, garantizando que el cliente reciba información clara sobre el estado de la eliminación solicitada.
Confirmaciones de borrado
En aplicaciones web profesionales, la eliminación directa de recursos puede resultar peligrosa y generar pérdidas de datos accidentales. Las confirmaciones de borrado proporcionan una capa adicional de seguridad que permite a los usuarios verificar su intención antes de proceder con la eliminación definitiva.
Confirmación mediante parámetros de consulta
Una aproximación sencilla para implementar confirmaciones es utilizar parámetros de consulta que indiquen explícitamente la intención del usuario:
app.delete('/documentos/:id', (req, res) => {
const documentoId = req.params.id;
const confirmacion = req.query.confirm;
if (confirmacion !== 'true') {
return res.status(400).json({
error: 'Eliminación requiere confirmación',
mensaje: 'Añade ?confirm=true para confirmar la eliminación',
recurso: { id: documentoId, tipo: 'documento' }
});
}
// Proceder con la eliminación confirmada
const eliminado = eliminarDocumento(documentoId);
if (eliminado) {
res.status(204).send();
} else {
res.status(404).json({ error: 'Documento no encontrado' });
}
});
Confirmación con token de seguridad
Para operaciones críticas, es recomendable implementar un sistema de tokens que garantice que la confirmación proviene de una fuente autorizada:
app.delete('/cuentas/:id', (req, res) => {
const cuentaId = req.params.id;
const tokenConfirmacion = req.headers['confirmation-token'];
if (!tokenConfirmacion) {
return res.status(400).json({
error: 'Token de confirmación requerido',
instrucciones: 'Incluye el header confirmation-token'
});
}
// Validar token de confirmación
const tokenValido = validarTokenConfirmacion(tokenConfirmacion, cuentaId);
if (!tokenValido) {
return res.status(403).json({
error: 'Token de confirmación inválido o expirado'
});
}
// Eliminar cuenta tras confirmación válida
eliminarCuenta(cuentaId);
res.status(200).json({
mensaje: 'Cuenta eliminada correctamente',
timestamp: new Date().toISOString()
});
});
Confirmación en dos pasos
El patrón de confirmación en dos pasos separa la solicitud de eliminación de su ejecución, proporcionando un flujo más seguro:
// Paso 1: Solicitar confirmación de eliminación
app.post('/proyectos/:id/solicitar-eliminacion', (req, res) => {
const proyectoId = req.params.id;
const proyecto = buscarProyecto(proyectoId);
if (!proyecto) {
return res.status(404).json({ error: 'Proyecto no encontrado' });
}
// Generar token temporal para confirmación
const tokenConfirmacion = generarTokenTemporal(proyectoId);
res.status(200).json({
mensaje: 'Solicitud de eliminación registrada',
tokenConfirmacion,
expiraEn: '5 minutos',
proyecto: {
id: proyecto.id,
nombre: proyecto.nombre
}
});
});
// Paso 2: Ejecutar eliminación con confirmación
app.delete('/proyectos/:id/confirmar', (req, res) => {
const proyectoId = req.params.id;
const { tokenConfirmacion } = req.body;
if (!verificarTokenTemporal(tokenConfirmacion, proyectoId)) {
return res.status(400).json({
error: 'Token de confirmación inválido o expirado',
accion: 'Solicita un nuevo token de eliminación'
});
}
// Proceder con eliminación confirmada
eliminarProyecto(proyectoId);
invalidarTokenTemporal(tokenConfirmacion);
res.status(204).send();
});
Confirmación con información detallada
Antes de proceder con la eliminación, es útil mostrar información detallada sobre las consecuencias de la acción:
app.delete('/categorias/:id', async (req, res) => {
const categoriaId = req.params.id;
const forzarEliminacion = req.query.force === 'true';
const categoria = await buscarCategoria(categoriaId);
if (!categoria) {
return res.status(404).json({ error: 'Categoría no encontrada' });
}
// Verificar dependencias antes de eliminar
const productosAsociados = await contarProductosEnCategoria(categoriaId);
if (productosAsociados > 0 && !forzarEliminacion) {
return res.status(409).json({
error: 'La categoría contiene productos asociados',
detalles: {
categoria: categoria.nombre,
productosAfectados: productosAsociados,
consecuencias: [
'Se eliminarán todos los productos asociados',
'Esta acción no se puede deshacer'
]
},
confirmacion: 'Añade ?force=true para proceder con la eliminación'
});
}
// Eliminar categoría y productos asociados
await eliminarCategoriaCompleta(categoriaId);
res.status(200).json({
mensaje: 'Categoría eliminada correctamente',
productosEliminados: productosAsociados
});
});
Confirmación con tiempo de espera
Para operaciones especialmente críticas, implementar un tiempo de espera obligatorio puede prevenir eliminaciones impulsivas:
app.delete('/bases-datos/:id', (req, res) => {
const baseDatosId = req.params.id;
const tiempoConfirmacion = req.headers['confirmation-timestamp'];
if (!tiempoConfirmacion) {
return res.status(400).json({
error: 'Confirmación temporal requerida',
instrucciones: 'Espera 30 segundos y reenvía con confirmation-timestamp',
timestamp: Date.now()
});
}
const tiempoTranscurrido = Date.now() - parseInt(tiempoConfirmacion);
const tiempoMinimo = 30000; // 30 segundos
if (tiempoTranscurrido < tiempoMinimo) {
const tiempoRestante = Math.ceil((tiempoMinimo - tiempoTranscurrido) / 1000);
return res.status(425).json({
error: 'Tiempo de confirmación insuficiente',
tiempoRestante: `${tiempoRestante} segundos`,
razon: 'Medida de seguridad para operaciones críticas'
});
}
// Proceder con eliminación tras tiempo de espera
eliminarBaseDatos(baseDatosId);
res.status(204).send();
});
Confirmación con múltiples factores
Para máxima seguridad, es posible combinar múltiples métodos de confirmación en una sola operación:
app.delete('/servidores/:id', (req, res) => {
const servidorId = req.params.id;
const {
confirmacionTexto,
tokenAutorizacion,
motivoEliminacion
} = req.body;
const servidor = buscarServidor(servidorId);
if (!servidor) {
return res.status(404).json({ error: 'Servidor no encontrado' });
}
// Validar confirmación textual
const textoEsperado = `ELIMINAR-${servidor.nombre}`;
if (confirmacionTexto !== textoEsperado) {
return res.status(400).json({
error: 'Confirmación textual incorrecta',
esperado: textoEsperado,
recibido: confirmacionTexto
});
}
// Validar token de autorización
if (!validarTokenAutorizacion(tokenAutorizacion)) {
return res.status(403).json({
error: 'Token de autorización inválido'
});
}
// Validar motivo de eliminación
if (!motivoEliminacion || motivoEliminacion.length < 10) {
return res.status(400).json({
error: 'Motivo de eliminación requerido',
requisito: 'Mínimo 10 caracteres explicando la razón'
});
}
// Registrar eliminación con auditoría
registrarEliminacionServidor(servidorId, motivoEliminacion);
eliminarServidor(servidorId);
res.status(200).json({
mensaje: 'Servidor eliminado correctamente',
auditoria: {
servidor: servidor.nombre,
motivo: motivoEliminacion,
timestamp: new Date().toISOString()
}
});
});
La implementación de confirmaciones de borrado robustas protege tanto a los usuarios como a la integridad de los datos, proporcionando múltiples oportunidades para verificar la intención antes de ejecutar operaciones irreversibles.
Otras lecciones de Express
Accede a todas las lecciones de Express y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Expressjs
Introducción Y Entorno
Instalación De Express
Introducción Y Entorno
Estados Http
Routing
Métodos Delete
Routing
Parámetros Y Query Strings
Routing
Métodos Get
Routing
Ejercicios de programación de Express
Evalúa tus conocimientos de esta lección Métodos DELETE con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.