Skip to main content

Overview

The OdontologyApp API uses standard HTTP status codes to indicate the success or failure of requests. All error responses include a JSON body with error details.

Standard Error Response Format

Most errors follow this structure:
{
  "message": "Human-readable error description",
  "code": "ERROR_CODE"
}
message
string
required
A human-readable error message, typically in Spanish
code
string
An optional error code for programmatic handling (e.g., “FORBIDDEN”)

Validation Errors

Validation errors (using Zod schema validation) include an errors array:
{
  "message": "Error de validación (Zod)",
  "errors": [
    {
      "field": "email",
      "message": "Invalid email format"
    },
    {
      "field": "cedula",
      "message": "Required field"
    }
  ]
}
errors
array
Array of validation error objects
field
string
The name of the field that failed validation
message
string
Description of the validation failure

HTTP Status Codes

The API uses the following HTTP status codes:

Success Codes (2xx)

200 OK
status
Meaning: Request succeededUsed for: Successful GET, POST, PUT, PATCH, DELETE operationsExample:
{
  "success": true,
  "patients": [...]
}

Client Error Codes (4xx)

400 Bad Request
status
Meaning: Invalid request dataCommon causes:
  • Missing required fields
  • Invalid data format
  • Validation errors
  • Duplicate entries (email, cedula)
Examples:
// Missing credentials
{
  "message": "Falta usuario o contraseña"
}
// Validation error
{
  "message": "Error de validación (Zod)",
  "errors": [...]
}
// Duplicate entry
{
  "message": "El email o cédula ya está registrado"
}
// Missing required parameter
{
  "message": "ID requerido"
}
401 Unauthorized
status
Meaning: Authentication required or failedCommon causes:
  • No session cookie present
  • Session expired
  • Invalid credentials
  • User not found
Examples:
// Not logged in
{
  "message": "No autorizado"
}
// Invalid username
{
  "message": "Usuario no encontrado"
}
// Wrong password
{
  "message": "Contraseña incorrecta"
}
Solution: Log in via /api/auth/login to obtain a valid session
403 Forbidden
status
Meaning: Authenticated but lacking required permissionsCommon causes:
  • User role doesn’t have permission for this action
  • Attempting to access admin-only endpoints
Example:
{
  "message": "No tienes permiso para realizar esta acción.",
  "code": "FORBIDDEN"
}
Solution: Contact an administrator to request the necessary permissions
404 Not Found
status
Meaning: Resource not foundCommon causes:
  • Invalid endpoint URL
  • Resource ID doesn’t exist
Example:
{
  "message": "Recurso no encontrado"
}

Server Error Codes (5xx)

500 Internal Server Error
status
Meaning: Unexpected server errorCommon causes:
  • Database connection failure
  • Unhandled exceptions
  • Stored procedure errors
Examples:
// Generic server error
{
  "message": "Error al cargar pacientes"
}
// Login error with details
{
  "message": "Error del servidor: Connection refused"
}
// Dashboard stats error
{
  "message": "Error al obtener estadísticas"
}
Action: Check server logs for detailed error information. The error is logged to the console.

Common Error Scenarios

Authentication Errors

Endpoint: POST /api/auth/loginTrigger: Username or password not provided
{
  "message": "Falta usuario o contraseña"
}
Solution: Include both username and password in request body
Endpoint: POST /api/auth/loginTrigger: Username doesn’t exist in database
{
  "message": "Usuario no encontrado"
}
Solution: Verify the username is correct
Endpoint: POST /api/auth/loginTrigger: Password doesn’t match stored bcrypt hash
{
  "message": "Contraseña incorrecta"
}
Solution: Verify the password is correct
Endpoint: Most API endpointsTrigger: No valid session cookie present
{
  "message": "No autorizado"
}
Solution: Log in first to obtain a session cookie

Permission Errors

Endpoint: Any protected endpointTrigger: User lacks required permission (e.g., VIEW_PATIENTS, CREATE_PATIENTS)
{
  "message": "No tienes permiso para realizar esta acción.",
  "code": "FORBIDDEN"
}
Solution: Request permission from administrator or use an admin account

Validation Errors

Endpoint: POST /api/patients, and others using schema validationTrigger: Request data doesn’t match Zod schema requirements
{
  "message": "Error de validación (Zod)",
  "errors": [
    {
      "field": "first_name",
      "message": "Required"
    },
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ]
}
Solution: Fix the specified fields according to the schema requirements
Endpoint: POST /api/patientsTrigger: Email or cedula already exists in database (MySQL ER_DUP_ENTRY error)
{
  "message": "El email o cédula ya está registrado"
}
Solution: Use a different email/cedula or update the existing patient
Endpoint: Various endpointsTrigger: Required field or query parameter missing
{
  "message": "ID requerido"
}
{
  "message": "Faltan datos"
}
Solution: Include all required fields in the request

Database Errors

Endpoint: Various endpointsTrigger: MySQL stored procedure throws error with SQLSTATE 45000
{
  "message": "[Custom error message from stored procedure]"
}
Example: A stored procedure might reject invalid data with a custom messageSolution: Follow the error message guidance or check data validity
Endpoint: Any endpoint with database operationsTrigger: Database query fails unexpectedly
{
  "message": "Error al cargar pacientes"
}
{
  "message": "Error al crear paciente"
}
Solution: Check server logs for detailed error. Verify database connection and stored procedures.

Error Logging

Console Logging

All errors are logged to the console with context:
console.error("Fetch Patients Error:", error);
console.error("Create Patient Error:", error);
console.error("Dashboard Stats API Error:", error);

Login Logging

Successful logins are logged to the database via sp_create_log. If login logging fails, it’s caught silently:
try {
  const ip = request.headers.get("x-forwarded-for") || "127.0.0.1";
  await pool.query('CALL sp_create_log(?, ?, ?, ?, ?)', [
    user.id,
    'Login',
    'Auth',
    `El usuario ${user.username} ha iniciado sesión`,
    ip
  ]);
} catch (logError) {
  console.error("Failed to write login log:", logError);
}

Global Error Handler

The application has a global error handler in hooks.server.js:
export function handleError({ error, event }) {
  console.error('🚨 Error Crítico en el Servidor:', error);

  return {
    message: 'Lo sentimos, ha ocurrido un error inesperado. Por favor, intente más tarde.',
    error: error instanceof Error ? error.message : 'Internal Server Error',
    status: 500
  };
}
This catches unhandled errors and returns a generic error response to the client.

Best Practices for Error Handling

1. Check Status Codes

Always check the HTTP status code before parsing the response:
const response = await fetch('/api/patients');

if (!response.ok) {
  const error = await response.json();
  console.error(`Error ${response.status}:`, error.message);
  return;
}

const data = await response.json();

2. Handle Different Error Types

try {
  const response = await fetch('/api/patients', { method: 'POST', ... });
  const data = await response.json();

  switch (response.status) {
    case 200:
      console.log('Success:', data);
      break;
    case 400:
      if (data.errors) {
        // Handle validation errors
        data.errors.forEach(err => {
          console.error(`${err.field}: ${err.message}`);
        });
      } else {
        console.error('Bad request:', data.message);
      }
      break;
    case 401:
      // Redirect to login
      window.location.href = '/login';
      break;
    case 403:
      alert('No tienes permiso para esta acción');
      break;
    case 500:
      console.error('Server error:', data.message);
      break;
  }
} catch (err) {
  console.error('Network error:', err);
}

3. Graceful Degradation

Some endpoints return partial data even on error:
// Dashboard stats - returns empty data structure if not authenticated
const response = await fetch('/api/dashboard/stats');
const data = await response.json();

if (!data.authenticated) {
  // User not logged in, but request didn't fail
  console.log('Not authenticated');
}

4. Retry Logic for Server Errors

For 5xx errors, implement retry logic:
async function fetchWithRetry(url, options, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status < 500) {
        return response; // Don't retry client errors
      }
      
      if (i === retries - 1) {
        return response; // Last attempt
      }
      
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    } catch (err) {
      if (i === retries - 1) throw err;
    }
  }
}

Debugging Tips

1

Check Server Console

All API errors are logged to the server console with context. Check the terminal running the dev server.
2

Inspect Network Tab

Use browser DevTools Network tab to see the exact request/response, including headers and cookies.
3

Verify Session Cookie

Check that the session cookie is being sent with requests. It should appear in the Cookie header.
4

Test with cURL

Isolate issues by testing endpoints directly with cURL:
curl -v http://localhost:5173/api/patients \
  -H "Cookie: session=..." 
5

Check Database Logs

If you’re getting 500 errors, check MySQL logs for stored procedure failures.

Error Response Reference

400 Bad Request

  • Missing required fields
  • Validation errors
  • Duplicate entries
  • Invalid data format

401 Unauthorized

  • No session cookie
  • Session expired
  • Invalid credentials
  • User not found

403 Forbidden

  • Insufficient permissions
  • Role-based access denied
  • Admin-only endpoint

500 Server Error

  • Database connection failed
  • Stored procedure error
  • Unhandled exception
  • System error

Next Steps

API Overview

Return to the API overview for endpoint documentation

Build docs developers (and LLMs) love