12 - HTTP

Uno de los modulos mas importantes de Angular tal vez sea el HTTP, como Angular esta dividido en modulos y para no hacer pesado el core, dividiendo todos por modulos de funcionalidad y este es el HTTP.

import { HttpModule } from '@angular/http';

Como ya sabemos este modulo se ingresa en el NgModule y una vez que lo tenemos vamos a poder trabajar con peticiones a servidores.

Tenemos varias formas de consumir data para nuestra app, la primera seria que tengamos en algun lado un json para poder consumirlo:

Esta constante tendra nuestros datos 'FAKES'

import { Heroe } from '../heroe';
export const HEROES: Heroe[] = [
  {id: 11, nombre: 'Mr. Nice'},
  {id: 12, nombre: 'Narco'},
  {id: 13, nombre: 'Bombasto'},
  {id: 14, nombre: 'Celeritas'},
  {id: 15, nombre: 'Magneta'},
  {id: 16, nombre: 'RubberMan'},
  {id: 17, nombre: 'Dynama'},
  {id: 18, nombre: 'Dr IQ'},
  {id: 19, nombre: 'Magma'},
  {id: 20, nombre: 'Tornado'}
];

Ahora desde el servicio vamos a consumir estos datos:

import { Injectable } from '@angular/core';
import { Heroe } from './heroe';
import { HEROES } from './mockups/mock-heroes';

@Injectable()
export class HeroeService {

  constructor() { }

  // retorno comun
  getHeroes(): Heroe[] {
    return HEROES;
  }
}

De estar forma cada vez que llegar a consumir el getHeroes, lo que va a pasar es que directamente se va a pasar esta Constante... osea este array de datos, se asignara directo al quien lo llame.

La segunda forma de consumir los datos es por medio del HttpModule.

Para ello mas alla de importalo vamos a tener que hacer algunas cosas mas.

Ahora vamos a ver un servicio, que ya tiene todo preparado para ahcer todas las llamadas necesarias.

Lo primero que voy a mencionar, es que tenemos dos formas de llamar a nuestra API, la primera es a travez de PROMISE ( si no sabes lo que es promise, te recomiendo que leas un poco sobre promise ) y la otra forma es por medio de los Observables.

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

import { TICKETS } from './mocks/tickets.mock';

@Injectable()
export class TicketService{

    urlBackEnd = "http://localhost:3000/";

    constructor(private http: Http){}


   getTicketsMongo (): Promise<any[]> {
    return this.http.get(this.urlBackEnd + 'tickets')
                    .toPromise()
                    .then(this.extractData)
                    .catch(this.handleError);
  }

  getTicketMongo(id:number):Promise<any[]>{
      return this.http.post(this.urlBackEnd+'ticket', {'id' : id})
                .toPromise()
                .then(this.extractData)
                .catch(this.handleError);
  }


    private extractData(res: Response) {
        let body = res.json();
        console.log("body", body);
        if (body.status == 200){
            return body.result;
        }
        else{
            return { };
        }
    }
    private handleError(error: Response | any){
        let errMsg:string;
        if(error instanceof Response){
            const body = error.json() || '';
            const err = body.error || JSON.stringify(body);
            errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
        }
        else{
            errMsg = error.message ? error.message : error.toString();
        }
        console.error(errMsg);
        return Observable.throw(errMsg);
    }


    getTicketObserver(id){
        return Observable.create(observer=>{
                        setTimeout(()=>{
                            observer.next(
                                TICKETS.find(
                                    (ticket)=>ticket.id == id
                                )
                            )
                    },3000);
        });
    }
} }

Bien vamos a dividir el ejemplo por partes:

Imports:

Injectable => este import lo usamos para poder hacer este servicio un singleton y que sobrevive alocado en la memoria mientras nuestra webapp este abierta.

Http, Response => estos imports los necesitamos para hacer las llamadas al mundo exterior, http nos sirve para hacer el llamado y response es el formato con el cual vamos a manejar el retorno de los datos.

Observable => es parte de RXJS y lo vamos a usar para las llamadas sobre los componentes reactivos, osea los observers, lo mismo asi con todos los los imports de RXJS.

Constructor:

En el constructor lo que hacemos es crear la variable HTTP, para poder utilizarla a lo largo de nuestra clase, y poder ir llamando al backend en el momento que queramos.

Funciones:

Vamos a ver las funciones, para ver lo que hacen y como lo hacen:

getTicketsMongo (): Promise<any[]> {
    return this.http.get(this.urlBackEnd + 'tickets')
                    .toPromise()
                    .then(this.extractData)
                    .catch(this.handleError);
  }

En esta función podemos ver que hacemos un get por medio de la variable http que creamos y que la devolución de todo esto va a ser un Promise.

Claro http, tiene => get, post, put, delete y maneja todo, le pasamos la url y tenemos la devolución.

private extractData(res: Response) {
        let body = res.json();
        console.log("body", body);
        if (body.status == 200){
            return body.result;
        }
        else{
            return { };
        }
    }

El contenido de la respuesta no es solo el contenido del JSON si no que tambien el status y todo lo que contiene la devolución de una petición HTTP.

Entonces lo que hacemos con extractData es obtener la respuesta, chequear que este todo bien (el status 200) y si es asi retornar el resultado, si no retornar un json vacio.. claro que esto depende de lo que queramos hacer por las especificaciones de nuestra app.

private handleError(error: Response | any){
    let errMsg:string;
    if(error instanceof Response){
        const body = error.json() || '';
        const err = body.error || JSON.stringify(body);
        errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    }
    else{
        errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
}

Ahora en el caso de que salga mal la llamada ( no que devuelva un error 500 por ejemplo) si no que falle algo, lo que podemos hacer es manejar el error, en esta funcion lo que hacemos es justamente esto... si el error viene como el tipo Response lo que vamos a hacer es directamente parsearlo para traer el error y si viene solo un texto de error , lo vamos a mostrar directamente.

getTicketMongo(id:number):Promise<any[]>{
return this.http.post(this.urlBackEnd+'ticket', {'id' : id})
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}

Por otro lado tenemos el post... para mostrar un ejemplo de pasaje de variables, en esta funcion lo que hacemos es un post y le enviamos los datos que necesitamos.

getTicketObserver(id){
        return Observable.create(observer=>{
                        setTimeout(()=>{
                            observer.next(
                                TICKETS.find(
                                    (ticket)=>ticket.id == id
                                )
                            )
                    },3000);
        });
    }

Por ultimo tenemos la función que se maneja por medio de los observables, pero la gran diferencia es que esta directamente crea un Observable y busca lo que necesita sobre nuestro fake... mas adelante con firebase veremos como funciona directamente... pero ahora es interesante saber que lo podemos manejar tranquilamente...

Por si no lo notaron todas las llamadas HTTP tiene un ".toPromise()" esto es porque en realidad el modulo HTTP de Angular se basa en observables, y si nosotros necesitamos transformarlo a promise tenemos que usar esa función.

Last updated