# Fundamentos de Express.js
Express.js es el framework web más popular para Node.js. Simplifica la creación de servidores, manejo de rutas, middleware y mucho más. Es la base de muchas aplicaciones Node.js.
## ¿Por Qué Express?
Express.js simplifica el módulo `http` integrado:
**Servidor HTTP Plano:**
```javascript
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('
Hola
');
}
}).listen(3000);
```
**Con Express:**
```javascript
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hola
');
});
app.listen(3000);
```
## Instalación
```bash
# Crear proyecto
npm init -y
# Instalar Express
npm install express
# Para desarrollo (opcional)
npm install -D nodemon
```
## Servidor Básico
```javascript
const express = require('express');
// Crear aplicación Express
const app = express();
// Definir ruta
app.get('/', (req, res) => {
res.send('¡Hola desde Express!');
});
// Iniciar servidor
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Servidor ejecutándose en http://localhost:${PORT}`);
});
```
## Enrutamiento
### Métodos HTTP Básicos
```javascript
const express = require('express');
const app = express();
// GET - Leer
app.get('/users', (req, res) => {
res.send('Obtener todos los usuarios');
});
// POST - Crear
app.post('/users', (req, res) => {
res.send('Crear nuevo usuario');
});
// PUT - Actualizar
app.put('/users/:id', (req, res) => {
res.send(`Actualizar usuario ${req.params.id}`);
});
// DELETE - Eliminar
app.delete('/users/:id', (req, res) => {
res.send(`Eliminar usuario ${req.params.id}`);
});
app.listen(3000);
```
### Parámetros de Ruta
```javascript
// Parámetros de ruta
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`Usuario ID: ${userId}`);
});
// Múltiples parámetros
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.send(`Usuario: ${userId}, Post: ${postId}`);
});
// Parámetros opcionales
app.get('/users/:id?', (req, res) => {
if (req.params.id) {
res.send(`Usuario: ${req.params.id}`);
} else {
res.send('Todos los usuarios');
}
});
```
### Parámetros de Query
```javascript
// /search?q=node&category=backend
app.get('/search', (req, res) => {
const { q, category } = req.query;
res.json({
búsqueda: q,
categoría: category
});
});
// Con valores por defecto
app.get('/products', (req, res) => {
const page = req.query.page || 1;
const limit = req.query.limit || 10;
res.json({
página: page,
límite: limit
});
});
```
## Middleware
El middleware son funciones que tienen acceso a los objetos request y response:
### Middleware Integrado
```javascript
const express = require('express');
const app = express();
// Analizar cuerpo JSON
app.use(express.json());
// Analizar datos de formulario codificados en URL
app.use(express.urlencoded({ extended: true }));
// Servir archivos estáticos
app.use(express.static('public'));
// Ahora puedes acceder a archivos en carpeta public:
// http://localhost:3000/style.css
// http://localhost:3000/images/logo.png
```
### Middleware Personalizado
```javascript
// Logger middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // Pasar al siguiente middleware
});
// Middleware de autenticación
function requireAuth(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Token requerido' });
}
// Verificar token...
next();
}
// Usar en ruta específica
app.get('/dashboard', requireAuth, (req, res) => {
res.send('Panel de control');
});
```
### Middleware de Manejo de Errores
```javascript
// Debe estar después de todas las rutas
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: 'Algo salió mal!',
mensaje: err.message
});
});
```
## Manejo de JSON
```javascript
const express = require('express');
const app = express();
// Habilitar análisis de JSON
app.use(express.json());
// Datos de ejemplo
let users = [
{ id: 1, nombre: 'Juan', email: 'juan@ejemplo.com' },
{ id: 2, nombre: 'María', email: 'maria@ejemplo.com' }
];
// GET - Obtener todos los usuarios
app.get('/api/users', (req, res) => {
res.json(users);
});
// GET - Obtener usuario por ID
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
res.json(user);
});
// POST - Crear nuevo usuario
app.post('/api/users', (req, res) => {
const newUser = {
id: users.length + 1,
nombre: req.body.nombre,
email: req.body.email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT - Actualizar usuario
app.put('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
user.nombre = req.body.nombre || user.nombre;
user.email = req.body.email || user.email;
res.json(user);
});
// DELETE - Eliminar usuario
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000);
```
## Archivos Estáticos
```javascript
const express = require('express');
const path = require('path');
const app = express();
// Servir archivos desde carpeta 'public'
app.use(express.static('public'));
// Con prefijo de URL
app.use('/static', express.static('public'));
// Acceder: http://localhost:3000/static/style.css
// Múltiples directorios
app.use(express.static('public'));
app.use(express.static('uploads'));
// Con ruta absoluta
app.use(express.static(path.join(__dirname, 'public')));
app.listen(3000);
```
**Estructura de carpetas:**
```
proyecto/
├── server.js
└── public/
├── index.html
├── style.css
├── script.js
└── images/
└── logo.png
```
Acceder archivos:
- `http://localhost:3000/index.html`
- `http://localhost:3000/style.css`
- `http://localhost:3000/images/logo.png`
## Express Router
Organiza rutas en módulos separados:
**Archivo: routes/users.js**
```javascript
const express = require('express');
const router = express.Router();
// Middleware para este router
router.use((req, res, next) => {
console.log('Solicitud a ruta de usuarios:', Date.now());
next();
});
// Define rutas
router.get('/', (req, res) => {
res.json({ mensaje: 'Obtener todos los usuarios' });
});
router.get('/:id', (req, res) => {
res.json({ mensaje: `Obtener usuario ${req.params.id}` });
});
router.post('/', (req, res) => {
res.json({ mensaje: 'Crear usuario', datos: req.body });
});
module.exports = router;
```
**Archivo: routes/posts.js**
```javascript
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json({ mensaje: 'Obtener todos los posts' });
});
router.get('/:id', (req, res) => {
res.json({ mensaje: `Obtener post ${req.params.id}` });
});
module.exports = router;
```
**Archivo: server.js**
```javascript
const express = require('express');
const app = express();
// Importar routers
const usersRouter = require('./routes/users');
const postsRouter = require('./routes/posts');
app.use(express.json());
// Montar routers
app.use('/api/users', usersRouter);
app.use('/api/posts', postsRouter);
// Rutas disponibles:
// GET /api/users
// GET /api/users/:id
// POST /api/users
// GET /api/posts
// GET /api/posts/:id
app.listen(3000);
```
## Métodos de Response
```javascript
app.get('/examples', (req, res) => {
// Enviar string
res.send('Hola');
// Enviar JSON
res.json({ mensaje: 'Hola' });
// Establecer código de estado
res.status(404).send('No encontrado');
res.status(201).json({ mensaje: 'Creado' });
// Redirigir
res.redirect('/nueva-url');
res.redirect(301, '/nueva-url-permanente');
// Descargar archivo
res.download('/ruta/a/archivo.pdf');
// Enviar archivo
res.sendFile('/ruta/absoluta/a/archivo.html');
// Establecer encabezados
res.set('Content-Type', 'text/html');
res.set({
'Content-Type': 'text/html',
'X-Custom-Header': 'valor'
});
});
```
## Ejemplo Completo: API REST
```javascript
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
// Logger
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
// Datos
let products = [
{ id: 1, nombre: 'Laptop', precio: 999.99 },
{ id: 2, nombre: 'Teléfono', precio: 599.99 }
];
// Rutas
app.get('/api/products', (req, res) => {
res.json(products);
});
app.get('/api/products/:id', (req, res) => {
const product = products.find(p => p.id === parseInt(req.params.id));
if (!product) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
res.json(product);
});
app.post('/api/products', (req, res) => {
const { nombre, precio } = req.body;
if (!nombre || !precio) {
return res.status(400).json({ error: 'Nombre y precio requeridos' });
}
const product = {
id: products.length + 1,
nombre,
precio: parseFloat(precio)
};
products.push(product);
res.status(201).json(product);
});
app.put('/api/products/:id', (req, res) => {
const product = products.find(p => p.id === parseInt(req.params.id));
if (!product) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
product.nombre = req.body.nombre || product.nombre;
product.precio = req.body.precio || product.precio;
res.json(product);
});
app.delete('/api/products/:id', (req, res) => {
const index = products.findIndex(p => p.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
products.splice(index, 1);
res.status(204).send();
});
// Middleware de manejo de errores
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Algo salió mal!' });
});
// Iniciar servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor ejecutándose en puerto ${PORT}`);
});
```
## Mejores Prácticas
1. **Usar Middleware**: Extraer lógica común a middleware
2. **Organizar Rutas**: Usar Express Router para aplicaciones grandes
3. **Manejo de Errores**: Implementar middleware de manejo de errores
4. **Validación**: Validar entrada del usuario
5. **Variables de Entorno**: Usar dotenv para configuración
6. **Seguridad**: Usar helmet, cors, rate limiting
7. **Logging**: Usar morgan u otros loggers
8. **Códigos de Estado**: Usar códigos de estado HTTP apropiados
## Middleware Popular
```bash
npm install cors helmet morgan dotenv
```
```javascript
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
require('dotenv').config();
const app = express();
// Middleware de seguridad
app.use(helmet());
// Habilitar CORS
app.use(cors());
// Logging
app.use(morgan('dev'));
// Análisis de JSON
app.use(express.json());
// Tus rutas aquí...
app.listen(process.env.PORT || 3000);
```
## Recursos
- [Documentación de Express](https://expressjs.com/)
- [Guía de Express](https://expressjs.com/en/guide/routing.html)
- [Middleware de Express](https://expressjs.com/en/resources/middleware.html)
¡Express hace el desarrollo de backend con Node.js mucho más simple! 🚀