To be able to handle errors better during the application runtime and to send errors back to the client so that the client can handle them easily, we will need to define some standards for errors => all errors in the application will be mapped to 1–2 standard errors, and that is the task we need to perform in this section.
Errors will be divided into 2 types: Application – errors belonging to the application (mapped to HTTP Error 5xx) and Client – errors belonging to the client (mapped to HTTP Error 4xx).
In the error folder, we will create additional files such as AppError.ts, ClientError.ts, index.ts and type.ts.
In type.ts we will add the following code
export type TBaseErrorDetail = { source: string; desc?: string } & Record<
string,
any
>;
export type TErrorDetails = {
reasons?: Array<TBaseErrorDetail>;
};
Sometimes the message and code may not be enough to describe the error, so I will also add a detail part in the error.

In AppError.ts, add
List of information for HTTP Server Error.
// Import types
import type { TBaseErrorDetail, TErrorDetails } from "./type";
export const HTTPServerErrorDict = {
InternalServerError: {
Status: 500,
Code: "INTERNAL_SERVER_ERROR",
},
NotImplemented: {
Status: 501,
Code: "NOT_IMPLEMENTED",
},
BadGateway: {
Status: 502,
Code: "BAD_GATEWAY",
},
ServiceUnavailable: {
Status: 503,
Code: "SERVICE_UNAVAILABLE",
},
GatewayTimeout: {
Status: 504,
Code: "GATEWAY_TIMEOUT",
},
HttpVersionNotSupported: {
Status: 505,
Code: "HTTP_VERSION_NOT_SUPPORTED",
},
} as const;
export type UHTTPServerErrorType = keyof typeof HTTPServerErrorDict;
Next is the definition class of AppError.
/**
* Lớp định nghĩa lỗi từ App hoặc phản hồi từ App.
*/
export class AppError extends Error {
public statusCode: number;
public code?: string;
public details?: TErrorDetails;
constructor(
message: string,
statusCode = 500,
code?: string,
details?: TErrorDetails,
) {
super(message);
this.statusCode = statusCode;
this.code = code;
this.details = details;
Object.setPrototypeOf(this, new.target.prototype);
}
/**
* Tạo ra một base error detail.
*
* @static
* @returns
*/
static createErrorDetail(source: string, desc: string): TBaseErrorDetail {
return {
source,
desc,
};
}
/**
* Thêm chi tiết lỗi vào tổng lỗi.
*
* @param detail - chi tiết lỗi.
*
* @returns
*/
addErrorDetail(detail: TBaseErrorDetail) {
if (!this.details) this.details = { reasons: [detail] };
else if (this.details && !this.details.reasons) {
this.details.reasons = [detail];
} else {
this.details.reasons?.push(detail);
}
}
/**
* Xem error này chính là HTTP Error.
*
* @param name - tên loại của HTTP Error.
*/
asHTTPError(name: string) {
this.statusCode = HTTPServerErrorDict[name as UHTTPServerErrorType].Status;
this.code = HTTPServerErrorDict[name as UHTTPServerErrorType].Code;
}
/**
* Trả về error là một plain object.
*
* @returns
*/
toPlain() {
return {
message: this.message,
code: this.code,
details: this.details,
};
}
}


Similarly, in ClientError.ts.
List of information for HTTP Client Error.
import { AppError, UHTTPServerErrorType } from "./AppError";
// Import types
import type { TBaseErrorDetail, TErrorDetails } from "./type";
export const HTTPClientErrorDict = {
BadRequest: {
Status: 400,
Code: "BAD_REQUEST",
},
Unauthorized: {
Status: 401,
Code: "UNAUTHORIZED",
},
Forbidden: {
Status: 403,
Code: "FORBIDDEN",
},
NotFound: {
Status: 404,
Code: "NOT_FOUND",
},
MethodNotAllowed: {
Status: 405,
Code: "METHOD_NOT_ALLOWED",
},
RequestTimeout: {
Status: 408,
Code: "REQUEST_TIMEOUT",
},
Conflict: {
Status: 409,
Code: "CONFLICT",
},
Gone: {
Status: 410,
Code: "GONE",
},
UnprocessableEntity: {
Status: 422,
Code: "UNPROCESSABLE_ENTITY",
},
TooManyRequests: {
Status: 429,
Code: "TOO_MANY_REQUESTS",
},
} as const;
export type UHTTPClientErrorType = keyof typeof HTTPClientErrorDict;
And the code for the definition of the ClientError class. We will make ClientError inherit from AppError.
/**
* Lớp định nghĩa lỗi từ client hoặc là lỗi nội bộ của app.
*/
export class ClientError extends AppError {
constructor(message: string, details?: TErrorDetails) {
super(
message,
HTTPClientErrorDict.BadRequest.Status,
HTTPClientErrorDict.BadRequest.Code,
details,
);
}
/**
* Xem error này chính là HTTP Error.
*
* @param name - tên loại của HTTP Error.
*/
asHTTPError(name: string) {
this.statusCode = HTTPClientErrorDict[name as UHTTPClientErrorType].Status;
this.code = HTTPClientErrorDict[name as UHTTPClientErrorType].Code;
}
/**
* Tạo ra một base error detail.
*
* @static
* @returns
*/
static createErrorDetail(source: string, desc: string): TBaseErrorDetail {
return {
source,
desc,
};
}
}


Finally, in index.ts, add the following code
import { AppError } from "./AppError";
import { ClientError } from "./ClientError";
export * from "./AppError";
export * from "./ClientError";
export * from "./type";
/**
* Kiểm tra xem nếu một lỗi có phải là lỗi tiêu chuẩn (AppError, ClientError).
*
* @param err - lỗi từ nguồn chưa biết.
*
* @returns
*/
export function isStandardError(err: any) {
return err instanceof AppError || err instanceof ClientError;
}
In this, we will add a function to check whether the passed object is a standard error or not.
