Angular2 traitant la réponse http

J’ai juste une question concernant la structuration et la gestion des réponses des requêtes http au sein d’un service. J’utilise Angular2.alpha46 Typescript (je viens de commencer à le tester, ce que j’adore … Ps .. Merci à tous ceux qui y ont travaillé et qui ont consortingbué via github)

Alors, prenez ce qui suit:

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])) } } 

à partir de ce composant, j’importe mon userService qui hébergera ma requête http pour se connecter à l’utilisateur auquel le service ressemble:

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: ssortingng) { if(jwt) localStorage.setItem('id_token', jwt) } logError(err: any) { console.log(err); } } 

Ce que je veux faire, c’est être capable de gérer la réponse renvoyée par l’appel après la requête http. Par exemple, si les informations d’identification de l’utilisateur ne sont pas valides, je transmets une réponse 401 au serveur principal. Ma question est la suivante: quelle est la meilleure façon de gérer la réponse et de renvoyer le résultat au composant à partir duquel j’ai appelé la méthode afin que je puisse manipuler la vue pour afficher le message de réussite ou afficher un message d’erreur.

Pour le moment dans mon service sous login, je ne gère pas la réponse. Je fais simplement un rappel sur le composant d’origine, mais je pense que ce n’est pas la bonne façon de procéder. Quelqu’un peut-il éclairer ce qu’ils feraient dans ce scénario typique? Est-ce que je traiterais la réponse dans le premier paramètre de la fonction subscribe comme:

  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' } 

Un rappel est-il correct dans ce cas ou cela peut-il être mieux traité avec une observable ou une promesse?

Concluant ce que je demande, c’est … Quelle est la meilleure pratique pour gérer la réponse de la réponse http et gérer le statut dans la vue du formulaire depuis user.service.ts vers le formulaire de connexion.component.ts

Mettre à jour l’alpha 47

À partir de l’alpha 47, la réponse ci-dessous (pour alpha46 et inférieur) n’est plus requirejse. Maintenant, le module HTTP gère automatiquement les erreurs renvoyées. Alors maintenant, c’est aussi simple que cela

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

Alpha 46 et ci-dessous

Vous pouvez gérer la réponse dans la map(...) , avant de 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 

Voici un plnkr avec un exemple simple.

Notez que dans la prochaine version, cela ne sera pas nécessaire car tous les codes d’état inférieurs à 200 et supérieurs à 299 émettront automatiquement une erreur, vous n’aurez donc pas à les vérifier vous-même. Vérifiez cette validation pour plus d’informations.

dans angular2 2.1.1, je n’ai pas pu intercepter l’exception en utilisant le modèle (data), (erreur), donc je l’ai implémenté en utilisant .catch (…).

C’est bien car il peut être utilisé avec toutes les autres méthodes enchaînées Observable comme .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 

à partir de la documentation :

Résultats

(Observable): Une séquence observable contenant des éléments de séquences sources consécutives jusqu’à ce qu’une séquence source se termine avec succès.

Le service :

 import 'rxjs/add/operator/map'; import { Http } from '@angular/http'; import { Observable } from "rxjs/Rx" import { Injectable } from '@angular/core'; @Injectable() export class ItemService { private api = "your_api_url"; constructor(private http: Http) { } toSaveItem(item) { return new Promise((resolve, reject) => { this.http .post(this.api + '/items', { item: item }) .map(res => res.json()) // This catch is very powerfull, it can catch all errors .catch((err: Response) => { // The err.statusText is empty if server down (err.type === 3) console.log((err.statusText || "Can't join the server.")); // Really usefull. The app can't catch this in "(err)" closure reject((err.statusText || "Can't join the server.")); // This return is required to comstack but unuseable in your app return Observable.throw(err); }) // The (err) => {} param on subscribe can't catch server down error so I keep only the catch .subscribe(data => { resolve(data) }) }) } } 

Dans l’application:

 this.itemService.toSaveItem(item).then( (res) => { console.log('success', res) }, (err) => { console.log('error', err) } )