Certificado de Express API REST

10h 0m

Aprende a desarrollar una API REST con Express y Node.js, el framework backend de JavaScript más popular. Curso completo para crear aplicaciones web robustas.

Empezar curso

Express.js se ha consolidado como el framework web más utilizado para Node.js, proporcionando una base sólida y flexible para construir APIs REST de nivel profesional. 

Su filosofía minimalista y su extenso ecosistema de middlewares lo convierten en la elección preferida por desarrolladores y empresas para crear servicios web escalables y mantenibles.

¿Qué es Express.js?

Express.js es un framework web minimalista para Node.js que simplifica significativamente el proceso de creación de aplicaciones web y APIs. A diferencia de otros frameworks más pesados, Express adopta un enfoque no opinativo, permitiendo a los desarrolladores estructurar sus aplicaciones según sus necesidades específicas.

El framework proporciona una capa de abstracción sobre el módulo HTTP nativo de Node.js, ofreciendo características esenciales como:

  • Sistema de enrutamiento robusto y flexible
  • Gestión de middlewares para el procesamiento de peticiones
  • Manejo simplificado de peticiones y respuestas HTTP
  • Integración nativa con motores de plantillas
  • Soporte completo para métodos HTTP estándar
const express = require('express');
const app = express();

// Ruta básica
app.get('/', (req, res) => {
  res.json({ mensaje: 'API funcionando correctamente' });
});

app.listen(3000, () => {
  console.log('Servidor ejecutándose en puerto 3000');
});

Arquitectura REST

Las APIs REST (Representational State Transfer) definen un conjunto de principios arquitectónicos para diseñar servicios web que sean escalables, mantenibles y fáciles de consumir. Express.js facilita enormemente la implementación de estos principios mediante su sistema de enrutamiento y manejo de métodos HTTP.

Principios REST fundamentales

Los servicios REST se basan en varios conceptos clave que Express implementa de manera natural:

  • Recursos identificables: Cada recurso tiene una URL única
  • Métodos HTTP estándar: GET, POST, PUT, DELETE para diferentes operaciones
  • Representaciones: Los datos se intercambian en formatos como JSON
  • Sin estado: Cada petición contiene toda la información necesaria
// Ejemplo de rutas RESTful para un recurso 'usuarios'
app.get('/api/usuarios', obtenerUsuarios);        // Listar todos
app.get('/api/usuarios/:id', obtenerUsuario);     // Obtener uno específico
app.post('/api/usuarios', crearUsuario);          // Crear nuevo
app.put('/api/usuarios/:id', actualizarUsuario);  // Actualizar completo
app.delete('/api/usuarios/:id', eliminarUsuario); // Eliminar

Métodos HTTP

Express proporciona métodos específicos para cada verbo HTTP, permitiendo una implementación clara y semánticamente correcta de las operaciones CRUD (Create, Read, Update, Delete).

GET: Recuperación de datos

El método GET se utiliza para recuperar información sin modificar el estado del servidor. Express maneja estas peticiones de forma eficiente, permitiendo tanto la recuperación de colecciones completas como de recursos específicos.

// Obtener todos los productos
app.get('/api/productos', (req, res) => {
  const productos = obtenerTodosLosProductos();
  res.json(productos);
});

// Obtener producto específico
app.get('/api/productos/:id', (req, res) => {
  const { id } = req.params;
  const producto = obtenerProductoPorId(id);
  
  if (!producto) {
    return res.status(404).json({ error: 'Producto no encontrado' });
  }
  
  res.json(producto);
});

POST: Creación de recursos

Las peticiones POST permiten crear nuevos recursos en el servidor. Express facilita el acceso a los datos enviados en el cuerpo de la petición mediante middlewares de parsing.

app.use(express.json()); // Middleware para parsear JSON

app.post('/api/productos', (req, res) => {
  const { nombre, precio, categoria } = req.body;
  
  // Validación básica
  if (!nombre || !precio) {
    return res.status(400).json({ 
      error: 'Nombre y precio son obligatorios' 
    });
  }
  
  const nuevoProducto = crearProducto({ nombre, precio, categoria });
  res.status(201).json(nuevoProducto);
});

PUT y PATCH: Actualización de recursos

Express distingue entre actualizaciones completas (PUT) y actualizaciones parciales (PATCH), permitiendo implementar estrategias de actualización flexibles según las necesidades de la aplicación.

// Actualización completa con PUT
app.put('/api/productos/:id', (req, res) => {
  const { id } = req.params;
  const datosCompletos = req.body;
  
  const productoActualizado = reemplazarProducto(id, datosCompletos);
  res.json(productoActualizado);
});

// Actualización parcial con PATCH
app.patch('/api/productos/:id', (req, res) => {
  const { id } = req.params;
  const cambios = req.body;
  
  const productoActualizado = actualizarProductoParcial(id, cambios);
  res.json(productoActualizado);
});

Parámetros y Query Strings

Express proporciona acceso directo a diferentes tipos de parámetros que pueden enviarse en las peticiones HTTP, facilitando la creación de APIs flexibles y expresivas.

Parámetros de ruta

Los parámetros de ruta permiten capturar valores dinámicos directamente desde la URL, proporcionando una forma limpia de identificar recursos específicos.

// Parámetro simple
app.get('/api/usuarios/:id', (req, res) => {
  const userId = req.params.id;
  // Procesar petición...
});

// Múltiples parámetros
app.get('/api/usuarios/:userId/pedidos/:pedidoId', (req, res) => {
  const { userId, pedidoId } = req.params;
  // Procesar petición con ambos parámetros...
});

Query parameters

Los query parameters ofrecen una forma flexible de enviar parámetros opcionales, especialmente útiles para filtrado, paginación y ordenamiento.

app.get('/api/productos', (req, res) => {
  const { 
    categoria, 
    precio_min, 
    precio_max, 
    orden = 'nombre',
    pagina = 1,
    limite = 10 
  } = req.query;
  
  const filtros = {
    categoria,
    precioMin: precio_min,
    precioMax: precio_max
  };
  
  const productos = buscarProductos(filtros, orden, pagina, limite);
  res.json(productos);
});

Request y response

Express enriquece significativamente los objetos de petición y respuesta nativos de Node.js, proporcionando métodos y propiedades adicionales que simplifican el desarrollo de APIs.

Request

El objeto request contiene toda la información sobre la petición HTTP entrante, incluyendo datos, cabeceras, parámetros y metadatos útiles.

app.post('/api/analizar-peticion', (req, res) => {
  // Información básica de la petición
  console.log('Método:', req.method);
  console.log('URL:', req.url);
  console.log('IP del cliente:', req.ip);
  
  // Cabeceras
  console.log('User-Agent:', req.get('User-Agent'));
  console.log('Content-Type:', req.get('Content-Type'));
  
  // Datos de la petición
  console.log('Parámetros de ruta:', req.params);
  console.log('Query parameters:', req.query);
  console.log('Cuerpo de la petición:', req.body);
  
  res.json({ mensaje: 'Petición analizada correctamente' });
});

Response

El objeto response proporciona métodos para enviar respuestas al cliente, configurar cabeceras y gestionar el estado de la respuesta.

app.get('/api/respuesta-completa', (req, res) => {
  // Configurar cabeceras
  res.set('X-API-Version', '1.0');
  res.set('Cache-Control', 'no-cache');
  
  // Configurar código de estado y enviar respuesta
  res.status(200).json({
    datos: { mensaje: 'Respuesta exitosa' },
    timestamp: new Date().toISOString(),
    version: '1.0'
  });
});

Headers y códigos HTTP

El manejo adecuado de cabeceras HTTP y códigos de estado es fundamental para crear APIs que se comuniquen efectivamente con los clientes y sigan los estándares web.

Gestión de cabeceras

Las cabeceras HTTP transportan metadatos importantes sobre la petición y la respuesta. Express facilita tanto la lectura de cabeceras entrantes como la configuración de cabeceras salientes.

app.post('/api/procesar-archivo', (req, res) => {
  // Leer cabeceras de la petición
  const contentType = req.get('Content-Type');
  const authorization = req.get('Authorization');
  
  if (!authorization) {
    return res.status(401)
      .set('WWW-Authenticate', 'Bearer')
      .json({ error: 'Token de autorización requerido' });
  }
  
  // Configurar cabeceras de respuesta
  res.set({
    'X-Processed-By': 'Express API',
    'X-Processing-Time': Date.now(),
    'Content-Type': 'application/json'
  });
  
  res.json({ mensaje: 'Archivo procesado correctamente' });
});

Códigos HTTP

Los códigos de estado comunican el resultado de la petición de manera estandarizada. Express permite configurar estos códigos de forma explícita para proporcionar información precisa a los clientes.

app.get('/api/recurso/:id', (req, res) => {
  const { id } = req.params;
  
  try {
    const recurso = obtenerRecurso(id);
    
    if (!recurso) {
      // 404 - No encontrado
      return res.status(404).json({ 
        error: 'Recurso no encontrado',
        codigo: 'RESOURCE_NOT_FOUND' 
      });
    }
    
    // 200 - Éxito
    res.status(200).json(recurso);
    
  } catch (error) {
    // 500 - Error interno del servidor
    res.status(500).json({ 
      error: 'Error interno del servidor',
      codigo: 'INTERNAL_ERROR' 
    });
  }
});

Middlewares

Los middlewares constituyen el corazón de Express, proporcionando un mecanismo elegante para procesar peticiones de forma modular y reutilizable. Cada middleware es una función que tiene acceso a los objetos de petición y respuesta, así como al siguiente middleware en la cadena.

Concepto de middleware

Un middleware es esencialmente una función que se ejecuta durante el ciclo de vida de una petición HTTP. Esta función puede modificar los objetos de petición y respuesta, ejecutar código, finalizar el ciclo petición-respuesta, o llamar al siguiente middleware en la pila.

// Middleware básico de logging
const logger = (req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`${timestamp} - ${req.method} ${req.url}`);
  next(); // Pasar control al siguiente middleware
};

// Aplicar middleware globalmente
app.use(logger);

// Middleware específico para una ruta
app.get('/api/protegida', autenticar, (req, res) => {
  res.json({ mensaje: 'Acceso autorizado' });
});

Middlewares integrados

Express incluye varios middlewares integrados que cubren necesidades comunes en el desarrollo de APIs, eliminando la necesidad de dependencias externas para funcionalidades básicas.

// Middleware para parsear JSON
app.use(express.json({ limit: '10mb' }));

// Middleware para parsear datos de formularios
app.use(express.urlencoded({ extended: true }));

// Middleware para servir archivos estáticos
app.use('/public', express.static('public'));

// Ejemplo de uso combinado
app.post('/api/upload', (req, res) => {
  // express.json() ya parseó el cuerpo de la petición
  const { titulo, descripcion } = req.body;
  
  res.json({ 
    mensaje: 'Datos recibidos correctamente',
    datos: { titulo, descripcion }
  });
});

Middlewares personalizados

La creación de middlewares personalizados permite encapsular lógica específica de la aplicación de forma reutilizable y mantenible.

// Middleware de autenticación
const autenticar = (req, res, next) => {
  const token = req.get('Authorization');
  
  if (!token) {
    return res.status(401).json({ error: 'Token requerido' });
  }
  
  try {
    const usuario = verificarToken(token);
    req.usuario = usuario; // Agregar información al objeto request
    next();
  } catch (error) {
    res.status(403).json({ error: 'Token inválido' });
  }
};

// Middleware de validación
const validarProducto = (req, res, next) => {
  const { nombre, precio } = req.body;
  
  if (!nombre || typeof nombre !== 'string') {
    return res.status(400).json({ error: 'Nombre inválido' });
  }
  
  if (!precio || precio <= 0) {
    return res.status(400).json({ error: 'Precio inválido' });
  }
  
  next();
};

// Uso de middlewares personalizados
app.post('/api/productos', autenticar, validarProducto, (req, res) => {
  // En este punto, la petición está autenticada y validada
  const producto = crearProducto(req.body);
  res.status(201).json(producto);
});

Control de flujo y errores

El control de flujo en Express se gestiona principalmente a través de la función next(), que permite dirigir la ejecución entre middlewares y manejar tanto el flujo normal como las situaciones de error.

La función next()

La función next() es el mecanismo que permite pasar el control al siguiente middleware en la cadena. Su uso correcto es fundamental para el funcionamiento adecuado de la aplicación.

// Middleware con control de flujo condicional
const verificarPermisos = (req, res, next) => {
  const usuario = req.usuario;
  
  if (usuario.rol === 'admin') {
    // Continuar con el siguiente middleware
    next();
  } else if (usuario.rol === 'usuario') {
    // Saltar al middleware de error
    next(new Error('Permisos insuficientes'));
  } else {
    // Responder directamente sin continuar
    res.status(403).json({ error: 'Rol no reconocido' });
  }
};

Gestión de errores

Express permite implementar un sistema centralizado de manejo de errores mediante middlewares especiales que reciben cuatro parámetros en lugar de tres.

// Middleware de manejo de errores (debe ir al final)
const manejarErrores = (error, req, res, next) => {
  console.error('Error capturado:', error.message);
  
  // Diferentes tipos de errores
  if (error.name === 'ValidationError') {
    return res.status(400).json({
      error: 'Datos de entrada inválidos',
      detalles: error.message
    });
  }
  
  if (error.name === 'UnauthorizedError') {
    return res.status(401).json({
      error: 'No autorizado',
      mensaje: 'Token inválido o expirado'
    });
  }
  
  // Error genérico
  res.status(500).json({
    error: 'Error interno del servidor',
    mensaje: 'Ha ocurrido un error inesperado'
  });
};

// Aplicar el middleware de errores
app.use(manejarErrores);

Validación de datos

La validación de datos es crucial para mantener la integridad de la API y proporcionar retroalimentación útil a los clientes.

// Middleware de validación avanzada
const validarCreacionUsuario = (req, res, next) => {
  const { email, password, nombre } = req.body;
  const errores = [];
  
  // Validar email
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!email || !emailRegex.test(email)) {
    errores.push('Email inválido');
  }
  
  // Validar contraseña
  if (!password || password.length < 8) {
    errores.push('La contraseña debe tener al menos 8 caracteres');
  }
  
  // Validar nombre
  if (!nombre || nombre.trim().length < 2) {
    errores.push('El nombre debe tener al menos 2 caracteres');
  }
  
  if (errores.length > 0) {
    return res.status(400).json({
      error: 'Datos de entrada inválidos',
      detalles: errores
    });
  }
  
  // Limpiar y normalizar datos
  req.body.email = email.toLowerCase().trim();
  req.body.nombre = nombre.trim();
  
  next();
};

app.post('/api/usuarios', validarCreacionUsuario, (req, res) => {
  // Los datos ya están validados y normalizados
  const usuario = crearUsuario(req.body);
  res.status(201).json(usuario);
});
Empezar curso

Otros cursos de programación con certificado

Supera todos los retos de Express API REST y obtén estos certificados de superación para mejorar tu currículum y tu empleabilidad.

Tecnologías que aprenderás

Express API REST

Al finalizar este curso obtendrás

Certificado de superación en Express API REST

Certificado de superación en Express API REST

Tras completar todas las lecciones y ejercicios del curso Express API REST se te genera un enlace con tu certificado para que lo puedas descargar o compartir directamente en cualquier plataforma, siempre accesible.

Accede a todas certificaciones