Merge pull request #1591 from bluewave-labs/feat/be/consistent-response-middleare

feat: be/consistent response middleare
This commit is contained in:
Alexander Holliday
2025-01-20 11:48:40 -08:00
committed by GitHub
13 changed files with 129 additions and 114 deletions

View File

@@ -115,8 +115,7 @@ class AuthController {
});
});
return res.status(200).json({
success: true,
res.success({
msg: successMessages.AUTH_CREATE_USER,
data: { user: newUser, token: token, refreshToken: refreshToken },
});
@@ -154,7 +153,9 @@ class AuthController {
// Compare password
const match = await user.comparePassword(password);
if (match !== true) {
next(new Error(errorMessages.AUTH_INCORRECT_PASSWORD));
const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD);
error.status = 401;
next(error);
return;
}
@@ -174,12 +175,16 @@ class AuthController {
// reset avatar image
userWithoutPassword.avatarImage = user.avatarImage;
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_LOGIN_USER,
data: { user: userWithoutPassword, token: token, refreshToken: refreshToken },
data: {
user: userWithoutPassword,
token: token,
refreshToken: refreshToken,
},
});
} catch (error) {
error.status = 401;
next(handleError(error, SERVICE_NAME, "loginUser"));
}
};
@@ -237,8 +242,7 @@ class AuthController {
appSettings
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_TOKEN_REFRESHED,
data: { user: payloadData, token: newAuthToken, refreshToken: refreshToken },
});
@@ -306,8 +310,7 @@ class AuthController {
}
const updatedUser = await this.db.updateUser(req, res);
return res.status(200).json({
success: true,
res.success({
msg: successMessages.AUTH_UPDATE_USER,
data: updatedUser,
});
@@ -328,8 +331,8 @@ class AuthController {
checkSuperadminExists = async (req, res, next) => {
try {
const superAdminExists = await this.db.checkSuperadmin(req, res);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_ADMIN_EXISTS,
data: superAdminExists,
});
@@ -375,8 +378,7 @@ class AuthController {
"Checkmate Password Reset"
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN,
data: msgId,
});
@@ -406,8 +408,8 @@ class AuthController {
try {
await this.db.validateRecoveryToken(req, res);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN,
});
} catch (error) {
@@ -439,8 +441,8 @@ class AuthController {
const user = await this.db.resetPassword(req, res);
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(user._doc, tokenType.ACCESS_TOKEN, appSettings);
res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_RESET_PASSWORD,
data: { user, token },
});
@@ -493,8 +495,8 @@ class AuthController {
}
// 6. Delete the user by id
await this.db.deleteUser(user._id);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.AUTH_DELETE_USER,
});
} catch (error) {
@@ -505,7 +507,11 @@ class AuthController {
getAllUsers = async (req, res, next) => {
try {
const allUsers = await this.db.getAllUsers(req, res);
res.status(200).json({ success: true, msg: "Got all users", data: allUsers });
return res.success({
msg: successMessages.AUTH_GET_ALL_USERS,
data: allUsers,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "getAllUsersController"));
}

View File

@@ -34,9 +34,11 @@ class CheckController {
try {
const checkData = { ...req.body };
const check = await this.db.createCheck(checkData);
return res
.status(200)
.json({ success: true, msg: successMessages.CHECK_CREATE, data: check });
return res.success({
msg: successMessages.CHECK_CREATE,
data: check,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "createCheck"));
}
@@ -54,8 +56,8 @@ class CheckController {
try {
const checks = await this.db.getChecks(req);
const checksCount = await this.db.getChecksCount(req);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.CHECK_GET,
data: { checksCount, checks },
});
@@ -74,8 +76,8 @@ class CheckController {
}
try {
const checkData = await this.db.getTeamChecks(req);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.CHECK_GET,
data: checkData,
});
@@ -94,8 +96,8 @@ class CheckController {
try {
const deletedCount = await this.db.deleteChecks(req.params.monitorId);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.CHECK_DELETE,
data: { deletedCount },
});
@@ -114,8 +116,8 @@ class CheckController {
try {
const deletedCount = await this.db.deleteChecksByTeamId(req.params.teamId);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.CHECK_DELETE,
data: { deletedCount },
});
@@ -141,8 +143,8 @@ class CheckController {
const { teamId } = jwt.verify(token, jwtSecret);
const ttl = parseInt(req.body.ttl, 10) * SECONDS_PER_DAY;
await this.db.updateChecksTTL(teamId, ttl);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.CHECK_UPDATE_TTL,
});
} catch (error) {

View File

@@ -13,18 +13,14 @@ const handleError = (error, serviceName, method, status = 500) => {
};
const fetchMonitorCertificate = async (sslChecker, monitor) => {
try {
const monitorUrl = new URL(monitor.url);
const hostname = monitorUrl.hostname;
const cert = await sslChecker(hostname);
// Throw an error if no cert or if cert.validTo is not present
if (cert?.validTo === null || cert?.validTo === undefined) {
throw new Error("Certificate not found");
}
return cert;
} catch (error) {
throw error;
const monitorUrl = new URL(monitor.url);
const hostname = monitorUrl.hostname;
const cert = await sslChecker(hostname);
// Throw an error if no cert or if cert.validTo is not present
if (cert?.validTo === null || cert?.validTo === undefined) {
throw new Error("Certificate not found");
}
return cert;
};
export { handleValidationError, handleError, fetchMonitorCertificate };

View File

@@ -7,7 +7,7 @@ import logger from "../utils/logger.js";
import jwt from "jsonwebtoken";
import { handleError, handleValidationError } from "./controllerUtils.js";
import { getTokenFromHeaders } from "../utils/utils.js";
import { successMessages } from "../utils/messages.js";
const SERVICE_NAME = "inviteController";
class InviteController {
@@ -65,9 +65,10 @@ class InviteController {
});
});
return res
.status(200)
.json({ success: true, msg: "Invite sent", data: inviteToken });
return res.success({
msg: successMessages.INVITE_ISSUED,
data: inviteToken,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "inviteController"));
}
@@ -83,7 +84,11 @@ class InviteController {
try {
const invite = await this.db.getInviteToken(req.body.token);
res.status(200).json({ status: "success", msg: "Invite verified", data: invite });
return res.success({
msg: successMessages.INVITE_VERIFIED,
data: invite,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "inviteVerifyController"));
}

View File

@@ -43,8 +43,8 @@ class MaintenanceWindowController {
});
});
await Promise.all(dbTransactions);
return res.status(201).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
});
} catch (error) {
@@ -61,8 +61,8 @@ class MaintenanceWindowController {
}
try {
const maintenanceWindow = await this.db.getMaintenanceWindowById(req.params.id);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
data: maintenanceWindow,
});
@@ -88,8 +88,7 @@ class MaintenanceWindowController {
req.query
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
data: maintenanceWindows,
});
@@ -111,8 +110,7 @@ class MaintenanceWindowController {
req.params.monitorId
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER,
data: maintenanceWindows,
});
@@ -130,8 +128,7 @@ class MaintenanceWindowController {
}
try {
await this.db.deleteMaintenanceWindowById(req.params.id);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_DELETE,
});
} catch (error) {
@@ -152,8 +149,7 @@ class MaintenanceWindowController {
req.params.id,
req.body
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
data: editedMaintenanceWindow,
});

View File

@@ -42,8 +42,7 @@ class MonitorController {
getAllMonitors = async (req, res, next) => {
try {
const monitors = await this.db.getAllMonitors();
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_GET_ALL,
data: monitors,
});
@@ -64,8 +63,7 @@ class MonitorController {
getAllMonitorsWithUptimeStats = async (req, res, next) => {
try {
const monitors = await this.db.getAllMonitorsWithUptimeStats();
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_GET_ALL,
data: monitors,
});
@@ -77,8 +75,7 @@ class MonitorController {
getUptimeDetailsById = async (req, res, next) => {
try {
const monitor = await this.db.getUptimeDetailsById(req);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_GET_BY_ID,
data: monitor,
});
@@ -107,8 +104,7 @@ class MonitorController {
try {
const monitorStats = await this.db.getMonitorStatsById(req);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_STATS_BY_ID,
data: monitorStats,
});
@@ -136,8 +132,7 @@ class MonitorController {
}
try {
const monitor = await this.db.getHardwareDetailsById(req);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_GET_BY_ID,
data: monitor,
});
@@ -158,8 +153,7 @@ class MonitorController {
const monitor = await this.db.getMonitorById(monitorId);
const certificate = await fetchMonitorCertificate(sslChecker, monitor);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_CERTIFICATE,
data: {
certificateDate: new Date(certificate.validTo),
@@ -192,8 +186,7 @@ class MonitorController {
try {
const monitor = await this.db.getMonitorById(req.params.monitorId);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_GET_BY_ID,
data: monitor,
});
@@ -237,8 +230,7 @@ class MonitorController {
await monitor.save();
// Add monitor to job queue
this.jobQueue.addJob(monitor._id, monitor);
return res.status(201).json({
success: true,
return res.success({
msg: successMessages.MONITOR_CREATE,
data: monitor,
});
@@ -272,11 +264,9 @@ class MonitorController {
timeout: 5000,
validateStatus: () => true,
});
return res.status(200).json({
success: true,
code: response.status,
statusText: response.statusText,
msg: `URL resolved successfully`,
return res.success({
status: response.status,
msg: response.statusText,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "checkEndpointResolution"));
@@ -319,7 +309,7 @@ class MonitorController {
stack: error.stack,
});
}
return res.status(200).json({ success: true, msg: successMessages.MONITOR_DELETE });
return res.success({ msg: successMessages.MONITOR_DELETE });
} catch (error) {
next(handleError(error, SERVICE_NAME, "deleteMonitor"));
}
@@ -359,9 +349,7 @@ class MonitorController {
}
})
);
return res
.status(200)
.json({ success: true, msg: `Deleted ${deletedCount} monitors` });
return res.success({ msg: `Deleted ${deletedCount} monitors` });
} catch (error) {
next(handleError(error, SERVICE_NAME, "deleteAllMonitors"));
}
@@ -412,8 +400,7 @@ class MonitorController {
await this.jobQueue.deleteJob(monitorBeforeEdit);
// Add the new job back to the queue
await this.jobQueue.addJob(editedMonitor._id, editedMonitor);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_EDIT,
data: editedMonitor,
});
@@ -449,8 +436,7 @@ class MonitorController {
monitor.isActive = !monitor.isActive;
monitor.status = undefined;
monitor.save();
return res.status(200).json({
success: true,
return res.ssuccess({
msg: monitor.isActive
? successMessages.MONITOR_RESUME
: successMessages.MONITOR_PAUSE,
@@ -482,8 +468,7 @@ class MonitorController {
demoMonitors.map((monitor) => this.jobQueue.addJob(monitor._id, monitor))
);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.MONITOR_DEMO_ADDED,
data: demoMonitors.length,
});
@@ -502,9 +487,8 @@ class MonitorController {
try {
const monitors = await this.db.getMonitorsByTeamId(req);
return res.status(200).json({
success: true,
msg: "good",
return res.success({
msg: successMessages.MONITOR_GET_BY_TEAM_ID,
data: monitors,
});
} catch (error) {

View File

@@ -11,8 +11,7 @@ class JobQueueController {
getMetrics = async (req, res, next) => {
try {
const metrics = await this.jobQueue.getMetrics();
res.status(200).json({
success: true,
res.success({
msg: successMessages.QUEUE_GET_METRICS,
data: metrics,
});
@@ -25,8 +24,7 @@ class JobQueueController {
getJobs = async (req, res, next) => {
try {
const jobs = await this.jobQueue.getJobStats();
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.QUEUE_GET_METRICS,
data: jobs,
});
@@ -39,8 +37,7 @@ class JobQueueController {
addJob = async (req, res, next) => {
try {
await this.jobQueue.addJob(Math.random().toString(36).substring(7));
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.QUEUE_ADD_JOB,
});
} catch (error) {
@@ -52,9 +49,9 @@ class JobQueueController {
obliterateQueue = async (req, res, next) => {
try {
await this.jobQueue.obliterate();
return res
.status(200)
.json({ success: true, msg: successMessages.QUEUE_OBLITERATE });
return res.success({
msg: successMessages.QUEUE_OBLITERATE,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "obliterateQueue"));
return;

View File

@@ -13,8 +13,7 @@ class SettingsController {
try {
const settings = { ...(await this.settingsService.getSettings()) };
delete settings.jwtSecret;
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.GET_APP_SETTINGS,
data: settings,
});
@@ -35,8 +34,7 @@ class SettingsController {
await this.db.updateAppSettings(req.body);
const updatedSettings = { ...(await this.settingsService.reloadSettings()) };
delete updatedSettings.jwtSecret;
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.UPDATE_APP_SETTINGS,
data: updatedSettings,
});

View File

@@ -22,8 +22,7 @@ class StatusPageController {
try {
const statusPage = await this.db.createStatusPage(req.body);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.STATUS_PAGE_CREATE,
data: statusPage,
});
@@ -42,8 +41,7 @@ class StatusPageController {
try {
const { url } = req.params;
const statusPage = await this.db.getStatusPageByUrl(url);
return res.status(200).json({
success: true,
return res.success({
msg: successMessages.STATUS_PAGE_BY_URL,
data: statusPage,
});

View File

@@ -8,6 +8,7 @@ import cors from "cors";
import logger from "./utils/logger.js";
import { verifyJWT } from "./middleware/verifyJWT.js";
import { handleErrors } from "./middleware/handleErrors.js";
import { responseHandler } from "./middleware/responseHandler.js";
import { fileURLToPath } from "url";
import AuthRoutes from "./routes/authRoute.js";
@@ -272,6 +273,8 @@ const startApp = async () => {
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(openApiSpec));
//routes
app.use(responseHandler);
app.use("/api/v1/auth", authRoutes.getRouter());
app.use("/api/v1/settings", verifyJWT, settingsRoutes.getRouter());
app.use("/api/v1/invite", inviteRoutes.getRouter());

View File

@@ -11,7 +11,10 @@ const handleErrors = (error, req, res, next) => {
method: error.method,
stack: error.stack,
});
res.status(status).json({ success: false, msg: message });
res.error({
status,
msg: message,
});
};
export { handleErrors };

View File

@@ -0,0 +1,20 @@
const responseHandler = (req, res, next) => {
res.success = ({ status = 200, msg = "OK", data = null }) => {
return res.status(status).json({
success: true,
msg: msg,
data: data,
});
};
res.error = ({ status = 500, msg = "Internal server error", data = null }) => {
return res.status(status).json({
success: false,
msg,
data,
});
};
next();
};
export { responseHandler };

View File

@@ -73,6 +73,7 @@ const successMessages = {
ALERT_EDIT: "Alert edited successfully",
ALERT_DELETE: "Alert deleted successfully",
// Auth Controller
AUTH_CREATE_USER: "User created successfully",
AUTH_LOGIN_USER: "User logged in successfully",
AUTH_LOGOUT_USER: "User logged out successfully",
@@ -83,6 +84,11 @@ const successMessages = {
AUTH_ADMIN_CHECK: "Admin check completed successfully",
AUTH_DELETE_USER: "User deleted successfully",
AUTH_TOKEN_REFRESHED: "Auth token is refreshed",
AUTH_GET_ALL_USERS: "Got all users successfully",
// Invite Controller
INVITE_ISSUED: "Invite sent successfully",
INVITE_VERIFIED: "Invite verified successfully",
// Check Controller
CHECK_CREATE: "Check created successfully",
@@ -94,6 +100,7 @@ const successMessages = {
MONITOR_GET_ALL: "Got all monitors successfully",
MONITOR_STATS_BY_ID: "Got monitor stats by Id successfully",
MONITOR_GET_BY_ID: "Got monitor by Id successfully",
MONITOR_GET_BY_TEAM_ID: "Got monitors by Team Id successfully",
MONITOR_GET_BY_USER_ID: (userId) => `Got monitor for ${userId} successfully"`,
MONITOR_CREATE: "Monitor created successfully",
MONITOR_DELETE: "Monitor deleted successfully",