8-Estructura final (web-api)-routes-public
¡Excelente! Aquí tienes una versión integrada que combina web (con EJS) y API (JSON) en un solo proyecto, todo organizado con express.Router().
📁 Estructura del proyecto
mi-proyecto-integrado/
├── app.js
├── package.json
├── routes/
│ ├── api.js ← Rutas para API (JSON)
│ └── web.js ← Rutas para vistas web (EJS)
├── views/
│ ├── index.ejs ← Lista de productos (HTML)
│ └── detalle.ejs ← Detalle de un producto (HTML)
└── public/ ← Archivos estáticos (opcional)🔧 Código completo
1. app.js – Servidor principal (monta ambos routers)
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000;
// ============ CONFIGURACIÓN EJS ============
app.set('view engine', 'ejs');
// Express busca las vistas en la carpeta 'views' por defecto
// ============ MIDDLEWARE (solo necesario para web) ============
app.use(express.static('public')); // archivos estáticos propios
// Opcional: Bootstrap desde node_modules
app.use('/css', express.static('node_modules/bootstrap/dist/css'));
app.use('/js', express.static('node_modules/bootstrap/dist/js'));
// ============ ROUTERS ============
const apiRouter = require('./routes/api');
const webRouter = require('./routes/web');
// Montar el router de API bajo el prefijo /api
app.use('/api', apiRouter);
// Montar el router web en la raíz (todas las rutas HTML)
app.use('/', webRouter);
// ============ INICIAR SERVIDOR ============
app.listen(PORT, () => {
console.log(`🚀 Servidor corriendo en http://localhost:${PORT}`);
console.log(`🌐 Web: http://localhost:${PORT}`);
console.log(`📡 API: http://localhost:${PORT}/api/productos`);
});2. routes/api.js – Solo endpoints JSON
const express = require('express');
const router = express.Router();
// Datos compartidos (podrían venir de un archivo o BD)
const productos = [
{ id: 1, nombre: 'Laptop', precio: 1000 },
{ id: 2, nombre: 'Mouse', precio: 25 },
{ id: 3, nombre: 'Teclado', precio: 50 }
];
// GET /api/productos → todos los productos
router.get('/productos', (req, res) => {
res.json({
success: true,
cantidad: productos.length,
productos: productos
});
});
// GET /api/productos/:id → un producto
router.get('/productos/:id', (req, res) => {
const id = parseInt(req.params.id);
const producto = productos.find(p => p.id === id);
if (!producto) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
res.json(producto);
});
module.exports = router;3. routes/web.js – Rutas que renderizan HTML con EJS
const express = require('express');
const router = express.Router();
// Mismos datos (para simplificar, se declaran otra vez)
// En un proyecto real conviene importarlos de un archivo común
const productos = [
{ id: 1, nombre: 'Laptop', precio: 1000 },
{ id: 2, nombre: 'Mouse', precio: 25 },
{ id: 3, nombre: 'Teclado', precio: 50 }
];
// Página principal: lista de productos
router.get('/', (req, res) => {
res.render('index', { productos });
});
// Página de detalle de un producto
router.get('/producto/:id', (req, res) => {
const id = parseInt(req.params.id);
const producto = productos.find(p => p.id === id);
if (!producto) {
return res.status(404).render('error', { mensaje: 'Producto no encontrado' });
}
res.render('detalle', { producto });
});
// Opcional: redirigir /productos a la raíz
router.get('/productos', (req, res) => {
res.redirect('/');
});
module.exports = router;4. views/index.ejs – Lista de productos (web)
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mi Tienda</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<h1 class="text-center">🛒 Productos disponibles</h1>
<div class="row">
<% productos.forEach(p => { %>
<div class="col-md-4 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><%= p.nombre %></h5>
<p class="card-text">$<%= p.precio %></p>
<a href="/producto/<%= p.id %>" class="btn btn-primary">Ver detalle</a>
</div>
</div>
</div>
<% }) %>
</div>
<hr>
<p class="text-muted">También puedes usar la API: <a href="/api/productos">/api/productos</a></p>
</div>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>5. views/detalle.ejs – Detalle de un producto
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title><%= producto.nombre %> - Detalle</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<div class="card">
<div class="card-header">
<h2><%= producto.nombre %></h2>
</div>
<div class="card-body">
<p><strong>ID:</strong> <%= producto.id %></p>
<p><strong>Precio:</strong> $<%= producto.precio %></p>
<p><strong>Descripción:</strong> Producto de alta calidad.</p>
<a href="/" class="btn btn-secondary">← Volver al listado</a>
<a href="/api/productos/<%= producto.id %>" class="btn btn-info" target="_blank">Ver JSON (API)</a>
</div>
</div>
</div>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>6. views/error.ejs – Página de error 404 (opcional)
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Error</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<div class="alert alert-danger">
<h4>❌ Error</h4>
<p><%= mensaje %></p>
<a href="/" class="btn btn-primary">Ir al inicio</a>
</div>
</div>
</body>
</html>🧪 Cómo probar la versión integrada
Instala dependencias:
npm init -y npm install express ejs bootstrapCrea la estructura de carpetas y archivos con los códigos anteriores.
Ejecuta:
node app.jsPrueba en el navegador:
Web:
http://localhost:3000/→ Lista de productos (HTML)Web detalle:
http://localhost:3000/producto/2→ Detalle del producto 2API todos:
http://localhost:3000/api/productos→ JSONAPI uno:
http://localhost:3000/api/productos/1→ JSON de producto
✅ Ventajas de esta integración
Rutas separadas por responsabilidad (
api.jspara datos,web.jspara interfaces).Un solo servidor ofrece ambos mundos.
Prefijos claros:
/api/*para JSON, el resto son páginas HTML.Fácil de extender: agregar POST, PUT, DELETE en el router de API; agregar más vistas en el router web.
Comentarios
Publicar un comentario