Ajax con AngularJS para acceso a API

  • Por
Nos introducimos en el uso de Ajax mediante AngularJS. Lo vamos a hacer de una manera muy habitual en el desarrollo con este framework que es accediendo a un servicio web que nos ofrece un API REST.

A la vez que aprendemos técnicas de Ajax vamos a repasar diversas de las prácticas que ya te hemos ido contando a lo largo del Manual de AngularJS.

Ya lo sabes, Ajax es una solicitud HTTP realizada de manera asíncrona con Javascript, para obtener datos de un servidor y mostrarlos en el cliente sin tener que recargar la página entera. Además para los despistados que no lo sepan todavía, tenemos un artículo que te explica muy bien qué son exactamente las API REST.

Service $http

El servicio $http (service en inglés, tal como se conoce en AngularJS) es una funcionalidad que forma parte del núcleo de Angular. Sirve para realizar comunicaciones con servidores, por medio de HTTP, a través de Ajax y vía el objeto XMLHttpRequest nativo de Javascript o vía JSONP.

Después de esa denominación formal, que encontramos en la documentación de AngularJS, te debes de quedar por ahora en que nos sirve para realizar solicitudes y para ello el servicio $http tiene varios tipos de acciones posibles. Todos los puedes invocar a través de los parámetros de la función $http y además existen varios métodos alternativos (atajos o shortcuts) que sirven para hacer cosas más específicas.

Entre los shortcuts encuentras:

$http.get()
$http.post()
$http.put()
$http.delete()
$http.jsonp()
$http.head()
$http.patch()

Tanto el propio $http() como las funciones de atajos te devuelven un objeto que con el "patrón promise" te permite definir una serie de funciones a ejecutar cuando ocurran cosas, por ejemplo, que la solicitud HTTP se haya resuelto con éxito o con fracaso.

Nota: Si vienes de jQuery ya habrás podido experimentar las promesas "promise" en las llamadas a la función $.ajax, $.get, $post, etc. En AngularJS funciona de manera muy similar.

El service $http es bastante complejo y tiene muchas cosas para aportar soluciones a las más variadas necesidades de solicitudes HTTP asíncronas. De momento nos vamos a centrar en lo más básico que será suficiente para realizar un ejemplo interesante.

Inyección de dependencias con $http

Si vas a querer usar el servicio $http lo primero que necesitarás será inyectarlo a tu controlador, o a donde quiera que lo necesites usar. Esto es parecido a lo que mostramos cuando estábamos practicando con controladores e inyectábamos el $scope.

angular
    .module('apiApp', [])
    .controller('apiAppCtrl', ['$http', controladorPrincipal] );

Como puedes ver, en la función de nuestro controlador, llamada controladorPrincipal, le estamos indicando que recibirá un parámetro donde tiene que inyectar el service $http.

Al declarar la función recibirás esa dependencia como parámetro.

function controladorPrincipal($http){

Ahora, dentro del código de ese controlador podrás acceder al servicio $http para realizar tus llamadas a Ajax.

Realizar una llamada a $http.get()

El método get() sirve para hacer una solicitud tipo GET. Recibe diversos parámetros, uno obligatirio, que es la URL y otro opcional, que es la configuración de tu solicitud.

$http.get("http://www.example.com")

Lo interesante es lo que nos devuelve este método, que es un objeto "HttpPromise", sobre el cual podemos operar para especificar el comportamiento de nuestra aplicación ante diversas situaciones.

Respuesta en caso de éxito

De momento, veamos qué deberíamos hacer para especificarle a Angular lo que deve de hacer cuando se reciba respuesta correcta del servidor.

$http.get(url)
.success(function(respuesta){
//código en caso de éxito
});

Como puedes ver en este código es que $http nos devuelve un objeto. Sobre ese objeto invocamos el método success() que sirve para indicarle la función que tenemos que ejecutar en caso de éxito en la solicitud Ajax. Esa función a su vez recibe un parámetro que es la respuesta que nos ha devuelto el servidor.

Nota: En Angualar 1.4 cambiaron el estándar de respuesta en caso de éxito o fracaso de la conexión Ajax. El nuevo mecanismo es bastante parecido, con funciones callback que se cargan a partir del método then(). Lo tienes descrito con ejemplos en el artículo de Estándar del patrón promise para los métodos del servicio $http en Angular 1.4.

Ejemplo completo de solicitud Ajax con $http

Vistos estos nuevos conocimientos sobre el "service" $http estamos en condiciones de hacer un poco de Ajax para conectarnos con un API REST que nos ofrezca unos datos. Esos datos son los que utilizaremos en nuestra pequeña aplicación para mostrar información.

Nota: Vamos a usar un API llamada REST Countries, que puedes encontrar en http://restcountries.eu/

Este API nos devuelve JSON con datos sobre los países del mundo. En principio puedes hacer diversas operaciones con los comandos sobre el API, pero vamos a ver solamente unas pocas que nos permiten recibir los datos de los países agrupados por regiones.

Las URL que usaremos para conectarnos al API son como estas:

http://restcountries.eu/rest/v1/region/africa
http://restcountries.eu/rest/v1/region/europe

Puedes abrirlas en tu navegador y observar cómo la respuesta es un conjunto de datos en notación JSON.

Aunque sencilla, esta aplicación ya contene varias cosillas que para una mejor comprensión conviene ver por separado.

Este es nuestro HTML:

<div ng-app="apiApp" ng-controller="apiAppCtrl as vm">
  <h1>Pruebo Ajax</h1>
  <p>
      Selecciona:
      <select ng-model="vm.url" ng-change="vm.buscaEnRegion()">
       <option value="http://restcountries.eu/rest/v1/region/africa">Africa</option>
        <option value="http://restcountries.eu/rest/v1/region/europe">Europa</option>
        <option value="http://restcountries.eu/rest/v1/region/americas">America</option>
      </select>
  </p>
  <ul>
      <li ng-repeat="pais in vm.paises">
        País: <span>{{pais.name}}</span>, capital: {{pais.capital}}
      </li>
  </ul>
</div>

Puedes fijarte que tenemos un campo SELECT que nos permite seleccionar una región y para cada uno de los OPTION tenemos como value la URL del API REST que usaríamos para obtener los países de esa región.

Aprecia que en el campo SELECT está colocada la directiva ngChange, que se activa cuando cambia el valor seleccionado en el combo. En ese caso se hace una llamada a un método llamado buscaEnRegion() que veremos luego escrito en nuestro controlador.

También encontrarás una lista UL en la que tienes una serie de elementos LI. Esos elementos LI tienen la directiva ngRepeat para iterar sobre un conjunto de países, de modo que tengas un elemento de lista por cada país.

Ahora puedes fijarte en el Javascript:

angular
    .module('apiApp', [])
    .controller('apiAppCtrl', ['$http', controladorPrincipal]);

function controladorPrincipal($http){
    var vm=this;
    
    vm.buscaEnRegion = function(){
        $http.get(vm.url).success(function(respuesta){
            //console.log("res:", respuesta);
            vm.paises = respuesta;
        });
    }
}

Creamos un module y luego un controlador al que inyectamos el $http como se explicó al inicio del artículo.

Luego, en la función que construye el controlador, tenemos un método que se llama buscaEnRegion() que es el que se invoca al modificar el valor del SELECT. Ese método es el que contiene la llamada Ajax.

Realmente el Ajax de este ejercicio se limita al siguiente código:

$http.get(vm.url).success(function(respuesta){
//console.log("res:", respuesta);
vm.paises = respuesta;
});

Usamos el shortcut $http.get() pasando como parámetro la URL, que sacamos del value que hay marcado en el campo SELECT del HTML. Luego se especifica una función para el caso "success" con el patrón "promise". Esa función devuelve en el parámetro "respuesta" aquello que nos entregó el API REST, que es un JSON con los datos de los países de una región. En nuestro ejemplo, en caso de éxito, simplemente volcamos en un dato del modelo, en el "scope", el contenido de la respuesta.

En concreto ves que la respuesta se vuelca en la variable vm.paises, que es justamente la colección por la que se itera en el ng-repeat de nuestro HTML.

Código completo del ejercicio

Quizás se puede ver y entender mejor el ejercicio en global si vemos el código completo de una sola vez. Pero ya sabes que para aprender bien las cosas debes practicar por tu cuenta, creando ahora tu propio ejemplo Ajax, accediendo a este API REST o a cualquier otra que te apetezca. Verás que es muy sencillo y con poco código puedes hacer cosas bastante más espectaculares de lo que nosotros hemos realizado en este ejemplo.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Probando Ajax en AngularJS</title>
    <style>
        body{ font-family: sans-serif;}
        li{
            font-size: 0.8em;
        }
        li span{
            font-weight: bold;
        }
    </style>
</head>
<body>
<div ng-app="apiApp" ng-controller="apiAppCtrl as vm">
  <h1>Pruebo Ajax</h1>
  <p>
      Selecciona:
      <select ng-model="vm.url" ng-change="vm.buscaEnRegion()">
       <option value="http://restcountries.eu/rest/v1/region/africa">Africa</option>
        <option value="http://restcountries.eu/rest/v1/region/europe">Europa</option>
        <option value="http://restcountries.eu/rest/v1/region/americas">America</option>
      </select>
  </p>
  <ul>
      <li ng-repeat="pais in vm.paises">País: <span>{{pais.name}}</span>, capital: {{pais.capital}}</li>
  </ul>

</div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js"></script>
    <script>
    angular
        .module('apiApp', [])
        .controller('apiAppCtrl', ['$http', controladorPrincipal]);

    function controladorPrincipal($http){
        var vm=this;
        
        vm.buscaEnRegion = function(){
            $http.get(vm.url).success(function(respuesta){
                //console.log("res:", respuesta);
                vm.paises = respuesta;
            });
        }
    }

    </script>
</body>
</html>

En el siguiente artículo explicaremos cómo acceder por Ajax a un JSON pero con JSONP.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

juan_c

03/11/2014
$scope vs this?
Hola, en los artículos veo que usas "this" dentro de los controladores en vez de "$scope" (tal y como se puede ver en otros tutoriales que uno encuentra por ahí), ¿qué ventajas tiene? Gracias

midesweb

04/11/2014
$scope y this
Hola,
Uso this para darle un contexto al scope.
$scope hace referencia en Angular al scope global, que puedes inyectar en un controlador si deseas. Sin embargo no es siempre necesario y usando this creas los datos para tu vista sin necesidad de guardarlos en el scope global.
Puedes hacer ambas cosas, pero con this tus datos tendrán un ámbito más reducido, lo que en principio tiene ventajas (ya sabes, mejor usar variables locales que globales, no es exactamente lo mismo en este caso pero sí similar)
Esto se vió en el modelo de trabajo del "controller as" que explicamos en el artículo
http://www.desarrolloweb.com/articulos/ejercicio-controladores-angularjs.html

juan_c

04/11/2014
$scope y this
Cierto! Me sonaba que había leido lo de usar this en vez de $scope, pero no recordaba que había sido aquí :-)

Carlos Bolivar

04/11/2014
Seguridad del Codigo
Hola,

Actualmente estoy iniciandome con AngularJS, pero tengo una duda. Si tengo mi url visibles en el archivo .js o en el codigo de la pagina HTML, asi como tambien otras partes del codigo JavaScript de mi controller angular. De que manera puedo implementar la seguridad en mi aplicacion para que este codigo no sea visible en el cliente?

Jordi

06/11/2014
controlador / servicio o factoria
Primero felicitaros, estoy empezando con angular, gracias a esta manual.
Que sería mejor ? hacer el ajax dentro de un servicio o factoría (Aun no me queda claro cual es la diferencia entre los dos). Creo entender que los servicio son como proveedores de datos y el controlador gestiona esos datos para pasarlo a la vista.

Esto es así realmente o lo acabo de soñar.

Gracias

midesweb

06/11/2014
Diferencias y usos de factorias/servicios
Hola,
Jordi, que bueno que estés aprovechando este manual.
Justamente ayer hicimos un webcast dedicado a las factorías, servicios y las diferencias, usos, etc.
Vimos muchas cosas interesantes. Por favor, responde a la pregunta tú mismo viendo este vídeo.
http://www.desarrolloweb.com/en-directo/logica-negocio-angularjs-angulario-8768.html

midesweb

06/11/2014
proteger tu código Javascript
Hola,
Carlos Bolivar, esa pregunta que te formulas es bastante habitual, pero por suerte o desgracia poco se puede hacer. El código Javascript llega al cliente y siempre hay maneras de recuperarlo. Puedes hacer cosas como minimizarlo, con lo que consigues que no se pueda leer, pero te lo pueden restaurar. En este caso, una vez des-minimizado lo cierto es que habría cosas que pierden un poco el sentido y dificulta entender el código, pero no por ello deja de ser susceptible de análisis o copia.
También lo puedes encriptar, pero antes de interpretarlo por el Javascript debes desencriptarlo y usando ese mismo proceso cualquiera puede leerlo.
En fin, dicen que los problemas que no tienen solución no deben preocuparnos.
De todos modos, la parte del servidor sigue sin ser visible y la seguridad debes implementarla allí. Osea, en Javascript puedes realizar todo tipo de validaciones y aplicación de reglas de negocio, pero tendrás que volverlas a realizar del lado del servidor, porque es la única parte realmente segura.
Saludos!

cacharro

29/10/2015
deve????
Respuesta en caso de éxito
De momento, veamos qué deberíamos hacer para especificarle a Angular lo que <code>deve</code> de hacer cuando se reciba respuesta correcta del servidor.

johan

03/11/2015
http.post
Hola, que tal, estoy tratando de pasar datos de angular a nodejs con http.post pero no recibo los datos a nodejs. Tienes un articulo que hable de ello o me puedes dar un ejemplo breve, gracias.

Gustavo Benites

28/12/2015
Como se aplica el filter al ng-repeat en este ejemplo con datos json
Hola, como se aplica el filter en este ejemplo con json, por ejemplo quiero filtrar paises que comiencen con A
Gracias