UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

361 lines 12.5 kB
import { HttpStatusCodes } from "./http-status-codes"; import { getLogger } from "./logger.utils"; import { ErrorResponse } from "./response.utils"; /** * Generic HTTP error class used for custom exceptions with any status code. * Inherit this when you need to throw errors dynamically at runtime. */ export class HttpError extends ErrorResponse { /** * Creates a new HTTP error instance. * @param status - A valid HTTP status code (e.g., 400, 500). * @param message - The error message to return to the client. */ constructor(status, message) { super(message); this.status = status; } } /** * Represents a 500 Internal Server Error. * Use this for unexpected backend errors that are not caused by the client. */ export class InternalServerErrorException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Internal server error". */ constructor(message = "Internal server error") { super(message); this.status = HttpStatusCodes.INTERNAL_SERVER_ERROR; } } /** * Represents a 401 Unauthorized Error. * Indicates that authentication is required and has failed or not been provided. */ export class UnauthorizedException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Unauthorized". */ constructor(message = "Unauthorized") { super(message); this.status = HttpStatusCodes.UNAUTHORIZED; } } /** * Represents a 400 Bad Request Error. * Indicates that the client has sent invalid data (e.g., malformed request body). */ export class BadRequestException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Bad request". */ constructor(message = "Bad request") { super(message); this.status = HttpStatusCodes.BAD_REQUEST; } } /** * Represents a 404 Not Found Error. * Used when a requested resource (e.g., user, file) could not be located. */ export class NotFoundException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Resource not found". */ constructor(message = "Resource not found") { super(message); this.status = HttpStatusCodes.NOT_FOUND; } } /** * Represents a 403 Forbidden Error. * Indicates that the client is authenticated but not allowed to access the resource. */ export class ForbiddenException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Forbidden". */ constructor(message = "Forbidden") { super(message); this.status = HttpStatusCodes.FORBIDDEN; } } /** * Represents a 409 Conflict Error. * Commonly used when a resource already exists or a versioning conflict occurs. */ export class ConflictException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Conflict". */ constructor(message = "Conflict") { super(message); this.status = HttpStatusCodes.CONFLICT; } } /** * Represents a 502 Bad Gateway Error. * Used when the server receives an invalid response from an upstream server. */ export class BadGatewayException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Bad Gateway". */ constructor(message = "Bad Gateway") { super(message); this.status = HttpStatusCodes.BAD_GATEWAY; } } /** * Represents a 429 Too Many Requests Error. * Returned when the client has hit a rate limit. */ export class TooManyRequestsException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Too many requests". */ constructor(message = "Too many requests") { super(message); this.status = HttpStatusCodes.TOO_MANY_REQUESTS; } } /** * Represents a 503 Service Unavailable Error. * Indicates that the server is temporarily unavailable (e.g., for maintenance). */ export class ServiceUnavailableException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Service Unavailable". */ constructor(message = "Service Unavailable") { super(message); this.status = HttpStatusCodes.SERVICE_UNAVAILABLE; } } /** * Represents a 504 Gateway Timeout Error. * Returned when the server acting as a gateway times out waiting for a response. */ export class GatewayTimeoutException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Gateway Timeout". */ constructor(message = "Gateway Timeout") { super(message); this.status = HttpStatusCodes.GATEWAY_TIMEOUT; } } /** * Represents a 422 Unprocessable Entity Error. * Used when the server understands the content type but cannot process the contained instructions. */ export class UnprocessableEntityException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Unprocessable Entity". * @param details - Optional validation details or additional error context. */ constructor(message = "Unprocessable Entity", details) { super(message); this.details = details; this.status = HttpStatusCodes.UNPROCESSABLE_ENTITY; } } /** * Represents a 405 Method Not Allowed Error. * Used when the request method is not supported for the requested resource. */ export class MethodNotAllowedException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Method Not Allowed". * @param allowedMethods - Optional array of allowed HTTP methods. */ constructor(message = "Method Not Allowed", allowedMethods) { super(message); this.allowedMethods = allowedMethods; this.status = HttpStatusCodes.METHOD_NOT_ALLOWED; } } /** * Represents a 406 Not Acceptable Error. * Used when the server cannot produce a response matching the client's accepted content types. */ export class NotAcceptableException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Not Acceptable". */ constructor(message = "Not Acceptable") { super(message); this.status = HttpStatusCodes.NOT_ACCEPTABLE; } } /** * Represents a 408 Request Timeout Error. * Used when the server times out waiting for the client to send a request. */ export class RequestTimeoutException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Request Timeout". */ constructor(message = "Request Timeout") { super(message); this.status = HttpStatusCodes.REQUEST_TIMEOUT; } } /** * Represents a 415 Unsupported Media Type Error. * Used when the request's Content-Type is not supported. */ export class UnsupportedMediaTypeException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Unsupported Media Type". */ constructor(message = "Unsupported Media Type") { super(message); this.status = HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE; } } /** * Represents a 413 Payload Too Large Error. * Used when the request body exceeds server limits. */ export class PayloadTooLargeException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Payload Too Large". */ constructor(message = "Payload Too Large") { super(message); this.status = HttpStatusCodes.PAYLOAD_TOO_LARGE; } } /** * Represents a 507 Insufficient Storage Error. * Used when the server has insufficient storage to complete the request. */ export class InsufficientStorageException extends ErrorResponse { /** * @param message - Optional custom message. Defaults to "Insufficient Storage". */ constructor(message = "Insufficient Storage") { super(message); this.status = HttpStatusCodes.INSUFFICIENT_STORAGE; } } /** * Checks if an error is an instance of HttpError or its subclasses. * * @param error - The error to check. * @returns True if the error is an HttpError, false otherwise. */ export function isHttpError(error) { return error instanceof ErrorResponse; } /** * Creates an HTTP error with the specified status code and message. * Factory function for creating appropriate HTTP error instances. * * @param status - HTTP status code. * @param message - Optional custom error message. * @returns An instance of the appropriate HTTP error class. */ export function createHttpError(status, message) { switch (status) { case HttpStatusCodes.BAD_REQUEST: return new BadRequestException(message); case HttpStatusCodes.UNAUTHORIZED: return new UnauthorizedException(message); case HttpStatusCodes.FORBIDDEN: return new ForbiddenException(message); case HttpStatusCodes.NOT_FOUND: return new NotFoundException(message); case HttpStatusCodes.METHOD_NOT_ALLOWED: return new MethodNotAllowedException(message); case HttpStatusCodes.NOT_ACCEPTABLE: return new NotAcceptableException(message); case HttpStatusCodes.REQUEST_TIMEOUT: return new RequestTimeoutException(message); case HttpStatusCodes.CONFLICT: return new ConflictException(message); case HttpStatusCodes.GONE: return new HttpError(HttpStatusCodes.GONE, message || "Gone"); case HttpStatusCodes.PAYLOAD_TOO_LARGE: return new PayloadTooLargeException(message); case HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE: return new UnsupportedMediaTypeException(message); case HttpStatusCodes.UNPROCESSABLE_ENTITY: return new UnprocessableEntityException(message); case HttpStatusCodes.TOO_MANY_REQUESTS: return new TooManyRequestsException(message); case HttpStatusCodes.INTERNAL_SERVER_ERROR: return new InternalServerErrorException(message); case HttpStatusCodes.BAD_GATEWAY: return new BadGatewayException(message); case HttpStatusCodes.SERVICE_UNAVAILABLE: return new ServiceUnavailableException(message); case HttpStatusCodes.GATEWAY_TIMEOUT: return new GatewayTimeoutException(message); case HttpStatusCodes.INSUFFICIENT_STORAGE: return new InsufficientStorageException(message); default: return new HttpError(status, message || `HTTP Error ${status}`); } } /** * Type guard to check if an object has specific error properties. * * @param error - The object to check. * @returns True if object has error-like structure. */ export function hasErrorShape(error) { return (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string"); } /** * Safely extracts message from any error type. * * @param error - Any error object or value. * @returns A string error message. */ export function getErrorMessage(error) { if (typeof error === "string") { return error; } if (error instanceof Error) { return error.message; } if (hasErrorShape(error)) { return error.message; } return "Unknown error occurred"; } /** * Wraps a function and transforms any errors into HTTP errors. * Useful for API handlers to ensure consistent error responses. * * @param handler - The async function to wrap. * @returns A function that always returns or throws an HTTP error. */ export function withErrorHandling(handler) { return async (...args) => { try { return await handler(...args); } catch (error) { if (isHttpError(error)) { throw error; } // Log the original error (consider using a proper logger) getLogger().error("Caught error in handler:", error); // Extract status code if it exists, otherwise use 500 let status = HttpStatusCodes.INTERNAL_SERVER_ERROR; if (hasErrorShape(error) && typeof error.status === "number") { status = error.status; } // Create appropriate HTTP error throw createHttpError(status, getErrorMessage(error)); } }; } //# sourceMappingURL=exception.utils.js.map