File

shared/common/catch-and-log-error.decorator.ts

Index

Properties

Properties

exclude
exclude: string[]
Type : string[]
Optional
syncFunc
syncFunc: string[]
Type : string[]
Optional
import { Logger } from "@nestjs/common";

export interface ApplyToAllOpts {
  syncFunc?: string[],
  exclude?: string[],
}

export const logError = (logger: Logger, name: string, error: any) =>
  logger.error(`[${name}]: ${error.message}`, error.stack);

/**
 * Decorator to wrap method with try catch
 *
 * @param serviceName {string} - name of class to for logger
 * @param rethrow {boolean} - re-throw exception, default false
 *
 */
export function CatchAndLogError(serviceName: string, rethrow = false) {
  return (
    target: any,
    propertyKey: string,
    propertyDescriptor: PropertyDescriptor
  ) => {
    const originalMethod = propertyDescriptor.value;

    propertyDescriptor.value = async function (...args: any[]) {
      try {
        return await originalMethod.apply(this, args);
      } catch (error) {
        const logger: Logger = new Logger(serviceName);

        logError(logger, originalMethod?.name, error);

        if (rethrow) throw error;
      }
    };
  };
}

/**
 * Decorator to apply decorator to all methods in class
 *
 * @param decorator {MethodDecorator} - decorator
 * @param opts {ApplyToAllOpts} - options to exclude methods, and sync functions:
 * exclude - array of strings with name of methods to exclude from apply
 * syncFunc - array of strings with name of sync methods to correctly apply decorator to them, or in another case sync methods will return the Promise
 *
 */
export const ApplyDecoratorToAll = (
  decorator: MethodDecorator,
  opts: ApplyToAllOpts,
) => {
  return (target: any) => {
    const descriptors = Object.getOwnPropertyDescriptors(target.prototype);

    for (const [propName, descriptor] of Object.entries(descriptors)) {
      const isMethod = descriptor.value instanceof Function &&
        propName != 'constructor';
      if (!isMethod) continue;
      if (opts?.exclude?.includes(propName)) continue;
      const originalMethod = descriptor.value;
      // apply decorator
      decorator(target, propName, descriptor)
      // copy metadata
      if (originalMethod != descriptor.value) {
        const metadataKeys = Reflect.getMetadataKeys(originalMethod);
        metadataKeys.map((key) => {
          const value = Reflect.getMetadata(key, originalMethod);
          Reflect.defineMetadata(key, value, descriptor.value);
        });
      }
      // Do not define property if sync function, or will be returned as promise
      if (opts?.syncFunc?.includes(propName)) continue;
      Object.defineProperty(target.prototype, propName, descriptor);
    }
  };
};

results matching ""

    No results matching ""