Angular2 maneja la respuesta http

Solo tengo una pregunta sobre la estructuración y el manejo de las respuestas de las solicitudes http dentro de un servicio. Estoy usando Angular2.alpha46 Typescript (Acabo de comenzar a probarlo, que me encanta … Ps. Gracias a todas las personas que han estado trabajando en ello y han contribuido a través de github)

Entonces tome lo siguiente:

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

desde este componente importo mi userService que alojará mi solicitud http para iniciar sesión en el usuario, el servicio se ve así:

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

Lo que quiero hacer es poder manejar la respuesta que devuelve la llamada después de la solicitud http. Por ejemplo, si las credenciales del usuario no son válidas, paso una respuesta 401 desde el back-end. Mi pregunta es dónde está la mejor manera de manejar la respuesta y devolver el resultado al componente desde el que llamé al método para poder manipular la vista y mostrar el mensaje de éxito o mostrar un mensaje de error.

Por el momento en mi servicio al iniciar sesión, actualmente no estoy manejando la respuesta. Simplemente estoy devolviendo la llamada al componente original, pero siento que esta no es la forma correcta de hacerlo. ¿Puede alguien arrojar algo de luz sobre lo que harían en este escenario típico? ¿Manejaría la respuesta en el primer parámetro de la función de suscripción como:

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

¿Se devuelve la devolución de la llamada en este caso o se puede manejar mejor con un observable o una promesa?

Concluyendo lo que estoy preguntando es … ¿Cuál es la mejor práctica para manejar la respuesta de la respuesta http y manejar el estado en la vista del formulario desde el usuario.service.ts de vuelta a login-form.component.ts

Actualizar alpha 47

A partir de alpha 47, la respuesta siguiente (para alpha46 y abajo) ya no es necesaria. Ahora el módulo Http maneja automáticamente los errores devueltos. Así que ahora es tan fácil como sigue

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

Alpha 46 y abajo

Puede manejar la respuesta en el map(...) antes 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 

Aquí hay un plnkr con un ejemplo simple.

Tenga en cuenta que en la próxima versión no será necesario porque todos los códigos de estado por debajo de 200 y por encima de 299 arrojarán un error automáticamente, por lo que no tendrá que comprobarlos usted mismo. Verifique este compromiso para más información.

en angular2 2.1.1 No pude detectar la excepción usando el patrón (datos), (error), así que lo implementé usando .catch (…).

Es bueno porque se puede usar con todos los demás métodos encadenados de Observable, como .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 

de la documentación :

Devoluciones

(Observable): Una secuencia observable que contiene elementos de secuencias fuente consecutivas hasta que una secuencia fuente finaliza con éxito.

El servicio :

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

En la aplicación:

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