Skip to main content

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

Ensure you have completed the database setup before proceeding.
  • 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:
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

1

Navigate to Backend Directory

cd ~/workspace/source/bakend
2

Install Dependencies

Install required npm packages:
npm install
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
3

Configure Database Connection

The db.js file manages the MySQL connection pool. Review and update as needed:
bakend/db.js
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.
4

Verify Server Configuration

Check server.js for proper configuration:
bakend/server.js
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:
ParameterValueDescription
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:
bakend/server.js
const PORT = process.env.PORT || 4000;

CORS Configuration

CORS is enabled for all origins in development:
app.use(cors());
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:
npm run dev
Or directly with Node:
node server.js

Production Mode

npm start
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:
.env
# 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:
npm install dotenv
Update db.js:
bakend/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:
bakend/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:
bakend/package.json
{
  "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

  1. Import the API collection
  2. Set base URL: http://localhost:4000
  3. 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:
bakend/server.js
// 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

Input Validation

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 <PID>

# 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:
{
  "type": "module"
}

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:
npm install -g pm2
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

Performance Optimization

Enable Compression

npm install 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:
  1. Configure the PHP backend if needed
  2. Set up environment variables
  3. Test the complete API with your frontend application
  4. Set up monitoring and logging for production

Build docs developers (and LLMs) love