Construcción de un servidor usando el módulo nativo http
Para crear un servidor básico con Node.js, se puede utilizar el módulo http incorporado. A continuación, se muestra un ejemplo en un archivo servidor.js:
const http = require('http');
const host = 'localhost';
const puerto = 3000;
const servidor = http.createServer((solicitud, respuesta) => {
respuesta.statusCode = 200;
respuesta.setHeader('Content-Type', 'text/html');
respuesta.end('Hola Mundo\n');
});
servidor.listen(puerto, () => {
console.log(`Servidor activo en http://${host}:${puerto}/`);
});
Este enfoque presenta desventajas significativas. Primero, requiere escribir código de bajo nivel, como establecer manualmente códigos de estado HTTP y encabezados, lo que se vuelve complejo al manejar características avanzadas como la autenticación. Segundo, carece de un mecanismo de rutas dedicado; la lógica de enrutamiento debe implementarse dentro de la función de callback, lo que dificulta la escalabilidad en aplicaciones grandes.
Express aborda estas limitaciones mediante dos mejoras clave: objetos de solicitud y respuesta enriquecidos con métodos útiles, y un sistema de rutas flexible que facilita la modularización del código.
Mejoras en los objetos Request y Response
El objeto de solicitud (comúnmente llamado req) incluye propiedades como:
- req.body: datos del cuerpo de la solicitud, como formularios o JSON.
- req.params: parámetros de ruta en la URI.
- req.query: parámetros de consulta en la URI.
- req.cookies: cookies del cliente.
El objeto de respuesta (res) permite operaciones como enviar HTML, archivos o renderizar plantillas:
// Envío de código HTML
res.send('<h1>Contenido HTML</h1>');
// Envío de un archivo
res.sendFile('documento.pdf');
// Renderización de una plantilla
res.render('pagina');
Sistema de rutas
Las rutas definen cómo el servidor responde a solicitudes en endpoints específicos, combinando una URI y un método HTTP. En Express, se definen con la sintaxis:
aplicacion.METODO(RUTA, CONTROLADOR)
Donde aplicacion es la instancia de Express, METODO es un método HTTP en minúsculas (get, post, etc.), RUTA es la URI, y CONTROLADOR es la función que ejecuta la lógica.
Implementación con Express
Reescribamos el servidor usando Express:
const express = require('express');
const host = 'localhost';
const puerto = 3000;
const aplicacion = express();
aplicacion.get('/', (solicitud, respuesta) => {
respuesta.send('Hola Mundo');
});
aplicacion.listen(puerto, () => {
console.log(`Servidor activo en http://${host}:${puerto}/`);
});
Aquí se crea la instancia de Express, se define una ruta para '/' y se inicia el servidor.
Middelwares
Los middlewares son funciones que se ejecutan secuencialmente antes de llegar a la lógica de las rutas. En el flujo simplificado, una solicitud pasa por middlewares en orden, y luego se procesa la ruta correspondiente. Es importante notar que el orden de registro es crucial, y cada middleware debe invocar next() para pasar al siguiente o finalizar la respuesta.
function miMiddleware(solicitud, respuesta, siguiente) {
// Lógica personalizada
siguiente();
}
Los middlewares se pueden registrar globalmente o por ruta. Para uso global:
aplicacion.use(miMiddleware);
Para uso en una ruta específica:
aplicacion.get('/ruta-especifica', miMiddleware, (solicitud, respuesta) => {
respuesta.send('Contenido protegido');
});
Modularización con subrutas
Para aplicaciones grandes, se pueden usar routers de Express para dividir el código. Un router actúa como una mini-aplicación:
const express = require('express');
const enrutador = express.Router();
enrutador.get('/info', (solicitud, respuesta) => {
respuesta.json({ mensaje: 'Datos de ejemplo' });
});
enrutador.post('/crear', (solicitud, respuesta) => {
respuesta.status(201).json({ exito: true });
});
Luego, el router se integra en la aplicación principal como middleware:
const aplicacion = express();
aplicacion.use('/api', enrutador);
Esto asigna las rutas del router bajo '/api', por ejemplo, '/api/info' y '/api/crear'. Un ejemplo completo incluiría la creación de un archivo de rutas separado, como routes/datos.js, y su importación en el servidor principle:
// Archivo routes/datos.js
const express = require('express');
const routerDatos = express.Router();
routerDatos.get('/', (solicitud, respuesta) => {
respuesta.json({ comunidad: 'Ejemplo', sitio: 'https://ejemplo.com' });
});
routerDatos.post('/nuevo', (solicitud, respuesta) => {
respuesta.status(201).json({ aviso: 'Operación exitosa' });
});
module.exports = routerDatos;
// Archivo servidor.js
const express = require('express');
const routerDatos = require('./routes/datos');
const host = 'localhost';
const puerto = 3000;
const aplicacion = express();
aplicacion.use('/datos', routerDatos);
aplicacion.use('*', (solicitud, respuesta) => {
respuesta.status(404).send('Página no encontrada');
});
En este caso, las rutas del router están bajo '/datos', y se maneja un error 404 para rutas no definidas.