0

I am implementing login for my nifty new Angular app, and sending login/signup requests to my backend with an @angualar/http post request, doing what I think is a standard post-map-catch paradigm.

My first test was to see how nicely it caught the error when the backend API was not available, and I was surprised and disappointed to find that the '.catch' mechanism didn't do a very good job, and did not catch the underlying error -- instead catching an ugly error Response object.

Here's my code for my LoginService that's being invoked from the component that handles login/signup

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { User } from '../models/user';

@Injectable()
export class LoginService {

private loginUrl = 'http://localhost:300/api/login';
private signupUrl = 'http://localhost:300/api/signup';

//_____________________________________________________________
// Public interface
constructor(private http: Http) {}

LoginUser(user: User): Observable<LoginResponse> {
    console.log('LoginService: login request for user %s', user.email);
    return this.http.post(this.loginUrl, user)
        .map(this.parseData)
        .catch(this.handleError);
}

SignupUser(user: User): Observable<SignupResponse> {
    console.log('LoginService: signup request for user %s', user.email);
    return this.http.post(this.signupUrl, user)
        .map(this.parseData)
        .catch(this.handleError);
}

//__________________________________________________________________
// Private interface
private parseData(res: Response)  {
    console.log('LoginService: received response %s', res.json());
    return res.json() || {};
}

private handleError(error: Response | any) {
    let errorMessage: string;
    errorMessage = error.message ? error.message : error.toString();
    console.error('LoginService: error: %s', errorMessage);
    return Observable.throw(errorMessage);
}

}

export class LoginResponse {
   // TODO: implement
   foo: number;
}

export class SignupResponse {
   // TODO: implement
   foo: number;
}

I am purposely testing using a low-numbered port (300) where nothing is listening (and likely access would be denied anyway).

What I see in the Chrome browser console is a very nice error that gets raised:

Nice ERR_CONNECTION_RESET error

Followed by the ugly error that ends up getting caught by the .catch() and then logged:

Ugly error

This stackoverflow post helpfully lets me know "You can probably check the status of the ResponseError. When an API is offline that is 0"...which is true, so that's nice.

Why doesn't the nice (at least 'nicer') error get caught and packaged up for the catch? Or perhaps it does get caught and the underlying CONNECTION_RESET part is simply thrown away, along with the URL (I found the for URL: null pretty amusing), and a more nebulous Response object is constructed in order to make it harder for me to concoct a nice error message for my users?

sjtitus
  • 101
  • 7
  • 1
    https://angular.io/guide/http#error-handling – Vikas Mar 30 '18 at 17:45
  • Thx Vikas, very helpful, obviously (wasn't as thorough prior to asking as I should have been). Looks like a robust solution is going to be post-map-pipe-catch -- and hopefully I can make the pipe bit pass through the situations (like 500 errors, etc) that are well-handled already. – sjtitus Mar 30 '18 at 18:21
  • you're welcome mate:) – Vikas Mar 30 '18 at 18:24

0 Answers0