Este proyecto utiliza una arquitectura de microservicios simplificada donde:
proyecto-productos/
├── backend/ # API REST (Puerto 3000)
│ ├── package.json
│ └── [tu código existente]
├── frontend/ # Servidor web (Puerto 3001)
│ ├── package.json
│ └── [archivos implementados]
└── instrucciones.md// Backend package.json
{
"dependencies": {
"express": "^4.18.2",
"mongoose": "^7.0.0", // Base de datos
"bcrypt": "^5.1.0", // Encriptación
"jsonwebtoken": "^9.0.0" // Autenticación
}
}
// Frontend package.json
{
"dependencies": {
"express": "^4.18.2",
"ejs": "^3.1.9", // Motor de plantillas
"axios": "^1.4.0" // Cliente HTTP
}
}proyecto-productos/
├── backend/
│ ├── package.json
│ ├── app.js
│ ├── routes/
│ │ └── productos.js
│ └── models/
│ └── producto.js
├── frontend/
│ ├── package.json
│ ├── app.js
│ ├── routes/
│ │ └── productos.js
│ ├── views/
│ │ ├── productos/
│ │ │ └── lista.ejs
│ │ └── error.ejs
│ └── public/
│ ├── css/
│ │ └── styles.css
│ └── js/
│ └── productos.js
└── instrucciones.mdGET /api/productos → [{id: 1, nombre: "...", precio: 100}]Navegador → Frontend Server → Backend API → Base de Datos
↓ ↓ ↓ ↓
HTML EJS Template JSON Datos
↑ ↑ ↑ ↑
Navegador ← Frontend Server ← Backend API ← Base de Datos# Crear estructura
mkdir frontend
cd frontend
mkdir routes views public
mkdir views/productos public/css public/js# En la carpeta frontend
npm init -y
npm install express ejs axios
npm install --save-dev nodemon# En la carpeta backend
# Verificar que existe el endpoint: GET /api/productos
curl http://localhost:3000/api/productos// Configuración del servidor Express
// Motor de plantillas EJS
// Rutas y middleware
// Manejo de errores// Consumo de API con Axios
// Manejo de errores de conexión
// Renderizado de vistas EJS<!-- Tabla responsive con Bootstrap -->
<!-- Manejo de estados (con/sin productos) -->
<!-- Botones de acción preparados -->/* Diseño moderno con animaciones */
/* Responsive design */
/* Efectos hover y transiciones */// Axios - Manejo automático de JSON
const response = await axios.get('/api/productos');
const productos = response.data; // Ya es objeto JS
// Fetch - Manejo manual
const response = await fetch('/api/productos');
const productos = await response.json(); // Conversión manual// Configuración reutilizable
const apiClient = axios.create({
baseURL: 'http://localhost:3000/api',
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
});
// Uso simple
const productos = await apiClient.get('/productos');Usuario accede a: http://localhost:3001/productos// frontend/routes/productos.js
router.get('/', async (req, res) => {
try {
// Paso 3: Petición al backend
const response = await axios.get('http://localhost:3000/api/productos');
// Paso 4: Procesamiento
const productos = response.data;
// Paso 5: Renderizado
res.render('productos/lista', { productos });
} catch (error) {
// Manejo de errores
res.render('error', { error: error.message });
}
});// backend/routes/productos.js
router.get('/api/productos', (req, res) => {
// Lógica de base de datos
res.json([
{ id: 1, nombre: "Producto 1", precio: 100, unidades: 10 }
]);
});<!-- frontend/views/productos/lista.ejs -->
<% productos.forEach(producto => { %>
<tr>
<td><%= producto.nombre %></td>
<td>$<%= producto.precio %></td>
<td><%= producto.unidades %></td>
</tr>
<% }) %>try {
const response = await axios.get('/api/productos');
} catch (error) {
if (error.code === 'ECONNREFUSED') {
// Backend no está corriendo
res.render('error', {
error: 'Backend no disponible',
message: 'Verifica que el servidor backend esté corriendo'
});
}
}try {
const response = await axios.get('/api/productos');
} catch (error) {
if (error.response?.status === 404) {
// Endpoint no encontrado
} else if (error.response?.status === 500) {
// Error interno del servidor
}
}frontend/views/productos/nuevo.ejsfrontend/routes/productos.jsPOST /api/productosfrontend/views/productos/detalle.ejs/:idGET /api/productos/:idfrontend/views/productos/editar.ejsPUT /api/productos/:idDELETE /api/productos/:id// Cliente (JavaScript)
function validarFormulario() {
// Validaciones del lado del cliente
}
// Servidor (Frontend)
const { body, validationResult } = require('express-validator');
// Validaciones del lado del servidor// Sistema de mensajes flash
app.use(session());
app.use(flash());
// Mostrar mensajes de éxito/error
req.flash('success', 'Producto creado exitosamente');// Frontend
const page = req.query.page || 1;
const response = await axios.get(`/api/productos?page=${page}`);
// Backend
const productos = await Producto.find()
.limit(10)
.skip((page - 1) * 10);# Iniciar backend
cd backend && npm start
# Iniciar frontend (en otra terminal)
cd frontend && npm run dev
# Instalar dependencias
npm install
# Verificar conexión
curl http://localhost:3000/api/productos
curl http://localhost:3001/productos# Logs detallados
DEBUG=express:* npm start
# Verificar puertos
netstat -an | grep 3000
netstat -an | grep 3001API_BASE_URL en frontend/routes/productos.jsDocumento actualizado: Primera implementación - Operación LISTAR productos