3

I'm new to Angular/Typescript and using catchError RxJs. I'm also using .subscribe and pipe operators. I would like to use observable as much as possible, combining it with RxJS operators. On submission of my form, frontend calls the API and a new product gets created and would like to have proper error handling for Error Codes of 400 and 500 using HttpErrorResponse. I wrote below code but not sure if I'm doing the error handling correctly as I get the below error (see bottom).

app.component.ts

onSubmit(): void {
    if (this.form.valid) {
        console.log('Creating product:', this.form.value);
        this.http.post('/api/create', {
            productName: this.form.value.productName,
        }).pipe(catchError(err => {
            if(err instanceof HttpErrorResponse && err.status == 500 || err.status == 502 || err.status == 503) {
                this.err = "Server Side Error";
                return throwError(err);;
            }
            else if(err instanceof HttpErrorResponse && err.status == 400){
                this.err = "Bad Request";
                return throwError(err);;
            } else if(err instanceof HttpErrorResponse && err.status == 422){
                this.err = "Unprocessable Entity - Invalid Parameters";
                return throwError(err);;
            }
        })
          .subscribe(
            resp => this.onSubmitSuccess(resp), err => this.onSubmitFailure(err)
        );
    }
    this.formSubmitAttempt = true;
}

private onSubmitSuccess(resp) {
    console.log('HTTP response', resp);
    this.productID = resp.projectID;
    this.submitSuccess = true;
    this.submitFailed = false;
}

private onSubmitFailure(err) {
    console.log('HTTP Error', err);
    this.submitFailed = true;
    this.submitSuccess = false;
}

Errors:

app.component.ts - error TS2339: Property 'err' does not exist on type 'AppComponent'.

app.component.ts:124:16 - error TS2339: Property 'subscribe' does not exist on type 'OperatorFunction'.}).subscribe(

1 Answer 1

4

To solve your issue, I have modified the code and shown below.

onSubmit(): void {
  if (this.form.valid) {
    console.log('Creating product:', this.form.value);
    this.http.post('/api/create', {
      productName: this.form.value.productName,
    }).pipe(catchError(errorResponse => {

      const err = <HttpErrorResponse>errorResponse;

      if (err && err.status === 422) {
        this.err = "Unprocessable Entity - Invalid Parameters";
        return throwError(err);
      } else if (err && err.status === 400) {
        this.err = "Bad Request";
        return throwError(err);;
      } else if (err && err.status === 404) {
        this.err = "Not found";
        return throwError(err);;
      } else if (
        err &&
        (err.status < 200 || err.status <= 300 || err.status >= 500)
      ) {
        this.err = "Server Side Error";
        return throwError(err);;
      }
    })
    .subscribe(
      resp => this.onSubmitSuccess(resp), err => this.onSubmitFailure(err)
    );
  }
  this.formSubmitAttempt = true;
}

I would suggest creating a common exception service that handles any exception. You should separate the outgoing API calls to a separate service and then use that in your component. It will be easy to read and maintain the code. Try the below code logic.

import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

@Injectable()
export class ExceptionService {
  constructor(private toastService: ToastService) {}

  catchBadResponse: (errorResponse: any) => Observable<any> = (
    errorResponse: any
  ) => {
    let res = <HttpErrorResponse>errorResponse;
    let err = res;
    let emsg = err
      ? err.error
        ? err.error
        : JSON.stringify(err)
      : res.statusText || 'unknown error';
    console.log(`Error - Bad Response - ${emsg}`);
    return of(false);
  };
}

In your service, you can create a post method like this

saveEntity(entityToSave: EntityToSave) {
  return <Observable<EntityToSave>>(
    this.http.post(`${postURL}`, entityToSave).pipe(
      map((res: any) => <EntityToSave>res),
      catchError(this.exceptionService.catchBadResponse),
      finalize(() => console.log('done'))
    )
  );
}

From your component, call the service which handles the exception

this.yourService.saveEntity(entityToSave).subscribe(s => {
  // do your work... this get called when the post call was successful
});

I hope it solve your issue.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.