diff --git a/db/errors/postgresErrorConstants.ts b/db/errors/postgresErrorConstants.ts index 1460b02..5c66a28 100644 --- a/db/errors/postgresErrorConstants.ts +++ b/db/errors/postgresErrorConstants.ts @@ -1,8 +1,8 @@ -export const publicPostgresErrorClasses = ["22", "23"] as const; +export const PUBLIC_POSTGRES_ERROR_CLASSES = ["22", "23"] as const; // from https://www.postgresql.org/docs/9.3/protocol-error-fields.html -export const postgresErrorSeverities = ["ERROR", "FATAL", "PANIC"] as const; -export const postgresNoticeSeverities = [ +export const POSTGRES_ERROR_SEVERITIES = ["ERROR", "FATAL", "PANIC"] as const; +export const POSTGRES_NOTICE_SEVERITIES = [ "WARNING", "NOTICE", "DEBUG", @@ -10,7 +10,7 @@ export const postgresNoticeSeverities = [ ] as const; // from https://www.postgresql.org/docs/current/errcodes-appendix.html -export const postgresErrorClassToTitleMap = { +export const POSTGRES_ERROR_CLASS_TO_TITLE_MAP = { "00": "Successful Completion", "01": "Warning", "02": "No Data", @@ -55,7 +55,7 @@ export const postgresErrorClassToTitleMap = { XX: "Internal Error", } as const; -export const postgresErrorCodeToMessageMap = { +export const POSTGRES_ERROR_CODE_TO_MESSAGE_MAP = { "00000": "successful_completion", "01000": "warning", diff --git a/db/errors/postgresErrorConstantsParsers.ts b/db/errors/postgresErrorConstantsParsers.ts index e3e4636..6de8621 100644 --- a/db/errors/postgresErrorConstantsParsers.ts +++ b/db/errors/postgresErrorConstantsParsers.ts @@ -1,28 +1,28 @@ import { zodEnumFromObjKeys } from "@lib/lib"; import { z } from "zod"; import { - postgresErrorClassToTitleMap, - postgresErrorCodeToMessageMap, - postgresErrorSeverities, - postgresNoticeSeverities, - publicPostgresErrorClasses, + POSTGRES_ERROR_CLASS_TO_TITLE_MAP, + POSTGRES_ERROR_CODE_TO_MESSAGE_MAP, + POSTGRES_ERROR_SEVERITIES, + POSTGRES_NOTICE_SEVERITIES, + PUBLIC_POSTGRES_ERROR_CLASSES, } from "./postgresErrorConstants"; export const postgresErrorCodeParser = zodEnumFromObjKeys( - postgresErrorCodeToMessageMap, + POSTGRES_ERROR_CODE_TO_MESSAGE_MAP, ); export const publicPostgresErrorClassParser = zodEnumFromObjKeys( - postgresErrorClassToTitleMap, -).extract(publicPostgresErrorClasses); + POSTGRES_ERROR_CLASS_TO_TITLE_MAP, +).extract(PUBLIC_POSTGRES_ERROR_CLASSES); -type PostgresErrorCode = keyof typeof postgresErrorCodeToMessageMap; +type PostgresErrorCode = keyof typeof POSTGRES_ERROR_CODE_TO_MESSAGE_MAP; type PostgresErrorMessage = - (typeof postgresErrorCodeToMessageMap)[PostgresErrorCode]; + (typeof POSTGRES_ERROR_CODE_TO_MESSAGE_MAP)[PostgresErrorCode]; -type PostgresErrorClass = keyof typeof postgresErrorClassToTitleMap; +type PostgresErrorClass = keyof typeof POSTGRES_ERROR_CLASS_TO_TITLE_MAP; type PostgresErrorTitle = - (typeof postgresErrorClassToTitleMap)[PostgresErrorClass]; + (typeof POSTGRES_ERROR_CLASS_TO_TITLE_MAP)[PostgresErrorClass]; export function generatePostgresErrorCodeInfo(code: PostgresErrorCode): { code: PostgresErrorCode; @@ -34,12 +34,12 @@ export function generatePostgresErrorCodeInfo(code: PostgresErrorCode): { const errorClass = code.substring(0, 2) as PostgresErrorClass; return { code, - message: postgresErrorCodeToMessageMap[code], + message: POSTGRES_ERROR_CODE_TO_MESSAGE_MAP[code], class: errorClass, - title: postgresErrorClassToTitleMap[errorClass], + title: POSTGRES_ERROR_CLASS_TO_TITLE_MAP[errorClass], }; } export const postgresSeverityParser = z - .enum(postgresErrorSeverities) - .or(z.enum(postgresNoticeSeverities)); + .enum(POSTGRES_ERROR_SEVERITIES) + .or(z.enum(POSTGRES_NOTICE_SEVERITIES)); diff --git a/src/db-access/expenses.ts b/src/db-access/expenses.ts index 9389d33..33354ca 100644 --- a/src/db-access/expenses.ts +++ b/src/db-access/expenses.ts @@ -1,7 +1,7 @@ import { database } from "@db/setup/queryPostgres"; import { expensesTable } from "@db/tables/expenses"; import { - type ORMResult, + type OrmResult, handleDatabaseFullfillment, handleDatabaseRejection, ormError, @@ -23,7 +23,7 @@ import { export async function insertExpenses( expenses: NewExpense[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const insertResult = await tx @@ -37,7 +37,7 @@ export async function insertExpenses( export async function paybackExpenses( expenseIds: ExpenseKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const handledExpenses = await tx @@ -50,7 +50,7 @@ export async function paybackExpenses( ), ); if (handledExpenses.length !== 0) { - throw ormError("Couldn't pay back expense, already handled."); + throw ormError("Already handled"); } const updateResult = await database @@ -59,7 +59,7 @@ export async function paybackExpenses( .where(inArray(expensesTable.id, expenseIds)) .returning(); if (updateResult.length !== expenseIds.length) { - throw ormError("Couldn't update, some id's didn't exist."); + throw ormError("Couln't find all entries"); } return updateResult; }) @@ -68,7 +68,7 @@ export async function paybackExpenses( export async function rejectExpense( expenseIds: ExpenseKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const handledExpenses = await tx @@ -81,7 +81,7 @@ export async function rejectExpense( ), ); if (handledExpenses.length !== 0) { - throw ormError("Couldn't reject expense, already handled."); + throw ormError("Already handled"); } const updateResult = await database @@ -90,7 +90,7 @@ export async function rejectExpense( .where(inArray(expensesTable.id, expenseIds)) .returning(); if (updateResult.length !== expenseIds.length) { - throw ormError("Couldn't update, some id's didn't exist."); + throw ormError("Couln't find all entries"); } return updateResult; }) @@ -99,7 +99,7 @@ export async function rejectExpense( export async function selectExpensesById( expenseIds: ExpenseKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const selectResult = await tx @@ -107,7 +107,7 @@ export async function selectExpensesById( .from(expensesTable) .where(inArray(expensesTable.id, expenseIds)); if (selectResult.length !== expenseIds.length) { - throw ormError("Couldn't select expenses, id's didn't exist."); + throw ormError("Couln't find all entries"); } return selectResult; }) @@ -116,7 +116,7 @@ export async function selectExpensesById( export async function selectExpenses( parameters: QueryParameters, -): Promise> { +): Promise> { return database .transaction(async (tx) => { let selectResult: Promise; @@ -142,7 +142,7 @@ export async function selectExpenses( export async function getSumUnprocessed( timePeriod: datePeriod, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const unprocessedExpences = await tx @@ -160,7 +160,7 @@ export async function getSumUnprocessed( ); if (unprocessedExpences.length !== 1) { - throw ormError("Invalid money numbers from database."); + throw ormError("Wrong database response format"); } const sumOfValues = unprocessedExpences[0]; @@ -177,7 +177,7 @@ export async function getSumUnprocessed( export async function getSumAccepted( timePeriod: datePeriod, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const acceptedExpences = await tx @@ -196,7 +196,7 @@ export async function getSumAccepted( ); if (acceptedExpences.length !== 1) { - throw ormError("Invalid money numbers from database."); + throw ormError("Wrong database response format"); } const sumOfValues = acceptedExpences[0]; @@ -213,7 +213,7 @@ export async function getSumAccepted( export async function getSumRejected( timePeriod: datePeriod, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const rejectedExpences = await tx @@ -232,7 +232,7 @@ export async function getSumRejected( ); if (rejectedExpences.length !== 1) { - throw ormError("Invalid money numbers from database."); + throw ormError("Wrong database response format"); } const sumOfValues = rejectedExpences[0]; @@ -249,7 +249,7 @@ export async function getSumRejected( export async function getAveragePaybackTime( timePeriod: datePeriod, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const result = await tx diff --git a/src/db-access/sponsors.ts b/src/db-access/sponsors.ts index d102f24..6fb2a0b 100644 --- a/src/db-access/sponsors.ts +++ b/src/db-access/sponsors.ts @@ -1,7 +1,7 @@ import { database } from "@db/setup/queryPostgres"; import { sponsorsTable } from "@db/tables/sponsors"; import { - type ORMResult, + type OrmResult, handleDatabaseFullfillment, handleDatabaseRejection, ormError, @@ -12,7 +12,7 @@ import { inArray } from "drizzle-orm"; export async function insertSponsors( sponsors: NewSponsor[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const insertResult = await tx @@ -26,7 +26,7 @@ export async function insertSponsors( export async function selectSponsorsById( sponsorIds: SponsorKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const selectResult = await tx @@ -34,7 +34,7 @@ export async function selectSponsorsById( .from(sponsorsTable) .where(inArray(sponsorsTable.id, sponsorIds)); if (selectResult.length !== sponsorIds.length) { - throw ormError("Couldn't select sponsors, id's didn's exist."); + throw ormError("Couln't find all entries"); } return selectResult; }) diff --git a/src/db-access/team_applications.ts b/src/db-access/team_applications.ts index 8a167de..c550d65 100644 --- a/src/db-access/team_applications.ts +++ b/src/db-access/team_applications.ts @@ -1,7 +1,7 @@ import { database } from "@db/setup/queryPostgres"; import { teamApplicationsTable } from "@db/tables/teamApplication"; import { - type ORMResult, + type OrmResult, handleDatabaseFullfillment, handleDatabaseRejection, } from "@src/error/ormError"; @@ -15,7 +15,7 @@ import { asc, inArray } from "drizzle-orm"; export const selectTeamApplications = async ( parameters: QueryParameters, -): Promise> => { +): Promise> => { return database .transaction(async (tx) => { return await tx @@ -31,7 +31,7 @@ export const selectTeamApplications = async ( export const selectTeamApplicationsByTeamId = async ( teamId: TeamKey[], parameters: QueryParameters, -): Promise> => { +): Promise> => { return database .transaction(async (tx) => { const selectResult = await tx @@ -47,7 +47,7 @@ export const selectTeamApplicationsByTeamId = async ( export async function insertTeamApplication( teamApplication: NewTeamApplication[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const insertResult = await tx diff --git a/src/db-access/users.ts b/src/db-access/users.ts index 4bb35b6..b4b8aef 100644 --- a/src/db-access/users.ts +++ b/src/db-access/users.ts @@ -5,7 +5,7 @@ import { usersTable, } from "@db/tables/users"; import { - type ORMResult, + type OrmResult, handleDatabaseFullfillment, handleDatabaseRejection, ormError, @@ -26,7 +26,7 @@ import { eq, inArray } from "drizzle-orm"; export async function selectUsersById( userIds: UserKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -34,7 +34,7 @@ export async function selectUsersById( .from(usersTable) .where(inArray(usersTable.id, userIds)); if (users.length !== userIds.length) { - throw ormError("Couln't select all users, some id's didn't exist."); + throw ormError("Couln't find all entries"); } return users; }) @@ -43,7 +43,7 @@ export async function selectUsersById( export async function selectTeamUsersById( userIds: UserKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -62,7 +62,7 @@ export async function selectTeamUsersById( .where(inArray(assistantUsersTable.id, userIds)) .innerJoin(usersTable, eq(teamUsersTable.id, usersTable.id)); if (users.length !== userIds.length) { - throw ormError("Couln't select all users, some id's didn't exist."); + throw ormError("Couln't find all entries"); } return users; }) @@ -71,7 +71,7 @@ export async function selectTeamUsersById( export async function selectAssistantUsersById( userIds: UserKey[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -88,7 +88,7 @@ export async function selectAssistantUsersById( .where(inArray(assistantUsersTable.id, userIds)) .innerJoin(usersTable, eq(assistantUsersTable.id, usersTable.id)); if (users.length !== userIds.length) { - throw ormError("Couln't select all users, some id's didn't exist."); + throw ormError("Couln't find all entries"); } return users; }) @@ -97,7 +97,7 @@ export async function selectAssistantUsersById( export async function selectUsers( queryParameters: QueryParameters, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -113,7 +113,7 @@ export async function selectUsers( export async function selectTeamUsers( queryParameters: QueryParameters, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -140,7 +140,7 @@ export async function selectTeamUsers( export async function selectAssistantUsers( queryParameters: QueryParameters, -): Promise> { +): Promise> { return database .transaction(async (tx) => { const users = await tx @@ -163,7 +163,7 @@ export async function selectAssistantUsers( .then(handleDatabaseFullfillment, handleDatabaseRejection); } -export async function insertUsers(user: NewUser[]): Promise> { +export async function insertUsers(user: NewUser[]): Promise> { return database .transaction(async (tx) => { return await tx.insert(usersTable).values(user).returning(); @@ -173,7 +173,7 @@ export async function insertUsers(user: NewUser[]): Promise> { export async function insertTeamUsers( teamUser: NewTeamUser[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const newTeamUserTables = await tx @@ -184,7 +184,7 @@ export async function insertTeamUsers( const newTeamUsersResult = await selectTeamUsersById(newTeamUserIds); if (!newTeamUsersResult.success) { throw ormError( - "Error when inserting team users", + "Failed to insert all entries", newTeamUsersResult.error, ); } @@ -195,7 +195,7 @@ export async function insertTeamUsers( export async function insertAssistantUsers( assistantUser: NewAssistantUser[], -): Promise> { +): Promise> { return database .transaction(async (tx) => { const newAssistantUserTables = await tx @@ -207,7 +207,7 @@ export async function insertAssistantUsers( await selectAssistantUsersById(newAssistantUserIds); if (!newAssistantUsersResult.success) { throw ormError( - "Error when inserting assistant users", + "Failed to insert all entries", newAssistantUsersResult.error, ); } diff --git a/src/error/errorMessages.ts b/src/error/errorMessages.ts new file mode 100644 index 0000000..eb09e59 --- /dev/null +++ b/src/error/errorMessages.ts @@ -0,0 +1,119 @@ +const ORM_ERROR_MESSAGES = [ + "Database access error", + "Connection failed", + "Query execution error", + "Entity not found", + "Validation error", + "Duplicate entry", + "Missing required field", + "Foreign key constraint violation", + "Transaction failed", + "Database timeout", + "Invalid data type", + "Record already exists", + "Update conflict", + "Permission denied", + "Schema mismatch", + "Data integrity violation", + "Record locked", + "Too many connections", + "Unsupported operation", + "Out of memory", + "Rollback error", + "Data not saved", + "Invalid query syntax", + "Database not reachable", + "Session expired", + "Query timeout", + "Already handled", + "Couln't find all entries", + "Wrong database response format", + "Failed to insert all entries", +] as const; +const HTTP_CLIENT_ERROR_MESSAGES = [ + "Invalid request format", + "Missing required parameters", + "Unauthorized access attempt", + "User not found in the system", + "Invalid credentials provided", + "Session has expired", + "Access denied to the requested resource", + "Request timeout", + "Invalid input data", + "Resource not available", + "Quota exceeded for this request", + "Insufficient permissions for this action", + "Request could not be processed", + "Bad request syntax", + "Operation not allowed", + "Request entity too large", + "Unsupported media type", + "Method not allowed for this endpoint", + "Invalid query parameters", + "Resource already exists", + "Rate limit exceeded", + "Validation error occurred", + "Unexpected error during request handling", + "Service unavailable temporarily", + "Request redirected to another endpoint", + "Conflict with the current state of the resource", + "Data not found in the database", + "Duplicate entry in the database", + "Database transaction failed", + "Database timeout occurred", + "Insufficient permissions to access the database", + "Data integrity violation", + "Failed to retrieve data from the database", + "Database schema mismatch", + "Failed to execute the database command", + "Error parsing database response", +] as const; +const HTTP_SERVER_ERROR_MESSAGES = [ + "Internal server error occurred", + "Database connection failed", + "Unexpected error on the server", + "Service is currently down for maintenance", + "Server encountered an unexpected condition", + "Failed to process the request due to a server error", + "Resource could not be retrieved", + "Server overload, please try again later", + "Error while processing data", + "Application error occurred", + "Service timeout while processing the request", + "Insufficient resources to handle the request", + "Unexpected response from external service", + "Error in server configuration", + "Failed to load required modules", + "Server encountered a critical error", + "Data processing error", + "Security violation detected", + "Service is temporarily unavailable", + "Error while communicating with the backend", + "Server is busy, please retry later", + "Network error while processing the request", + "Error while handling user session", + "Configuration error in the application", + "Error while generating response", + "Server is unable to fulfill the request", + "Database connection error", + "Database query execution failed", + "Database server is down", + "Error while migrating database", + "Database deadlock detected", + "Database index not found", + "Error while updating database records", + "Database timeout while executing query", + "Data corruption detected in the database", + "Invalid database credentials", + "Error while closing database connection", + "Database backup failed", + "Database restore operation failed", + "Database schema update required", + "Error while fetching records from the database", +] as const; +export type OrmErrorMessage = (typeof ORM_ERROR_MESSAGES)[number]; +export type HttpClientErrorMessage = + (typeof HTTP_CLIENT_ERROR_MESSAGES)[number]; +export type HttpServerErrorMessage = + (typeof HTTP_SERVER_ERROR_MESSAGES)[number]; +export type HttpErrorMessage = HttpClientErrorMessage | HttpServerErrorMessage; diff --git a/src/error/httpCodes.ts b/src/error/httpCodes.ts new file mode 100644 index 0000000..4c39e43 --- /dev/null +++ b/src/error/httpCodes.ts @@ -0,0 +1,70 @@ +// From https://developer.mozilla.org/en-US/docs/Web/HTTP/Status +export const HTTP_STATUS_CODE_MAP = { + Informational: { + 100: "Continue", + 101: "Switching Protocols", + 102: "Processing", + }, + Successful: { + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi-Status", + 208: "Already Reported", + 226: "IM Used", + }, + Redirection: { + 300: "Multiple Choices", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 306: "Switch Proxy", + 307: "Temporary Redirect", + 308: "Permanent Redirect", + }, + "Client error": { + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Payload Too Large", + 414: "URI Too Long", + 415: "Unsupported Media Type", + 416: "Range Not Satisfiable", + 417: "Expectation Failed", + 418: "I'm a teapot", + 421: "Misdirected Request", + 422: "Unprocessable Entity", + 423: "Locked", + 424: "Failed Dependency", + 426: "Upgrade Required", + 428: "Precondition Required", + 429: "Too Many Requests", + 431: "Request Header Fields Too Large", + 451: "Unavailable For Legal Reasons", + }, + "Server error": { + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported", + 511: "Network Authentication Required", + }, +} as const; diff --git a/src/error/httpCodesManipulators.ts b/src/error/httpCodesManipulators.ts new file mode 100644 index 0000000..a41c5fc --- /dev/null +++ b/src/error/httpCodesManipulators.ts @@ -0,0 +1,60 @@ +import { HTTP_STATUS_CODE_MAP } from "./httpCodes"; + +export type HttpClientErrorCode = + keyof (typeof HTTP_STATUS_CODE_MAP)["Client error"]; +export type HttpServerErrorCode = + keyof (typeof HTTP_STATUS_CODE_MAP)["Server error"]; +export type HttpErrorCode = HttpClientErrorCode | HttpServerErrorCode; + +function isHttpClientErrorCode(code: number): code is HttpClientErrorCode { + return Object.keys(HTTP_STATUS_CODE_MAP["Client error"]) + .map(Number) + .includes(code); +} +function isHttpServerErrorCode(code: number): code is HttpServerErrorCode { + return Object.keys(HTTP_STATUS_CODE_MAP["Server error"]) + .map(Number) + .includes(code); +} +function isHttpErrorCode(code: number) { + return isHttpClientErrorCode(code) || isHttpServerErrorCode(code); +} + +export type HttpClientErrorCodeInfo = { + title: "Client error"; + code: HttpClientErrorCode; + message: (typeof HTTP_STATUS_CODE_MAP)["Client error"][HttpClientErrorCode]; +}; +export type HttpServerErrorCodeInfo = { + title: "Server error"; + code: HttpServerErrorCode; + message: (typeof HTTP_STATUS_CODE_MAP)["Server error"][HttpServerErrorCode]; +}; +export type HttpErrorCodeInfo = + | HttpClientErrorCodeInfo + | HttpServerErrorCodeInfo; + +export function getHttpClientErrorCodeInfo( + code: HttpClientErrorCode, +): HttpClientErrorCodeInfo { + return { + title: "Client error", + code: code, + message: HTTP_STATUS_CODE_MAP["Client error"][code], + }; +} +export function getHttpServerErrorCodeInfo( + code: HttpServerErrorCode, +): HttpServerErrorCodeInfo { + return { + title: "Server error", + code: code, + message: HTTP_STATUS_CODE_MAP["Server error"][code], + }; +} +export function getHttpErrorCodeInfo(code: HttpErrorCode): HttpErrorCodeInfo { + if (isHttpClientErrorCode(code)) { + return getHttpClientErrorCodeInfo(code); + } + return getHttpServerErrorCodeInfo(code); +} diff --git a/src/error/httpErrors.ts b/src/error/httpErrors.ts index f36659e..016e69e 100644 --- a/src/error/httpErrors.ts +++ b/src/error/httpErrors.ts @@ -1,124 +1,122 @@ -import { STATUS_CODES } from "node:http"; import type { Result } from "@lib/types"; -import { isORMError } from "@src/error/ormError"; import { fromZodError, isZodErrorLike } from "zod-validation-error"; +import type { + HttpClientErrorMessage, + HttpErrorMessage, + HttpServerErrorMessage, +} from "./errorMessages"; +import { + type HttpClientErrorCode, + type HttpClientErrorCodeInfo, + type HttpErrorCode, + type HttpErrorCodeInfo, + type HttpServerErrorCode, + type HttpServerErrorCodeInfo, + getHttpClientErrorCodeInfo, + getHttpErrorCodeInfo, + getHttpServerErrorCodeInfo, +} from "./httpCodesManipulators"; +import { isORMError } from "./ormError"; -class HTTPError extends Error { - private errorCode: number; - private displayCause: boolean; - constructor(message: string, httpErrorCode: number, displayCause: boolean) { - super(message); - if (!Object.keys(STATUS_CODES).includes(httpErrorCode.toString())) { - throw new Error(`${httpErrorCode} is not a http statuscode.`); - } - if ( - Math.floor(httpErrorCode / 100) !== 4 && - Math.floor(httpErrorCode / 100) !== 5 - ) { - throw new Error(`${httpErrorCode} is not a http errorcode.`); - } +class HttpError extends Error { + declare message: HttpErrorMessage; + httpCodeInfo: HttpErrorCodeInfo; + constructor( + message: HttpErrorMessage, + httpCode: HttpErrorCode, + options?: ErrorOptions, + ) { + super(message, options); + this.message = message; this.name = "HTTPError"; - this.errorCode = httpErrorCode; - this.displayCause = displayCause; + this.httpCodeInfo = getHttpErrorCodeInfo(httpCode); } - private getHTTPErrorLabel(): string { - return STATUS_CODES[this.errorCode.toString()] as string; + getResponseCode(): HttpErrorCode { + return this.httpCodeInfo.code; } - private getCauseString() { - let causeString = ""; - if (this.displayCause && this.cause instanceof Error) { - if (isHTTPError(this.cause)) { - causeString += this.cause.getResponseBodyText(); - } else if (isORMError(this.cause)) { - causeString += this.cause.message; - if (this.cause.getPublicDatabaseMessage() !== undefined) { - causeString += `: ${this.cause.getPublicDatabaseMessage()}`; - } - } else if (isZodErrorLike(this.cause)) { - causeString += fromZodError(this.cause); - } else if (this.cause instanceof Error) { - causeString += this.cause.message; - } + getResponseString(): string { + let response = `${this.httpCodeInfo.title}\n${this.httpCodeInfo.code}: ${this.httpCodeInfo.message}\n${this.message}`; + if (this.cause === undefined || !(this.cause instanceof Error)) { + return response; } - return causeString; - } - getResponseBodyText() { - return `${this.errorCode.toString()} ${this.getHTTPErrorLabel()}: ${this.message}\n\t${this.getCauseString()}`; - } - getResponseBodyJSON() { - return { - error: true, - message: this.message, - cause: this.getCauseString(), - }; - } - getErrorCode(): number { - return this.errorCode; + if ( + isORMError(this.cause) && + this.cause.getPublicDatabaseMessage() !== undefined + ) { + response += `\n${this.cause.getPublicDatabaseMessage()}`; + } else if (isZodErrorLike(this.cause)) { + response += `\n${fromZodError(this.cause).message}`; + } else if (this.cause instanceof HttpError) { + response += `\n${this.cause.getResponseString()}`; + } else if (this.cause instanceof Error) { + response += `\n${this.message}`; + } + return response; } } -class ServerError extends HTTPError { - constructor(message: string, httpErrorCode = 500, displayCause = false) { - super(message, httpErrorCode, displayCause); - if (Math.floor(httpErrorCode / 100) !== 5) { - throw new Error( - `${httpErrorCode} is not a valid servererrorcode. Must start with 5.`, - ); - } - this.name = "ServerError"; +class ClientError extends HttpError { + declare message: HttpClientErrorMessage; + declare httpCodeInfo: HttpClientErrorCodeInfo; + constructor( + message: HttpClientErrorMessage, + httpCode: HttpClientErrorCode, + options?: ErrorOptions, + ) { + super(message, httpCode, options); + this.message = message; + this.name = "ClientError"; + this.httpCodeInfo = getHttpClientErrorCodeInfo(httpCode); } } -class ClientError extends HTTPError { - constructor(message: string, httpErrorCode = 400, displayCause = true) { - super(message, httpErrorCode, displayCause); - if (Math.floor(httpErrorCode / 100) !== 4) { - throw new Error( - `${httpErrorCode}is not a valid clienterrorcode. Must start with 4.`, - ); - } - this.name = "ClientError"; +class ServerError extends HttpError { + declare message: HttpServerErrorMessage; + declare httpCodeInfo: HttpServerErrorCodeInfo; + constructor( + message: HttpServerErrorMessage, + httpCode: HttpServerErrorCode, + options?: ErrorOptions, + ) { + super(message, httpCode, options); + this.message = message; + this.name = "ServerError"; + this.httpCodeInfo = getHttpServerErrorCodeInfo(httpCode); } } export const clientError = ( - // biome-ignore lint/style/useDefaultParameterLast: To have code as first parameter - httpStatusCode = 400, - message: string, - cause?: Error, - displayCause = true, + httpStatusCode: HttpClientErrorCode, + message: HttpClientErrorMessage, + cause?: unknown, + options?: ErrorOptions, ): ClientError => { - const error = new ClientError(message, httpStatusCode, displayCause); - if (cause !== undefined) { - error.cause = cause; + if (cause === undefined || cause === null) { + return new ClientError(message, httpStatusCode, options); } - Error.captureStackTrace(error, clientError); - return error; + return new ClientError(message, httpStatusCode, { ...options, cause: cause }); }; export const serverError = ( - // biome-ignore lint/style/useDefaultParameterLast: To have code as first parameter - httpStatusCode = 500, - message: string, - cause?: Error, - displayCause = false, + httpStatusCode: HttpServerErrorCode, + message: HttpServerErrorMessage, + cause?: unknown, + options?: ErrorOptions, ): ServerError => { - const error = new ServerError(message, httpStatusCode, displayCause); - if (cause !== undefined) { - error.cause = cause; + if (cause === undefined || cause === null) { + return new ServerError(message, httpStatusCode, options); } - Error.captureStackTrace(error, serverError); - return error; + return new ServerError(message, httpStatusCode, { ...options, cause: cause }); }; export function isHTTPError( x: unknown, -): x is ServerError | ClientError | HTTPError { +): x is ServerError | ClientError | HttpError { return ( x instanceof ServerError || x instanceof ClientError || - x instanceof HTTPError + x instanceof HttpError ); } -export type HTTPResult = Result; +type HTTPResult = Result; diff --git a/src/error/ormError.ts b/src/error/ormError.ts index 3943fc2..fb1e32d 100644 --- a/src/error/ormError.ts +++ b/src/error/ormError.ts @@ -5,24 +5,26 @@ import { postgresErrorParser, } from "@db/errors/postgresError"; import type { Result } from "@lib/types"; +import type { OrmErrorMessage } from "./errorMessages"; -const defaultORMErrorMessage = "Database access error" as const; +const defaultOrmErrorMessage: OrmErrorMessage = "Database access error"; -class ORMError extends Error { +type OrmErrorOptions = ErrorOptions & { customMessage?: { public: string; private: string; }; - constructor( - message: string, - options?: ErrorOptions & { - customMessage?: { - public: string; - private: string; - }; - }, - ) { +}; + +class OrmError extends Error { + declare message: OrmErrorMessage; + customMessage?: { + public: string; + private: string; + }; + constructor(message: OrmErrorMessage, options?: OrmErrorOptions) { super(message, options); + this.message = message; this.name = "ORMError"; this.customMessage = options?.customMessage; } @@ -41,26 +43,36 @@ class ORMError extends Error { } return this.customMessage?.private; } - private hasCustomMessage(): this is { - customMessage: { public: string; private: string }; - } { + private hasCustomMessage(): this is { public: string; private: string } { return this.customMessage !== undefined; } } -export function isORMError(error: unknown): error is ORMError { - return error instanceof ORMError; +export function isORMError(error: unknown): error is OrmError { + return error instanceof OrmError; } -export function ormError(message: string, cause?: unknown): ORMError { - return new ORMError(message, { cause: cause }); +export function ormError( + message: OrmErrorMessage, + cause?: unknown, + options?: OrmErrorOptions, +): OrmError { + if (cause === undefined || cause === null) { + return new OrmError(message, options); + } + return new OrmError(message, { + ...options, + cause: cause, + }); } export function customOrmError( - message: string, + message: OrmErrorMessage, customPublicMessage: string, customPrivateMessage: string, -): ORMError { - return new ORMError(message, { + options?: ErrorOptions, +): OrmError { + return new OrmError(message, { + ...options, customMessage: { public: customPublicMessage, private: customPrivateMessage, @@ -68,7 +80,7 @@ export function customOrmError( }); } -export type ORMResult = Result; +export type OrmResult = Result; export function handleDatabaseRejection(reason: unknown) { if (isORMError(reason)) { @@ -76,10 +88,10 @@ export function handleDatabaseRejection(reason: unknown) { } return { success: false as const, - error: ormError(defaultORMErrorMessage, reason), + error: ormError(defaultOrmErrorMessage, reason), }; } -export function handleDatabaseFullfillment(value: T): ORMResult { +export function handleDatabaseFullfillment(value: T): OrmResult { return { success: true as const, data: value, diff --git a/src/middleware/errorMiddleware.ts b/src/middleware/errorMiddleware.ts index 2c6893d..8063f44 100644 --- a/src/middleware/errorMiddleware.ts +++ b/src/middleware/errorMiddleware.ts @@ -5,7 +5,9 @@ export const errorHandler: ErrorRequestHandler = (err, req, res, next) => { if (!isHTTPError(err)) { return next(err); } - res.status(err.getErrorCode()).send(err.getResponseBodyJSON()); + res + .status(err.getResponseCode()) + .json({ error: true, message: err.getResponseString() }); }; export const defaultErrorHandler: ErrorRequestHandler = ( @@ -14,8 +16,6 @@ export const defaultErrorHandler: ErrorRequestHandler = ( res, next, ) => { - console.warn( - "WARNING! DEFAULT EXPRESS ERRORHANDLER IS USED. SOMETHING IS WRONG.", - ); - res.status(500).send("Unknown error."); + console.warn("WARNING! DEFAULT EXPRESS ERRORHANDLER IS USED."); + res.status(500).json({ error: true, message: "Unknown error." }); }; diff --git a/src/middleware/loggingMiddleware.ts b/src/middleware/loggingMiddleware.ts index 950ceab..199c30e 100644 --- a/src/middleware/loggingMiddleware.ts +++ b/src/middleware/loggingMiddleware.ts @@ -7,7 +7,3 @@ export function logger(req: Request, res: Response, next: NextFunction) { console.log(`Request nr. ${requestCounter} beeing processed...`); next(); } - -export function loggerSaver(req: Request, res: Response, next: NextFunction) { - // Not implemented.... -} diff --git a/src/routers/expenses.ts b/src/routers/expenses.ts index c0096c0..3630412 100644 --- a/src/routers/expenses.ts +++ b/src/routers/expenses.ts @@ -48,14 +48,18 @@ expenseRouter.post("/", async (req, res, next) => { if (!expenseRequest.success) { const error = clientError( 400, - "Failed parsing expenserequest.", + "Invalid request format", expenseRequest.error, ); return next(error); } const databaseResult = await insertExpenses([expenseRequest.data]); if (!databaseResult.success) { - const error = clientError(400, "Database error", databaseResult.error); + const error = clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ); return next(error); } res.status(201).json(databaseResult.data); @@ -84,12 +88,18 @@ expenseRouter.put("/:id/payback/", async (req, res, next) => { const paybackRequest = toSerialIdParser.safeParse(req.params.id); if (!paybackRequest.success) { return next( - clientError(400, "Failed parsing paybackrequest", paybackRequest.error), + clientError(400, "Invalid request format", paybackRequest.error), ); } const databaseResult = await paybackExpenses([paybackRequest.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ), + ); } res.json(paybackRequest.data); }); @@ -115,12 +125,18 @@ expenseRouter.put("/:id/reject/", async (req, res, next) => { const rejectRequest = toSerialIdParser.safeParse(req.params.id); if (!rejectRequest.success) { return next( - clientError(400, "Failed parsing rejectrequest", rejectRequest.error), + clientError(400, "Invalid request format", rejectRequest.error), ); } const databaseResult = await rejectExpense([rejectRequest.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ), + ); } res.json(rejectRequest.data); }); @@ -145,11 +161,19 @@ expenseRouter.put("/:id/reject/", async (req, res, next) => { expenseRouter.get("/:expenseId/", async (req, res, next) => { const expenseIdResult = toSerialIdParser.safeParse(req.params.expenseId); if (!expenseIdResult.success) { - return next(clientError(400, "", expenseIdResult.error)); + return next( + clientError(400, "Invalid request format", expenseIdResult.error), + ); } const databaseResult = await selectExpensesById([expenseIdResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -176,11 +200,19 @@ expenseRouter.get("/:expenseId/", async (req, res, next) => { expensesRouter.get("/", async (req, res, next) => { const queryParametersResult = toListQueryParser.safeParse(req.query); if (!queryParametersResult.success) { - return next(clientError(400, "", queryParametersResult.error)); + return next( + clientError(400, "Invalid request format", queryParametersResult.error), + ); } const databaseResult = await selectExpenses(queryParametersResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -209,11 +241,19 @@ expensesRouter.get("/", async (req, res, next) => { expensesRouter.get("/money-amount/unprocessed/", async (req, res, next) => { const bodyParameterResult = toDatePeriodParser.safeParse(req.body); if (!bodyParameterResult.success) { - return next(clientError(400, "", bodyParameterResult.error)); + return next( + clientError(400, "Invalid request format", bodyParameterResult.error), + ); } const databaseResult = await getSumUnprocessed(bodyParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -242,11 +282,19 @@ expensesRouter.get("/money-amount/unprocessed/", async (req, res, next) => { expensesRouter.get("/money-amount/accepted/", async (req, res, next) => { const bodyParameterResult = toDatePeriodParser.safeParse(req.body); if (!bodyParameterResult.success) { - return next(clientError(400, "", bodyParameterResult.error)); + return next( + clientError(400, "Invalid request format", bodyParameterResult.error), + ); } const databaseResult = await getSumAccepted(bodyParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -275,11 +323,19 @@ expensesRouter.get("/money-amount/accepted/", async (req, res, next) => { expensesRouter.get("/money-amount/rejected/", async (req, res, next) => { const bodyParameterResult = toDatePeriodParser.safeParse(req.body); if (!bodyParameterResult.success) { - return next(clientError(400, "", bodyParameterResult.error)); + return next( + clientError(400, "Invalid request format", bodyParameterResult.error), + ); } const databaseResult = await getSumRejected(bodyParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -309,12 +365,18 @@ expensesRouter.get("/payback-time/average/", async (req, res, next) => { const bodyParameterResult = toDatePeriodParser.safeParse(req.body); if (!bodyParameterResult.success) { return next( - clientError(400, "Body parse error", bodyParameterResult.error), + clientError(400, "Invalid request format", bodyParameterResult.error), ); } const databaseResult = await getAveragePaybackTime(bodyParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); diff --git a/src/routers/sponsors.ts b/src/routers/sponsors.ts index d7beb34..7e5d440 100644 --- a/src/routers/sponsors.ts +++ b/src/routers/sponsors.ts @@ -33,14 +33,18 @@ sponsorsRouter.post("/", async (req, res, next) => { if (!sponsorRequest.success) { const error = clientError( 400, - "Failed parsing sponsorrequest.", + "Invalid request format", sponsorRequest.error, ); return next(error); } const databaseResult = await insertSponsors([sponsorRequest.data]); if (!databaseResult.success) { - const error = clientError(400, "Database error", databaseResult.error); + const error = clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ); return next(error); } res.status(201).json(databaseResult.data); @@ -66,11 +70,19 @@ sponsorsRouter.post("/", async (req, res, next) => { sponsorsRouter.get("/:sponsorId", async (req, res, next) => { const sponsorIdResult = toSerialIdParser.safeParse(req.params.sponsorId); if (!sponsorIdResult.success) { - return next(clientError(400, "", sponsorIdResult.error)); + return next( + clientError(400, "Invalid request format", sponsorIdResult.error), + ); } const databaseResult = await selectSponsorsById([sponsorIdResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); diff --git a/src/routers/team_application.ts b/src/routers/team_application.ts index 79161db..294a141 100644 --- a/src/routers/team_application.ts +++ b/src/routers/team_application.ts @@ -34,12 +34,20 @@ teamApplicationRouter.use(json()); teamApplicationRouter.get("/", async (req, res, next) => { const queryParametersResult = listQueryParser.safeParse(req.query); if (!queryParametersResult.success) { - return next(clientError(400, "", queryParametersResult.error)); + return next( + clientError(400, "Invalid request format", queryParametersResult.error), + ); } const results = await selectTeamApplications(queryParametersResult.data); if (!results.success) { - return next(clientError(400, "Database error", results.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + results.error, + ), + ); } res.json(results.data); }); @@ -65,18 +73,26 @@ teamApplicationRouter.get("/", async (req, res, next) => { teamApplicationRouter.get("/:teamID/", async (req, res, next) => { const teamIdResult = serialIdParser.safeParse(req.params.teamID); if (!teamIdResult.success) { - return next(clientError(400, "", teamIdResult.error)); + return next(clientError(400, "Invalid request format", teamIdResult.error)); } const queryParametersResult = listQueryParser.safeParse(req.query); if (!queryParametersResult.success) { - return next(clientError(400, "", queryParametersResult.error)); + return next( + clientError(400, "Invalid request format", queryParametersResult.error), + ); } const databaseResult = await selectTeamApplicationsByTeamId( [teamIdResult.data], queryParametersResult.data, ); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -109,7 +125,7 @@ teamApplicationRouter.post("/", async (req, res, next) => { if (!teamApplicationBodyResult.success) { const error = clientError( 400, - "Failed parsing teamapplication request.", + "Invalid request format", teamApplicationBodyResult.error, ); return next(error); @@ -118,7 +134,11 @@ teamApplicationRouter.post("/", async (req, res, next) => { teamApplicationBodyResult.data, ]); if (!databaseResult.success) { - const error = clientError(400, "Database error", databaseResult.error); + const error = clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ); return next(error); } res.status(201).json(databaseResult.data); diff --git a/src/routers/users.ts b/src/routers/users.ts index 014cd16..28ecc34 100644 --- a/src/routers/users.ts +++ b/src/routers/users.ts @@ -50,11 +50,17 @@ usersRouter.use(json()); usersRouter.get("/:userId", async (req, res, next) => { const userIdResult = toSerialIdParser.safeParse(req.params.userId); if (!userIdResult.success) { - return next(clientError(400, "", userIdResult.error)); + return next(clientError(400, "Invalid request format", userIdResult.error)); } const databaseResult = await selectUsersById([userIdResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -79,11 +85,17 @@ usersRouter.get("/:userId", async (req, res, next) => { teamUsersRouter.get("/:userId", async (req, res, next) => { const userIdResult = toSerialIdParser.safeParse(req.params.userId); if (!userIdResult.success) { - return next(clientError(400, "", userIdResult.error)); + return next(clientError(400, "Invalid request format", userIdResult.error)); } const databaseResult = await selectTeamUsersById([userIdResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -108,11 +120,17 @@ teamUsersRouter.get("/:userId", async (req, res, next) => { assistantUsersRouter.get("/:userId", async (req, res, next) => { const userIdResult = toSerialIdParser.safeParse(req.params.userId); if (!userIdResult.success) { - return next(clientError(400, "", userIdResult.error)); + return next(clientError(400, "Invalid request format", userIdResult.error)); } const databaseResult = await selectAssistantUsersById([userIdResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -139,11 +157,19 @@ assistantUsersRouter.get("/:userId", async (req, res, next) => { usersRouter.get("", async (req, res, next) => { const queryParameterResult = toListQueryParser.safeParse(req.query); if (!queryParameterResult.success) { - return next(clientError(400, "", queryParameterResult.error)); + return next( + clientError(400, "Invalid request format", queryParameterResult.error), + ); } const databaseResult = await selectUsers(queryParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -170,11 +196,19 @@ usersRouter.get("", async (req, res, next) => { teamUsersRouter.get("", async (req, res, next) => { const queryParameterResult = toListQueryParser.safeParse(req.query); if (!queryParameterResult.success) { - return next(clientError(400, "", queryParameterResult.error)); + return next( + clientError(400, "Invalid request format", queryParameterResult.error), + ); } const databaseResult = await selectTeamUsers(queryParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -201,11 +235,19 @@ teamUsersRouter.get("", async (req, res, next) => { assistantUsersRouter.get("", async (req, res, next) => { const queryParameterResult = toListQueryParser.safeParse(req.query); if (!queryParameterResult.success) { - return next(clientError(400, "", queryParameterResult.error)); + return next( + clientError(400, "Invalid request format", queryParameterResult.error), + ); } const databaseResult = await selectAssistantUsers(queryParameterResult.data); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to retrieve data from the database", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -234,11 +276,19 @@ assistantUsersRouter.get("", async (req, res, next) => { usersRouter.post("", async (req, res, next) => { const newUserResult = userRequestToInsertParser.safeParse(req.body); if (!newUserResult.success) { - return next(clientError(400, "", newUserResult.error)); + return next( + clientError(400, "Invalid request format", newUserResult.error), + ); } const databaseResult = await insertUsers([newUserResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -267,11 +317,19 @@ usersRouter.post("", async (req, res, next) => { teamUsersRouter.post("", async (req, res, next) => { const newUserResult = teamUserRequestToInsertParser.safeParse(req.body); if (!newUserResult.success) { - return next(clientError(400, "", newUserResult.error)); + return next( + clientError(400, "Invalid request format", newUserResult.error), + ); } const databaseResult = await insertTeamUsers([newUserResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ), + ); } res.json(databaseResult.data); }); @@ -300,11 +358,19 @@ teamUsersRouter.post("", async (req, res, next) => { assistantUsersRouter.post("/assistants", async (req, res, next) => { const newUserResult = assistantUserRequestToInsertParser.safeParse(req.body); if (!newUserResult.success) { - return next(clientError(400, "", newUserResult.error)); + return next( + clientError(400, "Invalid request format", newUserResult.error), + ); } const databaseResult = await insertAssistantUsers([newUserResult.data]); if (!databaseResult.success) { - return next(clientError(400, "Database error", databaseResult.error)); + return next( + clientError( + 400, + "Failed to execute the database command", + databaseResult.error, + ), + ); } res.json(databaseResult.data); });