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

text
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)

javascript
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

javascript
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

javascript
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)

html
<!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

html
<!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)

html
<!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

  1. Instala dependencias:

    bash
    npm init -y
    npm install express ejs bootstrap
  2. Crea la estructura de carpetas y archivos con los códigos anteriores.

  3. Ejecuta:

    bash
    node app.js
  4. Prueba en el navegador:

    • Web: http://localhost:3000/ → Lista de productos (HTML)

    • Web detalle: http://localhost:3000/producto/2 → Detalle del producto 2

    • API todos: http://localhost:3000/api/productos → JSON

    • API uno: http://localhost:3000/api/productos/1 → JSON de producto

✅ Ventajas de esta integración

  • Rutas separadas por responsabilidad (api.js para datos, web.js para 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