Not able to implement method decorators for catching http errors in Angular?

691 Views Asked by At

Actually I want to catch errors on all http requests using custom decorators.

My actual code looks like this:

  createRecord(data: data) {
    
    return this.httpClient.post(`${this.apiURL}/record/`, data);
  }

I want to convert these kind of functions to something like this:

 createRecord(data: data) {
        
        return this.httpClient.post(`${this.apiURL}/record/`, data)
               .pipe(tap((data)=>console.log(data)),catchError(handleError)));
      }

I know this is possible using http interceptors but I tried it using custom method decorators. My decorator looks like this:

export function CatchHttpError() : MethodDecorator {
    return function ( target : any, propertyKey : string, descriptor : PropertyDescriptor ) {
      const original = descriptor.value;
      descriptor.value = original()
      .pipe(
        tap((data)=>console.log('tap entered: data = ',data)),
        catchError(handleError)
      );
      return descriptor;
    };
  }

And then I decorate the function like this:

 @CatchHttpError()
  createRecord(data: data) {
    
    return this.httpClient.post(`${this.apiURL}/record/`, data);
  }

But the problem here is that it tries to execute the function then only when I initialize this particular service, not when I actually call createRecord method. How do I modify the method decorator to achieve this result?

1

There are 1 best solutions below

0
On BEST ANSWER

If you want the decorator to alter the behavior of the method it's applied on, you need to override the original method from within the decorator :

export function CatchHttpError() : MethodDecorator {
    return function (target : any, propertyKey : string, descriptor : PropertyDescriptor ) {
      const original = descriptor.value;
      // override the method
      descriptor.value = function(...args: any[]) {
            // Calling the original method
            const originalResults = original.apply(this, args);
            return originalReults.pipe(
                tap((data) => console.log('tap entered: data = ',data)),
                catchError(handleError)
            );
      }
}

Note that it's important to define the override with the function keyword and not an arrow function to be able to use the this of the class context.