refactor(backend): standardize error responses, logging, pagination
- errorResponse(res, error, status, publicMessage) in routeHelpers,
wired into 125 catch blocks across 10 route files; wire format
({ error: <string> }) unchanged byte-for-byte
- Replace remaining console.* with logger across src (178 sites);
3 intentional console sites kept (install boot, unbound .catch ref)
- Adopt getPagination in 6 routes where semantics match exactly
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
const { db } = require('../database/db');
|
||||
const logger = require('./logger');
|
||||
|
||||
// Default date format settings
|
||||
const DEFAULT_FORMAT = {
|
||||
@@ -19,7 +20,7 @@ async function formatDate(date, language = 'en') {
|
||||
try {
|
||||
dateConfig = JSON.parse(setting.setting_value);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse date format setting:', e.message);
|
||||
logger.warn('Failed to parse date format setting:', e.message);
|
||||
dateConfig = DEFAULT_FORMAT;
|
||||
}
|
||||
} else {
|
||||
@@ -46,7 +47,7 @@ async function formatDate(date, language = 'en') {
|
||||
|
||||
// Check if date is valid
|
||||
if (isNaN(dateObj.getTime())) {
|
||||
console.error('Invalid date provided to formatDate:', date);
|
||||
logger.error('Invalid date provided to formatDate:', date);
|
||||
throw new Error('Invalid date');
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ async function formatDate(date, language = 'en') {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error formatting date:', error);
|
||||
logger.error('Error formatting date:', error);
|
||||
// Fallback to basic formatting
|
||||
return date instanceof Date ? date.toLocaleDateString() : new Date(date).toLocaleDateString();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
// Note: Requiring db here creates circular dependency
|
||||
// db should be passed as parameter or required where needed
|
||||
const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Get database client type
|
||||
@@ -91,7 +92,7 @@ async function getDatabaseSize(db, dbName) {
|
||||
const stats = await fs.stat(dbPath);
|
||||
return stats.size;
|
||||
} catch (error) {
|
||||
console.error('Error getting SQLite database size:', error);
|
||||
logger.error('Error getting SQLite database size:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Secure file security utilities to prevent path traversal and validate file types
|
||||
@@ -174,7 +175,7 @@ async function validateFileContent(filePath, expectedMimeType) {
|
||||
return true;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error validating file content:', error);
|
||||
logger.error('Error validating file content:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -239,7 +240,7 @@ function createFileUploadValidator(options = {}) {
|
||||
try {
|
||||
await fs.unlink(file.path);
|
||||
} catch (err) {
|
||||
console.error('Error removing invalid file:', err);
|
||||
logger.error('Error removing invalid file:', err);
|
||||
}
|
||||
return res.status(400).json({
|
||||
error: `File content does not match declared type: ${file.originalname}`
|
||||
@@ -250,7 +251,7 @@ function createFileUploadValidator(options = {}) {
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('File validation error:', error);
|
||||
logger.error('File validation error:', error);
|
||||
res.status(500).json({ error: 'File validation failed' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
const { validationResult } = require('express-validator');
|
||||
const { ValidationError } = require('./errors');
|
||||
const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Wraps an async route handler to catch errors and pass them to the error handler.
|
||||
@@ -69,25 +70,26 @@ const successResponse = (res, data, statusCode = 200, message = null) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a standardized error response.
|
||||
* Note: Prefer throwing custom errors and letting the error handler format the response.
|
||||
* Logs an error and sends a standardized error response of shape `{ error: <string> }`.
|
||||
*
|
||||
* @param {Response} res - Express response object
|
||||
* @param {string} message - Error message
|
||||
* @param {Error|*} error - The caught error (logged, never sent to the client)
|
||||
* @param {number} [statusCode=500] - HTTP status code
|
||||
* @param {string} [code] - Optional error code
|
||||
* @param {*} [details] - Optional additional error details
|
||||
* @param {string} [publicMessage] - Message sent to the client; falls back to the error's message
|
||||
*
|
||||
* @example
|
||||
* errorResponse(res, 'Invalid input', 400, 'VALIDATION_ERROR', { field: 'email' });
|
||||
* } catch (error) {
|
||||
* errorResponse(res, error, 500, 'Failed to fetch events');
|
||||
* }
|
||||
*/
|
||||
const errorResponse = (res, message, statusCode = 500, code = null, details = null) => {
|
||||
const response = {
|
||||
error: message,
|
||||
...(code && { code }),
|
||||
...(details && { details })
|
||||
};
|
||||
res.status(statusCode).json(response);
|
||||
const errorResponse = (res, error, statusCode = 500, publicMessage) => {
|
||||
const message = publicMessage || (error instanceof Error ? error.message : String(error));
|
||||
const route = res.req ? `${res.req.method} ${res.req.originalUrl}` : null;
|
||||
logger.error(route ? `${route} - ${message}` : message, {
|
||||
error: error instanceof Error ? error.message : error,
|
||||
stack: error instanceof Error ? error.stack : undefined
|
||||
});
|
||||
res.status(statusCode).json({ error: message });
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user