Skip to main content

Error response format

The DAF Backend API returns errors in a consistent JSON format with appropriate HTTP status codes:
{
  "errors": [
    "cli_nombre es requerido y máximo 120 caracteres",
    "cli_telefono es requerido y debe tener 10 dígitos numéricos"
  ]
}

HTTP status codes

The API uses standard HTTP status codes to indicate the type of error:
The request was invalid or cannot be processed due to client error.Common causes:
  • Missing required fields
  • Invalid data format
  • Validation errors
  • Invalid query parameters
Example:
src/controllers/pos.cliente.controller.js:15-18
const create = async (req, res) => {
    // 1. Validar datos de entrada
    const errors = validateClienteDTO(req.body);
    if (errors.length) return res.status(400).json({ errors });
Authentication failed or token is invalid/missing.Common causes:
  • Missing Authorization header
  • Invalid JWT token format
  • Expired JWT token
  • Invalid database credentials (POS)
  • Wrong JWT_SECRET
Examples:
src/middlewares/pos.auth.middleware.js:7-11
if (!authHeader) {
  return res.status(401).json({
    message: 'Token no proporcionado',
  });
}
src/controllers/pos.auth.controller.js:48-51
} catch (error) {
  return res.status(401).json({
    message: 'Credenciales incorrectas o error de conexión',
    detail: error.message
  });
The requested resource does not exist.Common causes:
  • Invalid endpoint URL
  • Resource ID doesn’t exist in database
  • Deleted/inactive record
Examples:
src/controllers/pos.cliente.controller.js:72
if (!result) return res.status(404).json({ message: "Cliente no encontrado" });
src/controllers/ecom.carrito.controller.js:19-23
if (!carrito) {
  return res.status(404).json({
    message: "Carrito no encontrado",
  });
}
Global 404 handler for undefined routes:
src/app.js:80-82
app.use((req, res) => {
  res.status(404).json({ message: 'Not Found' });
});
An unexpected error occurred on the server.Common causes:
  • Database connection errors
  • Unhandled exceptions
  • Database query errors
  • File system errors
Examples:
src/controllers/pos.cliente.controller.js:32-34
} catch (error) {
    console.error("Error en createCliente:", error.message);
    res.status(500).json({ message: "Error interno al crear cliente", detail: error.message });
}
src/controllers/ecom.carrito.controller.js:32-36
} catch (err) {
  console.log(err);
  res.status(500).json({
    message: "Error al añadir el producto al carrito",
  });
}

Validation errors

Validation errors occur when request data doesn’t meet the API’s requirements. The API uses two validation approaches:

Custom validation functions

Custom DTOs return arrays of error messages:
src/dtos/cliente.dto.js:3-43
const validateClienteDTO = (data, isUpdate = false) => {
  const errors = [];
  const validStatuses = ['ACT', 'INA', 'SUS'];

  // Validación de Ciudad (FK)
  if (!isUpdate || data.ct_codigo !== undefined) {
    if (!data.ct_codigo || data.ct_codigo.length > 10) {
      errors.push('ct_codigo es requerido y máximo 10 caracteres');
    }
  }

  // Nombre
  if (!isUpdate || data.cli_nombre !== undefined) {
    if (!data.cli_nombre || data.cli_nombre.length > 120) {
      errors.push('cli_nombre es requerido y máximo 120 caracteres');
    }
  }

  // RUC / Cédula (13 dígitos)
  if (!isUpdate || data.cli_ruc_ced !== undefined) {
    if (!data.cli_ruc_ced || !/^\d/.test(data.cli_ruc_ced)) {
      errors.push('cli_ruc_ced es requerido y debe ser numérico');
    }
  }

  // Teléfono (10 dígitos)
  if (!isUpdate || data.cli_telefono !== undefined) {
    if (!data.cli_telefono || !/^\d{10}$/.test(data.cli_telefono)) {
      errors.push('cli_telefono es requerido y debe tener 10 dígitos numéricos');
    }
  }

  // Email
  if (!isUpdate || data.cli_mail !== undefined) {
    if (!data.cli_mail || data.cli_mail.length > 60) {
      errors.push('cli_mail es requerido y máximo 60 caracteres');
    }
  }

  return errors;
};
Response format (400):
{
  "errors": [
    "cli_nombre es requerido y máximo 120 caracteres",
    "cli_telefono es requerido y debe tener 10 dígitos numéricos",
    "cli_mail es requerido y máximo 60 caracteres"
  ]
}

Authentication errors

Authentication errors occur when JWT tokens are invalid, missing, or expired:
Status: 401 UnauthorizedCause: The Authorization header is missing from the request.Response:
{
  "message": "Token no proporcionado"
}
Source:
src/middlewares/pos.auth.middleware.js:7-11
if (!authHeader) {
  return res.status(401).json({
    message: 'Token no proporcionado',
  });
}
Solution: Include the Authorization header with Bearer token:
curl -H "Authorization: Bearer YOUR_TOKEN_HERE" http://localhost:3000/api/pos/cliente
Status: 401 UnauthorizedCause: The token format is incorrect (missing Bearer prefix or malformed).Response:
{
  "message": "Token inválido"
}
Source:
src/middlewares/pos.auth.middleware.js:15-19
if (!token) {
  return res.status(401).json({
    message: 'Token inválido',
  });
}
Solution: Ensure token is in format Bearer <token> with space after Bearer.
Status: 401 UnauthorizedCause: The JWT signature is invalid, JWT_SECRET is wrong, or token has expired.Response:
{
  "message": "Token inválido o expirado"
}
Source:
src/middlewares/pos.auth.middleware.js:28-32
} catch (error) {
  return res.status(401).json({
    message: 'Token inválido o expirado',
  });
}
Solutions:
  • Token may have expired (default 24h) - login again
  • Verify JWT_SECRET in .env hasn’t changed
  • Check token wasn’t corrupted during transmission
Status: 401 UnauthorizedCause: For POS login - database credentials are incorrect or database is unreachable.Response:
{
  "message": "Credenciales incorrectas o error de conexión",
  "detail": "password authentication failed for user \"pos_user\""
}
Source:
src/controllers/pos.auth.controller.js:48-51
} catch (error) {
  return res.status(401).json({
    message: 'Credenciales incorrectas o error de conexión',
    detail: error.message
  });
}
Solutions:
  • Verify PostgreSQL user exists and password is correct
  • Check database is running and accessible
  • Ensure user has CONNECT privilege on database

Database errors

Database errors typically result in 500 status codes:

Database connection failures

Common errors:
  • ECONNREFUSED - PostgreSQL not running or wrong port
  • Connection terminated unexpectedly - Database crashed
  • password authentication failed - Wrong credentials
  • database does not exist - Database name incorrect
Example response (500):
{
  "message": "Error al buscar cliente"
}
Controller handling:
src/controllers/pos.cliente.controller.js:75-80
} catch (error) {
    console.error("Error en getClienteByID:", error.message);
    res.status(500).json({ message: "Error al buscar cliente" });
} finally {
    await pool.end();
}
Debugging:
  • Check server logs for detailed error messages
  • Verify database connection settings in .env
  • Test database connectivity: psql -h localhost -p 5432 -U user -d database

File upload errors

File upload errors occur when handling product images:
Status: 500 Internal Server ErrorCause: Uploaded file is not an image type.Response:
{
  "message": "Solo se permiten imágenes"
}
Source:
src/middlewares/upload.js:22-27
const fileFilter = (req, file, cb) => {
  if (!file.mimetype.startsWith('image/')) {
    cb(new Error('Solo se permiten imágenes'), false);
  }
  cb(null, true);
};
Solution: Only upload image files (JPEG, PNG, GIF, WebP, etc.)
Status: 500 Internal Server ErrorCause: Uploaded file exceeds 5MB limit.Configuration:
src/middlewares/upload.js:29-33
const upload = multer({
  storage,
  fileFilter,
  limits: { fileSize: 5 * 1024 * 1024 }  // 5MB limit
});
Solution: Compress or resize images before uploading.
Status: 500 Internal Server ErrorCause: The src/images directory doesn’t exist or lacks write permissions.Prevention: Upload middleware creates directory if missing:
src/middlewares/upload.js:5-9
const imagesDir = path.join(__dirname, '../images');

if (!fs.existsSync(imagesDir)) {
  fs.mkdirSync(imagesDir);
}
Solution: Ensure the Node.js process has write permissions:
chmod 755 src/images

Common client-side errors

Missing required parameters

Example:
src/controllers/pos.producto.controller.js:111-113
if (req.query.name === undefined) {
  return res.status(400).json({ message: 'El parámetro name es requerido' });
}
Always check API documentation for required parameters.

Invalid ID format

Example:
src/controllers/pos.producto.controller.js:143-145
if (req.params.id === undefined) {
  return res.status(400).json({ message: 'El parámetro id es requerido' });
}
Ensure IDs match expected format (usually VARCHAR(10)).

CORS errors

If frontend origin is not in allowed list:
src/app.js:29-35
let corsConfiguration = {
  origin: process.env.FRONTEND_IP ? [process.env.FRONTEND_IP] : ['http://localhost:5173', 'http://localhost:5174'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}
Add your frontend URL to FRONTEND_IP in .env.

Pagination errors

Invalid page numbers default to 1:
src/controllers/pos.cliente.controller.js:47
const page = parseInt(req.query.page) || 1;
Use positive integers for page numbers.

Error handling best practices

1

Always validate input

Validate request data before processing:
const errors = validateClienteDTO(req.body);
if (errors.length) return res.status(400).json({ errors });
2

Use try-catch-finally

Wrap database operations in try-catch blocks:
try {
  const result = await model.query(pool, data);
  res.json(result);
} catch (error) {
  res.status(500).json({ message: error.message });
} finally {
  await pool.end(); // For POS endpoints only
}
3

Return appropriate status codes

Use the correct HTTP status code:
  • 400 for validation errors
  • 401 for authentication errors
  • 404 for not found
  • 500 for server errors
4

Log errors for debugging

Always log errors to console:
console.error("Error en createCliente:", error.message);
5

Provide helpful error messages

Include enough detail for clients to fix issues:
res.status(400).json({ 
  message: "Error interno al crear cliente", 
  detail: error.message 
});

Debugging tips

The API logs errors to console. Run the server and watch for error output:
npm run dev
Look for:
  • console.error() messages from controllers
  • Database connection errors
  • Middleware errors
Verify database connections separately:
# Test POS database
psql -h localhost -p 5432 -U pos_user -d daf_pos_db -c "SELECT 1;"

# Test E-commerce database
psql -h $EC_HOST -p $EC_PORT -U $EC_USER -d $EC_NAME -c "SELECT 1;"
Debug JWT tokens at jwt.io:
  1. Copy your token
  2. Paste into jwt.io debugger
  3. Verify payload and expiration
  4. Check signature with your JWT_SECRET
Isolate issues by testing with cURL:
# Test login
curl -X POST http://localhost:3000/api/pos/auth/login \
  -H "Content-Type: application/json" \
  -d '{"user":"pos_user","password":"pass"}' \
  -v

# Test authenticated endpoint
curl http://localhost:3000/api/pos/cliente \
  -H "Authorization: Bearer TOKEN_HERE" \
  -v
The -v flag shows full request/response details.
Verify .env is loaded correctly:Add temporary debug output:
console.log('POS_HOST:', process.env.POS_HOST);
console.log('EC_USER:', process.env.EC_USER);
console.log('JWT_SECRET:', process.env.JWT_SECRET ? 'SET' : 'NOT SET');
Remove after debugging.

Next steps

POS API Reference

See all endpoints with request/response examples

Authentication

Understand authentication error scenarios

Database

Learn about database connection errors

Architecture

Understand the error handling flow

Build docs developers (and LLMs) love