UNPKG

@nestia/core

Version:

Super-fast validation decorators of NestJS

116 lines (104 loc) 3.55 kB
import { HttpError } from "@nestia/fetcher"; import { HttpException } from "@nestjs/common"; import { Creator } from "../typings/Creator"; /** * Exception manager for HTTP server. * * `ExceptionManager` is an utility class who can insert or erase custom error * class with its conversion method to a regular {@link nest.HttpException} * instance. * * If you define an API function through {@link TypedRoute} or * {@link EncryptedRoute} instead of the basic router decorator functions like * {@link nest.Get} or {@link nest.Post} and the API function throws a custom * error whose class has been {@link ExceptionManager.insert inserted} in this * `EntityManager`, the error would be automatically converted to the regular * {@link nest.HttpException} instance by the {@link ExceptionManager.Closure} * function. * * Therefore, with this `ExceptionManager` and {@link TypedRoute} or * {@link EncryptedRoute}, you can manage your custom error classes much * systemtically. You can avoid 500 internal server error or hard coding * implementation about the custom error classes. * * Below error classes are defaultly configured in this `ExceptionManager` * * - `typia.TypeGuardError` * - `@nestia/fetcher.HttpError` * * @author Jeongho Nam - https://github.com/samchon */ export namespace ExceptionManager { /** * Insert an error class with converter. * * If you've inserted an duplicated error class, the closure would be * overwritten. * * @param creator Target error class * @param closure A closure function converting to the `HttpException` class */ export function insert<T extends Error>( creator: Creator<T>, closure: Closure<T>, ): void { const index: number = tuples.findIndex((tuple) => tuple[0] === creator); if (index !== -1) tuples.splice(index, 1); tuples.push([creator, closure]); tuples.sort(([x], [y]) => (x.prototype instanceof y ? -1 : 1)); } /** * Erase an error class. * * @param creator Target error class * @returns Whether be erased or not */ export function erase<T extends Error>(creator: Creator<T>): boolean { const index: number = tuples.findIndex((tuple) => tuple[0] === creator); if (index === -1) return false; tuples.splice(index, 1); return true; } export function on(closure: (error: any) => any): void { listeners.add(closure); } export function off(closure: (error: any) => any): void { listeners.delete(closure); } /** * Type of a closure function converting to the regular * {@link nest.HttpException}. * * `ExceptionManager.Closure` is a type of closure function who are converting * from custom error to the regular {@link nest.HttpException} instance. It * would be used in the {@link ExceptionManager} with {@link TypedRoute} or * {@link EncryptedRoute}. */ export interface Closure<T extends Error> { /** * Error converter. * * Convert from custom error to the regular {@link nest.HttpException} * instance. * * @param exception Custom error instance * @returns Regular {@link nest.HttpException} instance */ (exception: T): HttpException; } /** @internal */ export const tuples: Array<[Creator<any>, Closure<any>]> = []; /** @internal */ export const listeners: Set<(error: any) => any> = new Set(); } ExceptionManager.insert( HttpError, (error) => new HttpException( { path: error.path, message: error.message, }, error.status, ), );