Error chaining from a service to component for a http.post subscription

Viewed 30

I am using firebase to authenticate a sign in and then send a request to my backend to create a custom session token for the logged in user. For this, I send in a function call from my component.ts to service.ts.



  SignIn(email: string, password: string) {
    return this.angularFireAuth
      .signInWithEmailAndPassword(email, password)
      .then(async res => {
        const idToken = await res.user.getIdToken()
        this.http.post(environment.baseURL + "auth/sessionLogin", { idToken: idToken }).pipe(
          catchError(err=>{
            return throwError("FailedLogin")   // ** NOT USEFUL ERROR 
          })
        )
        .subscribe((response) => {
          this.router.navigate(["/signup"]);    // ** IF SIGN IN IS SUCCESSFUL
        }
        // , (err) => {
        //   throw new Error("Failed Login").   // ** NOT USEFUL ERROR
        // }
      )
        return { loggedIn: false, message: "Failed Login" }   // ** INCASE MY BACKEND THROWS ERROR

      }).catch(err => {
        return { loggedIn: false, message: err.message }.  // ** INCASE FIREBASE THROWS ERROR

      });
  }

The component.ts code is

  async signIn(loginF: NgForm) {
    const email = loginF.value.email
    const password = loginF.value.password
    const response = await this.authenticationService.SignIn(email, password)
    if(!response.loggedIn){
      // my error handling code for flash messages
    }

  }

Now, the above code does the job, but I know that it's one of the worst ways of error handling as I am not using the observables to their fullest potential. I want to know how to use the catchError or perhaps try-catch blocks to not manually send and check a custom { loggedIn: false, message: err.message } like object to my component.

The catchErrors above are basically useless as they are not being forwarded to my component. If I return the this.http.post.., it says it is a subscription and I can't do a .then() on it + it says the response in my frontend would then either be of the type Subscription or of the type { loggedIn: false, message: err.message }

1 Answers

UPDATE : A POSSIBLE ANSWER

I have broken down the two things : signing in using firebase and then sending a request to backend for token into two different parts. It looks like a much more elegant solution for it doesn't involve any manual response object creation.

** component.ts**
  async signIn(loginF: NgForm) {
    const email = loginF.value.email
    const password = loginF.value.password
    let idToken
    try{
      idToken = await this.authenticationService.SignIn(email, password)
    }catch(err){
      idToken = null;         // ** INCASE FIREBASE FAILS
      // error handling for flash messages
    }


    if(idToken!= null){
      this.authenticationService.SignInBackend(idToken).subscribe((response) => {
        this.router.navigate(["/signup"]);
      }
      , (err) => {
        // error handling for flash messages // ** INCASE BACKEND FAILS
      }
    )
    }

  }
** service.ts**
SignIn(email: string, password: string) {
    return this.angularFireAuth
      .signInWithEmailAndPassword(email, password)
      .then(async res => {
        const idToken = await res.user.getIdToken()
        return idToken;
      }).catch(err => {
        throw new Error(err.message).      // ** ERROR GETS CHAINED
      });
  }

  SignInBackend(idToken){
    return this.http.post(environment.baseURL + "auth/sessionLogin", { idToken: idToken })

  }
Related