Tutorial de IONIC: Peticiones http

Hola a todos, hoy vamos a ver cómo podemos comunicar una aplicación desarrollada con ionic con una API REST, para ello vamos a aprender cómo realizar peticiones a un servidor remoto a través de http.

En el siguiente enlace tienes el índice para acceder al resto de entradas de este tutorial:

En esta pequeña prueba vamos acceder a una API REST para obtener desde un servidor remoto un listado de usuarios. Para este pequeño ejemplo vamos a utilizar RANDOM USER GENERATOR que como se indica en su web es una API libre de código abierto para generar datos de usuario aleatorios para realizar pruebas. Cómo Lorem Ipsum, pero con personas.

Lo que vamos a hacer es simplemente realizar una llamada a esta API donde recibiremos como respuesta un listado de usuarios que mostraremos en nuestra vista.

Antes de nada vamos a crear una nueva aplicación de prueba:

ionic start pruebahttp1 blank

Seleccionamos Angular como framework pulsando enter y le podemos decir que no queremos integrarlo con Capacitor, si deseas probarlo desde un dispositivo móvil entonces le diremos que sí, aunque puedes integrarlo después si lo deseas.

Una vez generado el proyecto como siempre desde el terminal con cd pruebahttp1 entramos dentro de la carpeta que acabamos de crear.

Ahora vamos a crear un servicio donde gestionaremos la comunicación con el servidor remoto:

ionic g service services/http

Se habrá creado una carpeta services y dentro  un archivo .ts con el nombre http.service.ts.

Por defecto contendrá el siguiente código:

import { Injectable } from '@angular/core';
 
@Injectable({
 providedIn: 'root'
})
export class HttpService {
 
 constructor() { }
}

Para realizar las peticiones al servidor vamos a utilizar un paquete de angular llamado HttpClient, así que vamos a importarlo en nuestro servicio:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class HttpService {

  constructor(public http: HttpClient) { }
}

Ahora debemos importar y declarar como provider en app.module.ts el servicio que acabamos de crear, también debemos importar y declarar en los imports HttpClientModule:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { HttpService } from './services/http.service';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    HttpService,
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

http.get

Vamos a añadir un método que llamaremos loadUsers a nuestro servicio para obtener la lista de usuarios desde el servidor, por lo tanto editamos el archivo http.service.ts y añadimos el siguiente función después del constructor:

 loadUsers() {
   return this.http
   .get('https://randomuser.me/api/?results=25')
 }

 En este caso llamamos a randomuser y le decimos que devuelva 25 resultados (?results=25).

http.get devuelve el resultado de la solicitud en forma de un observable.

Como resultado de la petición obtendremos un JSON con un formato parecido a este:

{
 "results":[
   {
     "gender":"male",
     "name":{"title":"mr","first":"denis","last":"vieira"},
     "location":{
       "street":"666 rua sete de setembro ",
       "city":"rondonópolis",
       "state":"minas gerais",
       "postcode":44819,
       "coordinates":{"latitude":"-73.8339","longitude":"-19.7138"},
       "timezone":{"offset":"-2:00","description":"Mid-Atlantic"}
     },
     "email":"denis.vieira@example.com",
     "login":{
       "uuid":"4f51bc76-8f49-4043-841d-7b2978bd7665",
       "username":"beautifulswan509",
       "password":"down",
       "salt":"I9rLbtmc",
       "md5":"3689e6b1cb08345ac5ab67b179358250",
       "sha1":"4f0e8bf0fea756dbaa8f4e7e01b7c6a8de328abf",
       "sha256":"a23a5af4e8622e69c464a2a30f608066e77aa8d36f037ecdb171d452b20e5c96"
     },
     "dob":{"date":"1984-02-04T02:47:36Z","age":35},
     "registered":{"date":"2004-07-29T23:10:42Z","age":14},
     "phone":"(45) 7844-4365",
     "cell":"(73) 5854-2157",
     "id":{"name":"","value":null},
     "picture":{
       "large":"https://randomuser.me/api/portraits/men/62.jpg",
       "medium":"https://randomuser.me/api/portraits/med/men/62.jpg",
       "thumbnail":"https://randomuser.me/api/portraits/thumb/men/62.jpg"
     },
     "nat":"BR"
   }, ...

Ahora vamos a crear la vista en home.page.html para mostrar un botón que llamará a la función cargarUsuarios, y un listado de items con los usuarios que crearemos recorriendo con *ngFor el array usuarios que posteriormente vamos a crear en el controlador:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Usuarios
   </ion-title>
 </ion-toolbar>
</ion-header>

<ion-content>
 <ion-list>
   <ion-item *ngFor="let usuario of usuarios">
     <ion-avatar slot="start">
       <img [src]="usuario.picture.medium">
     </ion-avatar>
     <ion-label>
     <h2>{{ usuario.name.first }}</h2>
     <p>{{ usuario.email }}</p>
   </ion-label>
   </ion-item>
 </ion-list>
 <ion-button expand="block" (click) = "cargarUsuarios()">Cargar Usuarios</ion-button>
</ion-content>

Vamos a modificar home.page.ts para obtener los datos desde el servicio y mostrarlos en la vista para ello editamos home.page.ts e importamos el service httpProvider que acabamos de crear:

import { HttpService } from '../services/http.service';

Para poder utilizarlo debemos inyectarlo en el constructor:

constructor(private http: HttpService) {}

Justo antes del constructor vamos a definir una variable miembro donde guardaremos el array de usuarios que recibamos desde el servidor:

...
export class HomePage {

 usuarios: any[];

 constructor(private http: HttpService) {}
...

Ahora vamos a crear un método en home.page.ts que que a su vez llamará al método loadUsers de nuestro provider para recibir los datos de los usuarios:

cargarUsuarios(){
  this.http.loadUsers().subscribe(
    (res: any) => {
      this.usuarios = res.results;
    },
    (error) =>{
      console.error(error);
    }
  );
}

Como podemos observar llamamos al método loadUsers que hemos definido en el servicio, pero no utilizamos then sino subscribe, esto es porque http no devuelve una promesa si no que devuelve un observable. Un observable se queda a la espera de recibir datos y nosotros nos “suscribimos” recibiendo estos datos en cuanto estén disponibles.

Esta cualidad se puede utilizar para suscribirnos a una url y observar si ha habido cambios, como por ejemplo si es un sitio de noticias donde se están continuamente renovando.

La diferencia entre promesas y observables a groso modo es que la promesa devuelve los datos una única vez cuando estos son recibidos mientras que un observable se queda “vigilando” si se han producido cambios y se ejecuta cada vez que un cambio se produce, aunque hasta que no te suscribes a un observable éste no se ejecutará.

Si solo necesitamos recibir los datos una única vez sin necesidad de observar si se han producido cambios podemos utilizar promesas. Una promesa se ejecuta una vez que se haya resuelto la llamada y recibimos los datos en la función .then(res=>{… }).

El código del provider en el archivo http.ts utilizando una promesa quedaría de la siguiente manera:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
 
 
@Injectable({
 providedIn: 'root'
})
export class HttpService {
 
 constructor(public http: HttpClient) { }
 
 loadUsers() {
   return this.http
   .get('https://randomuser.me/api/?results=25').toPromise();
 
 }
 
}

Simplemente  debemos añadir toPromise() después del get.

Ahora en home.ts solo tenemos que sustituir subscribe por then:

cargarUsuarios(){
  this.http.loadUsers().then(
    (res: any) => {
      this.usuarios = res.results;
    },
    (error) =>{
      console.error(error);
    }
  );
}

Si ejecutamos la aplicación con ionic serve y pulsamos en el botón Cargar Usuarios podremos ver algo como esto:

 

Podéis observar como cada vez que pulsemos el botón la lista de usuarios cambia ya que Random User Generator como su propio nombre indica devuelve una lista aleatoria de usuarios.

http.post

RANDOM USER GENERATOR  nos ha servido para aprender ha hacer una petición get a una API REST para recibir datos, en este caso una lista de usuarios.

Si queremos conectarnos con un servicio que tengamos corriendo en un servidor remoto y necesitamos pasarle datos desde la aplicación para que se guarden en el servidor tenemos que usar http.post.

Vamos a imaginar que tenemos corriendo un servicio en PHP cuya url sea https://www.miservicio.com/adduser/ que está programado para recibir vía post un nuevo usuario para guardarlo en la base de datos del servidor.

En nuestro servicio tendremos que crear una función similar a esta:

postDatos() {
  const datos = { nombre: 'Edu', email: 'edu.revilla.vaquero@gmail.com'};

  const options = {
     headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    }
  };

  const url = 'https://www.miservicio.com/adduser/';

  return this.http.post(url, JSON.stringify(datos), options).toPromise();
}

En la variable datos  tenemos un objeto con los datos del usuario que queremos enviar al servidor, en este caso nombre y email.

Después definimos la variable options donde a su vez definimos las cabeceras en la variable headers, dependiendo de la configuración del servidor podría necesitar parámetros diferentes en la cabecera.

Como vemos http.post es bastante parecido a http.get, solo que como segundo parámetro le pasamos la variable que contiene los datos que queremos enviar convertida a formato JSON con JSON.stringify(datos), como tercer parámetro le pasamos options.

En data recibiremos la respuesta que nos de el servidor.

Vamos a ver un ejemplo de cómo obtendremos los datos enviados desde nuestra aplicación con un servicio desarrollado en PHP en el servidor:

<?php
  header('Access-Control-Allow-Origin: *');
 
  $postdata = file_get_contents("php://input");
  if (isset($postdata)) {
   $request = json_decode($postdata);
   $request->recibido = 'OK';
   echo json_encode($request);
  }
 
?>

Por seguridad muchos sitios solo admiten peticiones que se hagan desde su propio dominio,  para no tener problemas de Cross-Origin en la primera línea le asignamos la opción header para indicarle que está permitido cualquier origen:

header('Access-Control-Allow-Origin: *');

También hay que tener en cuenta que el navegador puede bloquear peticiones a dominios que no sean https, por lo que sí estás intentando acceder a un servidor que no tenga activado https puede que el navegador bloquee la petición y te muestre un error en consola.

Si vas a hacer pruebas en un servidor local existen complementos para Chrome que evita el bloqueo de las peticiones Cross-Origin.

 

En este ejemplo tan sencillo lo único que hacemos en la siguiente línea es recoger los datos que hemos enviado desde la aplicación:

$postdata = file_get_contents("php://input");

Después miramos si no está vacío $postdata y en $request guardamos el objeto resultante al decodificar el json.

$request = json_decode($postdata);

Le añadimos una propiedad más al objeto para indicar que hemos recibido la petición:

$request->recibido = 'OK';

Por último simplemente sacamos un echo de $request convertido de nuevo a json.

Es decir que recibiremos como resultado en la app lo mismo que hemos enviado más un campo recibido que contendrá la palabra ‘OK’.

Evidentemente en otros lenguajes de programación del lado del servidor el código para recibir los datos sería diferente, pero se escapa del propósito de este libro el abordar como sería en cada lenguaje.

Para probar esto podemos añadir un botón al al home.page.ts del ejemplo anterior y que llame a una función de definiremos después en el controlador:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Usuarios
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 <ion-list>
   <ion-item *ngFor="let usuario of usuarios">
     <ion-avatar slot="start">
       <img [src]="usuario.picture.medium">
     </ion-avatar>
     <ion-label>
     <h2>{{ usuario.name.first }}</h2>
     <p>{{ usuario.email }}</p>
   </ion-label>
   </ion-item>
 </ion-list>
 <ion-button expand="block" (click) = "cargarUsuarios()">Cargar Usuarios</ion-button>
 <ion-button expand="block" (click) = "post()">Peticion POST</ion-button>
</ion-content>

Definimos entonces la función post en home.page.ts:

post() {
    this.http.postDatos().then(res=>{
      alert(JSON.stringify(res));
    })
 }

Esta función simplemente va a realizar una llamada a la función postDatos que tendremos creada en nuestro servicio http y saca un alert del resultado obtenido convirtiéndolo a texto utilizando el método stringify de JSON.

Si no tienes la posibilidad de tener un servidor para hacer pruebas puedes utilizar algún servicio online que te permite hacer pruebas como por ejemplo http://httpbin.org, pudiendo quedar el método postDatos de nuestro servicio de la siguiente manera:

postDatos() {
   const datos = { nombre: 'Edu', email: 'edu.revilla.vaquero@gmail.com'};
 
   const options = {
     headers: {
       'Content-Type': 'application/x-www-form-urlencoded'
     }
   };
 
   const url = 'http://httpbin.org/post';
 
   return this.http.post(url, JSON.stringify(datos), options).toPromise();
 }

Si quieres saber más sobre el desarrollo de aplicaciones con IONIC puedes adquirir mi libro, es esta entrada puedes ver el índice de contenidos del libro:

Libro: Desarrollo de aplicaciones móviles multiplataforma y PWAs con Ionic y Firebase desde cero.

Muchas gracias

Un saludo, y si aún no lo has hecho no olvides suscribirte a mi blog para no perderte los próximos posts  :-),

También puedes seguirme en Twitter en ‎@revigames y no olvides que me ayudas mucho si compartes este post en las redes sociales.

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.