Overview
The Node.js backend provides the modern API layer for Mis Compras, built with Express.js and MySQL2. It handles product management, order processing, and user operations through RESTful API endpoints.
Prerequisites
Node.js 16.x or higher
npm or yarn package manager
MySQL 8.4.3+ running and accessible
Basic knowledge of Express.js and REST APIs
Checking Node.js Installation
Verify your Node.js and npm versions:
node --version # Should be v16.x or higher
npm --version # Should be 8.x or higher
If Node.js is not installed:
Ubuntu/Debian
macOS (Homebrew)
Windows
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
Project Structure
The Node.js backend is located in the bakend/ directory with the following structure:
bakend/
├── server.js # Main application entry point
├── db.js # Database connection configuration
├── package.json # Dependencies and scripts
├── routes/
│ ├── productos.js # Product API endpoints
│ ├── pedidos.js # Order API endpoints
│ └── usuarios.js # User API endpoints
└── node_modules/ # Installed dependencies
Installation
Navigate to Backend Directory
cd ~/workspace/source/bakend
Install Dependencies
Install required npm packages: The package.json file should include these core dependencies:
express - Web framework
cors - Cross-origin resource sharing
body-parser - Request body parsing
mysql2 - MySQL client with promise support
If package.json is incomplete, install dependencies manually: npm install express cors body-parser mysql2
For development, also install: npm install --save-dev nodemon
Configure Database Connection
The db.js file manages the MySQL connection pool. Review and update as needed: import mysql from "mysql2/promise" ;
export const db = await mysql . createPool ({
host: "localhost" ,
user: "root" ,
password: "" ,
database: "tienda_online" ,
waitForConnections: true ,
connectionLimit: 10 ,
queueLimit: 0 ,
});
The default configuration uses an empty password, which is insecure. Update credentials before deploying to production.
Verify Server Configuration
Check server.js for proper configuration: import express from "express" ;
import cors from "cors" ;
import bodyParser from "body-parser" ;
import productosRoutes from "./routes/productos.js" ;
import pedidosRoutes from "./routes/pedidos.js" ;
import usuariosRoutes from "./routes/usuarios.js" ;
const app = express ();
const PORT = 4000 ;
app . use ( cors ());
app . use ( bodyParser . json ());
// API Routes
app . use ( "/api/productos" , productosRoutes );
app . use ( "/api/pedidos" , pedidosRoutes );
app . use ( "/api/usuarios" , usuariosRoutes );
app . get ( "/" , ( req , res ) => {
res . send ( "Servidor de Tienda Online funcionando ✅" );
});
app . listen ( PORT , () => {
console . log ( `🚀 Servidor escuchando en http://localhost: ${ PORT } ` );
});
Configuration
Database Connection Pool
The mysql2/promise connection pool provides:
Parameter Value Description hostlocalhostMySQL server hostname userrootDatabase username password""Database password (empty by default) databasetienda_onlineTarget database name waitForConnectionstrueQueue requests when pool is full connectionLimit10Maximum concurrent connections queueLimit0Unlimited queue size
Connection Pool Benefits
Performance : Reuses connections instead of creating new ones
Scalability : Limits concurrent database connections
Reliability : Automatic connection recovery
Promise Support : Modern async/await syntax
Example usage in routes:
import { db } from "../db.js" ;
// Query with async/await
async function getProducts () {
try {
const [ rows ] = await db . query ( "SELECT * FROM productos" );
return rows ;
} catch ( error ) {
console . error ( "Database error:" , error );
throw error ;
}
}
Server Configuration
The Express server runs on port 4000 by default. To change:
const PORT = process . env . PORT || 4000 ;
CORS Configuration
CORS is enabled for all origins in development:
For production, restrict to specific domains:
import cors from "cors" ;
const corsOptions = {
origin: 'https://yourdomain.com' ,
credentials: true ,
optionsSuccessStatus: 200
};
app . use ( cors ( corsOptions ));
Running the Backend
Development Mode
Using nodemon for automatic restarts:
Or directly with Node:
Production Mode
Expected output:
🚀 Servidor escuchando en http://localhost:4000
Verifying the Server
Test the health endpoint:
curl http://localhost:4000
Expected response:
Servidor de Tienda Online funcionando ✅
API Routes
The backend exposes three main API route groups:
Products API (/api/productos)
Handles product catalog operations:
GET / api / productos # List all products
GET / api / productos / : id # Get single product
POST / api / productos # Create new product
PUT / api / productos / : id # Update product
DELETE / api / productos / : id # Delete product
Example request:
curl http://localhost:4000/api/productos
Orders API (/api/pedidos)
Manages order processing:
GET / api / pedidos # List all orders
GET / api / pedidos / : id # Get single order
POST / api / pedidos # Create new order
PUT / api / pedidos / : id # Update order status
DELETE / api / pedidos / : id # Cancel order
Users API (/api/usuarios)
Handles user management:
GET / api / usuarios # List all users
GET / api / usuarios / : id # Get single user
POST / api / usuarios # Register new user
PUT / api / usuarios / : id # Update user profile
DELETE / api / usuarios / : id # Delete user account
Environment Variables
Creating .env File
For better configuration management, create a .env file:
# Database Configuration
DB_HOST = localhost
DB_USER = root
DB_PASSWORD =
DB_NAME = tienda_online
DB_CONNECTION_LIMIT = 10
# Server Configuration
PORT = 4000
NODE_ENV = development
# CORS
CORS_ORIGIN = http://localhost:3000
# Security
JWT_SECRET = your-secret-key-here
SESSION_SECRET = your-session-secret
Using Environment Variables
Install dotenv:
Update db.js:
import mysql from "mysql2/promise" ;
import dotenv from "dotenv" ;
dotenv . config ();
export const db = await mysql . createPool ({
host: process . env . DB_HOST || "localhost" ,
user: process . env . DB_USER || "root" ,
password: process . env . DB_PASSWORD || "" ,
database: process . env . DB_NAME || "tienda_online" ,
waitForConnections: true ,
connectionLimit: parseInt ( process . env . DB_CONNECTION_LIMIT ) || 10 ,
queueLimit: 0 ,
});
Update server.js:
import dotenv from "dotenv" ;
dotenv . config ();
const PORT = process . env . PORT || 4000 ;
const NODE_ENV = process . env . NODE_ENV || "development" ;
Package.json Configuration
Complete package.json example:
{
"name" : "tienda-backend" ,
"version" : "1.0.0" ,
"type" : "module" ,
"description" : "Backend API for Mis Compras marketplace" ,
"main" : "server.js" ,
"scripts" : {
"start" : "node server.js" ,
"dev" : "nodemon server.js" ,
"test" : "echo \" Error: no test specified \" && exit 1"
},
"keywords" : [ "ecommerce" , "marketplace" , "api" ],
"author" : "Your Name" ,
"license" : "ISC" ,
"dependencies" : {
"express" : "^4.18.2" ,
"cors" : "^2.8.5" ,
"body-parser" : "^1.20.2" ,
"mysql2" : "^3.6.5" ,
"dotenv" : "^16.3.1"
},
"devDependencies" : {
"nodemon" : "^3.0.2"
}
}
The "type": "module" field enables ES6 module syntax (import/export) instead of CommonJS (require).
Testing the API
Using cURL
Test each endpoint:
# Health check
curl http://localhost:4000
# Get all products
curl http://localhost:4000/api/productos
# Get single product
curl http://localhost:4000/api/productos/1
# Create new product (POST)
curl -X POST http://localhost:4000/api/productos \
-H "Content-Type: application/json" \
-d '{
"nombre": "Test Product",
"descripcion": "Test description",
"precio": 99.99,
"id_categoria": 2
}'
Using Postman
Import the API collection
Set base URL: http://localhost:4000
Test each endpoint with sample data
Using httpie
# Install httpie
pip install httpie
# Test endpoints
http GET localhost:4000/api/productos
http POST localhost:4000/api/productos nombre="New Product" precio:= 199.99
Error Handling
Implement centralized error handling:
// Error handling middleware
app . use (( err , req , res , next ) => {
console . error ( err . stack );
const statusCode = err . statusCode || 500 ;
const message = err . message || "Internal Server Error" ;
res . status ( statusCode ). json ({
success: false ,
error: message ,
... ( process . env . NODE_ENV === "development" && { stack: err . stack })
});
});
Security Best Practices
Use express-validator for request validation:
npm install express-validator
import { body , validationResult } from "express-validator" ;
app . post ( "/api/productos" ,
body ( "nombre" ). notEmpty (). trim (),
body ( "precio" ). isFloat ({ min: 0 }),
async ( req , res ) => {
const errors = validationResult ( req );
if ( ! errors . isEmpty ()) {
return res . status ( 400 ). json ({ errors: errors . array () });
}
// Process request
}
);
SQL Injection Prevention
Always use parameterized queries:
// WRONG - Vulnerable
const query = `SELECT * FROM productos WHERE id = ${ req . params . id } ` ;
// CORRECT - Safe
const [ rows ] = await db . query (
"SELECT * FROM productos WHERE id_producto = ?" ,
[ req . params . id ]
);
Rate Limiting
Install and configure rate limiting:
npm install express-rate-limit
import rateLimit from "express-rate-limit" ;
const limiter = rateLimit ({
windowMs: 15 * 60 * 1000 , // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app . use ( "/api/" , limiter );
Troubleshooting
Port Already in Use
# Find process using port 4000
lsof -i :4000
# Kill the process
kill -9 < PI D >
# Or use a different port
PORT = 4001 node server.js
Database Connection Errors
Error: “ER_ACCESS_DENIED_ERROR”
Verify database credentials in db.js
Check MySQL user privileges
Error: “ECONNREFUSED”
Ensure MySQL is running: sudo systemctl status mysql
Verify MySQL port (default: 3306)
Error: “Unknown database ‘tienda_online‘“
CREATE DATABASE tienda_online ;
Module Import Errors
Error: “Cannot use import statement outside a module”
Add to package.json:
CORS Errors
If frontend can’t access the API:
import cors from "cors" ;
app . use ( cors ({
origin: [ "http://localhost:3000" , "http://localhost:5173" ],
credentials: true
}));
Production Deployment
Using PM2
Install PM2 process manager:
Start the application:
pm2 start server.js --name tienda-backend
pm2 save
pm2 startup
Monitor the application:
pm2 status
pm2 logs tienda-backend
pm2 monit
Environment-Specific Configuration
Create separate environment files:
.env.development
.env.production
.env.staging
Load based on NODE_ENV:
import dotenv from "dotenv" ;
const envFile = `.env. ${ process . env . NODE_ENV || 'development' } ` ;
dotenv . config ({ path: envFile });
Docker Deployment
Create Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 4000
CMD [ "node" , "server.js" ]
Build and run:
docker build -t tienda-backend .
docker run -p 4000:4000 --env-file .env tienda-backend
Enable Compression
import compression from "compression" ;
app . use ( compression ());
Connection Pooling
Optimize pool size based on load:
export const db = await mysql . createPool ({
connectionLimit: process . env . NODE_ENV === "production" ? 20 : 10 ,
queueLimit: 0 ,
enableKeepAlive: true ,
keepAliveInitialDelay: 0
});
Next Steps
After setting up the Node.js backend:
Configure the PHP backend if needed
Set up environment variables
Test the complete API with your frontend application
Set up monitoring and logging for production