Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 handling http response

I just have a question regarding structuring and handling responses from http requests within a service. I am using Angular2.alpha46 Typescript ( Just started testing it out- which I love... Ps.. Thank you all the people who have been working on it and contributing via github )

So take the following:

login-form.component.ts

import {Component, CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2'; import {UserService} from '../../shared/service/user.service'; import {Router} from 'angular2/router'; import {User} from '../../model/user.model'; import {APP_ROUTES, Routes} from '../../core/route.config';  @Component({     selector: 'login-form',     templateUrl: 'app/login/components/login-form.component.html',     directives: [CORE_DIRECTIVES, FORM_DIRECTIVES] })  export class LoginFormComponent {     user: User;     submitted: Boolean = false;      constructor(private userService:UserService, private router: Router) {         this.user = new User();     }      onLogin() {         this.submitted = true;          this.userService.login(this.user,             () => this.router.navigate([Routes.home.as]))     } } 

from this component I import my userService which will house my http request to login the user the service looks like this:

user.service.ts

import {Inject} from 'angular2/angular2'; import {Http, HTTP_BINDINGS, Headers} from 'angular2/http'; import {ROUTER_BINDINGS} from 'angular2/router'; import {User} from '../../model/user.model';  export class UserService {      private headers: Headers;      constructor(@Inject(Http) private http:Http) {     }      login(user: User, done: Function) {         var postData = "email=" + user.email + "&password=" + user.password;          this.headers = new Headers();         this.headers.append('Content-Type', 'application/x-www-form-urlencoded');          this.http.post('/auth/local', postData, {                 headers: this.headers             })             .map((res:any) => res.json())             .subscribe(                 data => this.saveJwt(data.id_token),                 err => this.logError(err),                 () => done()             );     }      saveJwt(jwt: string) {         if(jwt) localStorage.setItem('id_token', jwt)     }      logError(err: any) {         console.log(err);     } } 

What I want to do is to be able to handle the response the call returns after the http request. For instance if the user credentials are invalid I pass a 401 response back from the backend. My question is where is the best way to handle the response and return the result back to the component where i called the method from so I can manipulate the view to show either the success message or display an error message.

At the moment in my service under login I am currently not handling the response I am simply doing a callback back to the original component but I feel this isnt the correct way to go about it? Can someone shed some light on what they would do in this typical scenario? Would I handle the response in the first parameter of the subscribe function like:

 login(user: User, done: Function) {      var postData = "email=" + user.email + "&password=" + user.password;      this.headers = new Headers();     this.headers.append('Content-Type', 'application/x-www-form-urlencoded');      this.http.post('/auth/local', postData, {             headers: this.headers         })         .map((res:any) => res.json())         .subscribe(             (data) => {                 // Handle response here                 let responseStat = this.handleResponse(data.header)                  // Do some stuff                 this.saveJwt(data.id_token);                  // do call back to original component and pass the response status                 done(responseStat);             },             err => this.logError(err)         ); }  handleResponse(header) {     if(header.status != 401) {         return 'success'     }       return 'error blah blah' } 

Is a call back fine in this case or can this be handled better with an observable or a promise?

Concluding what I am asking is... What is the best practice to handle the response from the http response and handle the status in the view of the form from the user.service.ts back to the login-form.component.ts

like image 899
Nige Avatar asked Nov 26 '15 15:11

Nige


People also ask

How to handle HTTP error response?

When the error occurs in the HTTP Request it is intercepted and invokes the catchError . Inside the catchError you can handle the error and then use throwError to throw it to the service. We then register the Interceptor in the Providers array of the root module using the injection token HTTP_INTERCEPTORS .

How to handle error from api in Angular?

The basic way to handle errors in Angular is to use Angular's HttpClient service along with RxJS operators throwError and catchError. The HTTP request is made, and it returns the data with a response if anything wrong happens then it returns an error object with an error status code.

What is Httperrorresponse?

HttpErrorResponselink A response that represents an error or failure, either from a non-successful HTTP status, an error while executing the request, or some other failure which occurred during the parsing of the response.

What is HttpClient in Angular?

What Is HttpClient? HttpClient is a built-in service class available in the @angular/common/http package. It has multiple signature and return types for each request. It uses the RxJS observable-based APIs, which means it returns the observable and what we need to subscribe it.


2 Answers

Update alpha 47

As of alpha 47 the below answer (for alpha46 and below) is not longer required. Now the Http module handles automatically the errores returned. So now is as easy as follows

http   .get('Some Url')   .map(res => res.json())   .subscribe(     (data) => this.data = data,     (err) => this.error = err); // Reach here if fails 

Alpha 46 and below

You can handle the response in the map(...), before the subscribe.

http   .get('Some Url')   .map(res => {     // If request fails, throw an Error that will be caught     if(res.status < 200 || res.status >= 300) {       throw new Error('This request has failed ' + res.status);     }      // If everything went fine, return the response     else {       return res.json();     }   })   .subscribe(     (data) => this.data = data, // Reach here if res.status >= 200 && <= 299     (err) => this.error = err); // Reach here if fails 

Here's a plnkr with a simple example.

Note that in the next release this won't be necessary because all status codes below 200 and above 299 will throw an error automatically, so you won't have to check them by yourself. Check this commit for more info.

like image 167
Eric Martinez Avatar answered Oct 19 '22 17:10

Eric Martinez


in angular2 2.1.1 I was not able to catch the exception using the (data),(error) pattern, so I implemented it using .catch(...).

It's nice because it can be used with all other Observable chained methods like .retry .map etc.

import {Observable} from 'rxjs/Rx';     Http   .put(...)   .catch(err =>  {       notify('UI error handling');      return Observable.throw(err); // observable needs to be returned or exception raised   })   .subscribe(data => ...) // handle success 

from documentation:

Returns

(Observable): An observable sequence containing elements from consecutive source sequences until a source sequence terminates successfully.

like image 29
Sonic Soul Avatar answered Oct 19 '22 18:10

Sonic Soul