How to propagate errors through catchError() properly?

dc-p8 picture dc-p8 · May 11, 2018 · Viewed 22.3k times · Source

I wrote a function that is pipe-able:

HandleHttpBasicError<T>()
{
    return ((source:Observable<T>) => {
        return source.pipe(
            catchError((err:any) => {
                let msg = '';
                if(err && err instanceof HttpErrorResponse)
                {
                    if(err.status == 0)
                        msg += "The server didn't respond";
                }
                throw {
                    err,
                    msg
                } as CustomError
            })
        )

    })
}

I can use this function this way in my HttpService:

checkExist(id:string)
{
    return this.http.head<void>(environment.apiUrl + 'some_url/' + id)
        .pipe(
            HandleHttpBasicError(),
            catchError((err:CustomError) => {
                if(err.msg)
                    throw err.msg;
                if(err.err.status == HttpStatusCodes.NOT_FOUND)
                    throw("It doesn't exist.");
                throw(err);
            })

        )
}

It's working great. When I subscribe to checkExist(), I get a good error message, because HandleHttpBasicError first catches an error and throws it to the service's catchError(), which throwes the error message because it was not null.

This way, it allows me to have a global catchError() which handles error messages that will always be the same. In the future, I will do it in a HttpHandler, but that's not the point here.

Is it ok to chain the errors with the throw keyword?

I tried to return Observable.throwError(), but the browser said

Observable.throwError is not a function

My imports are import {Observable, of, throwError} from 'rxjs';.

Isn't it better to do this:

return ((source:Observable<T>) => {
        return source.pipe(
            catchError((err:any) => {
                msg = '';
                ...
                return of({err, msg} as CustomError)
                /* instead of
                throw(err)
                -or-
                return Observable.throwError(err) (which doesn't work)
                */
            })
        )

    })

?

Answer

Ingo B&#252;rk picture Ingo Bürk · May 11, 2018

Is it ok to chain the errors with the throw keyword ?

Yes, it's totally fine. rxjs try-catches such cases and converts it into an error notification.

I tryed to return Observable.throwError() but the browser say "Observable.throwError is not a function"

With rxjs6, the Observable prototype is no longer modified to contain operators or these »creation operators«, instead they are exposed as standalone functions. You can read more about it here, but the gist of it is that you'd just return throwError(…), e.g.

return source$.pipe(
  catchError(err => err.code === 404 
    ? throwError("Not found")
    : throwError(err)
  )
)