10.2-Ejemplo MVC con Express y app.route
🏗️ Ejemplo MVC con Express y app.route()
Aquí tienes el CRUD anterior reorganizado en arquitectura MVC (Modelo-Vista-Controlador):
📁 ESTRUCTURA DEL PROYECTO
text
mi-app-mvc/
├── models/
│ └── Producto.js
├── controllers/
│ └── productoController.js
├── routes/
│ └── productoRoutes.js
├── views/ (opcional, si usas EJS)
├── app.js
└── server.js
📄 CÓDIGO COMPLETO
1️⃣ models/Producto.js (Modelo - Datos y lógica de negocio)
javascript
// Modelo de Producto - Maneja los datos y operaciones con la "base de datos"
class Producto {
constructor() {
// Base de datos simulada
this.productos = [
{ id: 1, nombre: 'Laptop', precio: 1000 },
{ id: 2, nombre: 'Mouse', precio: 25 },
{ id: 3, nombre: 'Teclado', precio: 50 }
];
this.contadorId = 4;
}
// Obtener todos los productos
obtenerTodos() {
return this.productos;
}
// Obtener un producto por ID
obtenerPorId(id) {
return this.productos.find(p => p.id === id);
}
// Crear nuevo producto
crear(nombre, precio) {
const nuevoProducto = {
id: this.contadorId++,
nombre,
precio: parseFloat(precio)
};
this.productos.push(nuevoProducto);
return nuevoProducto;
}
// Actualizar producto
actualizar(id, nombre, precio) {
const index = this.productos.findIndex(p => p.id === id);
if (index === -1) return null;
this.productos[index] = {
...this.productos[index],
nombre,
precio: parseFloat(precio)
};
return this.productos[index];
}
// Eliminar producto
eliminar(id) {
const index = this.productos.findIndex(p => p.id === id);
if (index === -1) return null;
const eliminado = this.productos.splice(index, 1);
return eliminado[0];
}
}
module.exports = new Producto();
2️⃣ controllers/productoController.js (Controlador - Lógica de respuesta)
javascript
const Producto = require('../models/Producto');
// Controlador: Procesa las peticiones y envía respuestas
class ProductoController {
// GET /productos - Obtener todos
obtenerTodos(req, res) {
const productos = Producto.obtenerTodos();
res.json({
success: true,
total: productos.length,
productos: productos
});
}
// POST /productos - Crear nuevo
crear(req, res) {
const { nombre, precio } = req.body;
// Validaciones
if (!nombre || !precio) {
return res.status(400).json({
error: 'Faltan datos: nombre y precio son requeridos'
});
}
if (isNaN(precio)) {
return res.status(400).json({
error: 'El precio debe ser un número'
});
}
const nuevoProducto = Producto.crear(nombre, precio);
res.status(201).json({
mensaje: '✅ Producto creado exitosamente',
producto: nuevoProducto
});
}
// GET /productos/:id - Obtener uno
obtenerUno(req, res) {
const id = parseInt(req.params.id);
const producto = Producto.obtenerPorId(id);
if (!producto) {
return res.status(404).json({
error: `Producto con ID ${id} no encontrado`
});
}
res.json(producto);
}
// PUT /productos/:id - Actualizar
actualizar(req, res) {
const id = parseInt(req.params.id);
const { nombre, precio } = req.body;
if (!nombre || !precio) {
return res.status(400).json({
error: 'Faltan datos: nombre y precio son requeridos'
});
}
const productoActualizado = Producto.actualizar(id, nombre, precio);
if (!productoActualizado) {
return res.status(404).json({
error: `Producto con ID ${id} no encontrado`
});
}
res.json({
mensaje: '✅ Producto actualizado exitosamente',
producto: productoActualizado
});
}
// DELETE /productos/:id - Eliminar
eliminar(req, res) {
const id = parseInt(req.params.id);
const productoEliminado = Producto.eliminar(id);
if (!productoEliminado) {
return res.status(404).json({
error: `Producto con ID ${id} no encontrado`
});
}
res.json({
mensaje: '✅ Producto eliminado exitosamente',
producto: productoEliminado
});
}
}
module.exports = new ProductoController();
3️⃣ routes/productoRoutes.js (Rutas - Definición de endpoints con app.route)
javascript
const express = require('express');
const productoController = require('../controllers/productoController');
const router = express.Router();
// ============ USANDO app.route() ============
// Rutas para colección de productos
router.route('/productos')
.get(productoController.obtenerTodos) // GET /productos
.post(productoController.crerar); // POST /productos
// Rutas para producto específico
router.route('/productos/:id')
.get(productoController.obtenerUno) // GET /productos/:id
.put(productoController.actualizar) // PUT /productos/:id
.delete(productoController.eliminar); // DELETE /productos/:id
module.exports = router;
4️⃣ app.js (Configuración central)
javascript
const express = require('express');
const app = express();
const productoRoutes = require('./routes/productoRoutes');
// Middlewares globales
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Archivos estáticos (opcional)
app.use(express.static('public'));
// ============ REGISTRAR RUTAS ============
app.use('/', productoRoutes); // Todas las rutas estarán disponibles
// Ruta de bienvenida (opcional)
app.get('/', (req, res) => {
res.send(`
<h1>📦 API MVC con app.route()</h1>
<h2>Endpoints disponibles:</h2>
<ul>
<li><strong>GET</strong> /productos - Ver todos</li>
<li><strong>GET</strong> /productos/1 - Ver uno</li>
<li><strong>POST</strong> /productos - Crear</li>
<li><strong>PUT</strong> /productos/1 - Actualizar</li>
<li><strong>DELETE</strong> /productos/1 - Eliminar</li>
</ul>
<h3>Ejemplo POST/PUT (JSON):</h3>
<code>{"nombre": "Monitor", "precio": 300}</code>
`);
});
// Manejo de errores 404
app.use((req, res) => {
res.status(404).json({ error: 'Ruta no encontrada' });
});
module.exports = app;
5️⃣ server.js (Punto de entrada)
javascript
const app = require('./app');
const PORT = 3000;
app.listen(PORT, () => {
console.log(`\n=================================`);
console.log(`🚀 Servidor MVC corriendo en http://localhost:${PORT}`);
console.log(`📦 API de Productos con app.route()`);
console.log(`\n📌 Probar endpoints:`);
console.log(` GET /productos`);
console.log(` GET /productos/1`);
console.log(` POST /productos`);
console.log(` PUT /productos/1`);
console.log(` DELETE /productos/1`);
console.log(`=================================\n`);
});
🚀 CÓMO EJECUTAR
bash
# 1. Instalar Express
npm install express
# 2. Ejecutar el servidor
node server.js
📊 FLUJO DE LA ARQUITECTURA MVC
text
Petición HTTP
↓
[Routes] app.route('/productos')
↓
[Controller] productoController.obtenerTodos()
↓
[Model] Producto.obtenerTodos()
↓
[Model] Base de datos simulada
↓
[Controller] res.json() respuesta
↓
Cliente (JSON)
💡 VENTAJAS DE ESTA ORGANIZACIÓN MVC
🧪 PROBAR CON CURL
bash
# GET todos
curl http://localhost:3000/productos
# GET uno
curl http://localhost:3000/productos/1
# POST crear
curl -X POST http://localhost:3000/productos \
-H "Content-Type: application/json" \
-d '{"nombre":"Tablet","precio":200}'
# PUT actualizar
curl -X PUT http://localhost:3000/productos/1 \
-H "Content-Type: application/json" \
-d '{"nombre":"Ultrabook","precio":1200}'
# DELETE eliminar
curl -X DELETE http://localhost:3000/productos/2
🔄 SI QUIERES AGREGAR VISTAS EJS
javascript
// En app.js (agregar después de middlewares)
app.set('view engine', 'ejs');
app.set('views', './views');
// En productoController.js (agregar método)
mostrarVistaProductos(req, res) {
const productos = Producto.obtenerTodos();
res.render('productos', {
title: 'Lista de Productos',
productos
});
}
// En productoRoutes.js (agregar ruta)
router.get('/productos-vista', productoController.mostrarVistaProductos);
¡Así queda un CRUD completo en MVC usando app.route()
Comentarios
Publicar un comentario