Inicio Android Acceso a Servicios Web REST en Android (1/2)

Acceso a Servicios Web REST en Android (1/2)

por sgoliver

En los dos artículos anteriores (éste y éste) del Curso de Programación Android nos hemos ocupado de describir la forma de construir un sistema formado por un servicio web SOAP que accede a una base de datos externa y una aplicación Android que, a través de este servicio, es capaz de manipular dichos datos.

En este nuevo artículo vamos a crear un sistema similar, pero esta vez haciendo uso de la otra alternativa por excelencia a la hora de crear servicios web, y no es otra de utilizar servicios web tipo REST. Las famosas APIs que publican muchos de los sitios web actualmente no son más que servicios web de este tipo, aunque en la mayoría de los casos con medidas de seguridad adicionales tales como autenticación OAuth o similares.

REST también se asienta sobre el protocolo HTTP como mecanismo de transporte entre cliente y servidor, ya veremos después en qué medida. Y en cuanto al formato de los datos transmitidos, a diferencia de SOAP, no se impone ninguno en concreto, aunque lo más habitual actualmente es intercambiar la información en formato XML o JSON. Ya que en el caso de SOAP utilizamos XML, en este nuevo artículo utilizaremos JSON para construir nuestro ejemplo.

También vamos a utilizar un framework distinto para construir el servicio, aunque seguiremos haciéndolo en Visual Studio y en lenguaje C#. En este caso, en vez de utilizar ASP.NET a secas, vamos a utilizar el framework específico ASP.NET MVC 3, cuyo sistema de direccionamiento se ajusta mejor a los principios de REST, donde cada recurso [en nuestro caso cada cliente] debería ser accesible mediante su propia URL única. Podéis descargar MVC3 desde su página oficial de Microsoft.

En este primer artículo sobre servicios REST vamos a describir la construcción del servicio web en sí, y dedicaremos un segundo artículo a explicar cómo podemos acceder a este servicio desde una aplicación Android.

Empezamos. Lo primero que vamos a hacer será crear un nuevo proyecto en Visual Studio utilizando esta vez la plantilla llamada «ASP.NET MVC 3 Web Application«, lo llamaremos «ServicioWebRest«.

nuevo-proyecto-rest

En la ventana de opciones del proyecto dejaremos todos los datos que aparecen por defecto y seleccionaremos como plantilla «Empty» para crear una aplicación vacía.

opciones-proyecto-rest

Esto debería crearnos el nuevo proyecto con la estructura de carpetas necesaria, que como veréis es bastante elaborada.  En nuestro caso vamos a crear el servicio web de forma aislada del resto de la aplicación web, y para ello lo primero que vamos a hacer es añadir una nueva Area al proyecto, a la que llamaremos por ejemplo «Api«, lo que nos creará una estructura de carpetas similar a la de la aplicación principal pero dentro de una carpeta independiente. Esto nos permite aislar todo el código y recursos de nuestro servicio web del resto de la aplicación web (que en nuestro caso no existirá porque no es el objetivo de este artículo, pero que podríamos crear sin problemas si lo necesitáramos).

menu-nueva-area

Con esto, la estructura de nuestro proyecto será la siguiente:

estructura-proyecto-mvc3

Una vez que ya tenemos preparada toda la estructura de nuestro proyecto empecemos a añadir los elementos necesarios. Lo primero que vamos a crear será una nueva clase Cliente, igual que hicimos en el ejemplo anterior con SOAP. La colocaremos en la carpeta «Api/Models» y el código es el mismo que ya vimos:

namespace ServicioWebRest.Areas.Api.Models
{
    public class Cliente
    {
        public int Id { get; set; }
        public string Nombre { get; set; }
        public int Telefono { get; set; }
    }
}

El siguiente elemento a añadir será una nueva clase que contenga todas las operaciones que queramos realizar sobre nuestra base de datos de clientes. Llamaremos a la clase ClienteManager. En este caso sí vamos a añadir las cuatro operaciones básicas sobre clientes, y una adicional para obtener el listado completo, de forma que más tarde podamos mostrar la implementación en Android de todos los posibles tipos de llamada al servicio. Los métodos que añadiremos serán los siguientes:

  • Cliente ObtenerCliente(int id)
  • List<Clientes> ObtenerClientes()
  • bool InsertarCliente(Cliente c)
  • bool ActualizarCliente(Cliente c)
  • bool EliminarCliente(int id)

Los dos primeros métodos nos servirán para recuperar clientes de la base de datos, tanto por su ID para obtener un cliente concreto, como el listado completo que devolverá una lista de clientes. Los otros tres métodos permitirán insertar, actualizar y eliminar clientes a partir de su ID y los datos de entrada (si aplica). El código de todos estos métodos es análogo a los ya implementados en el caso de SOAP, por lo que no nos vamos a parar en volverlos a comentar, tan sólo decir que utilizan la api clásica de ADO.NET para el acceso a SQL Server. En cualquier caso, al final del artículo tenéis como siempre el código fuente completo para poder consultar lo que necesitéis. A modo de ejemplo veamos la implementación de los métodos ObtenerClientes() e InsertarCliente().

public bool InsertarCliente(Cliente cli)
{
      SqlConnection con = new SqlConnection(cadenaConexion);

      con.Open();

      string sql = "INSERT INTO Clientes (Nombre, Telefono) VALUES (@nombre, @telefono)";

      SqlCommand cmd = new SqlCommand(sql,con);

      cmd.Parameters.Add("@nombre", System.Data.SqlDbType.NVarChar).Value = cli.Nombre;
      cmd.Parameters.Add("@telefono", System.Data.SqlDbType.Int).Value = cli.Telefono;

      int res = cmd.ExecuteNonQuery();

      con.Close();

      return (res == 1);
}

public List<Cliente> ObtenerClientes()
{
      List<Cliente> lista = new List<Cliente>();

      SqlConnection con = new SqlConnection(cadenaConexion);

      con.Open();

      string sql = "SELECT IdCliente, Nombre, Telefono FROM Clientes";

      SqlCommand cmd = new SqlCommand(sql,con);

      SqlDataReader reader =
            cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);

      while (reader.Read())
      {
          Cliente cli = new Cliente();

          cli = new Cliente();
          cli.Id = reader.GetInt32(0);
          cli.Nombre = reader.GetString(1);
          cli.Telefono = reader.GetInt32(2);

          lista.Add(cli);
      }

      reader.Close();

      return lista;
}

Hasta ahora, todo el código que hemos escrito es bastante genérico y nada tiene que ver con que nuestro proyecto sea de tipo MVC. Sin embargo, los dos siguientes elementos sí que están directamente relacionados con el tipo de proyecto que tenemos entre manos.

Lo siguiente que vamos a añadir será un controlador a nuestro servicio web. Este controlador (clase ClientesController) será el encargado de contener las diferentes acciones que se podrán llamar según la URL y datos HTTP que recibamos como petición de entrada al servicio. Para nuestro ejemplo, añadiremos tan sólo dos acciones, una primera dirigida a gestionar todas las peticiones que afecten a un único cliente (insertar, actualizar, eliminar y obtener por ID), y otra que trate la petición del listado completo de clientes. Las llamaremos Clientes() y Cliente() respectivamente. Estas acciones harán uso de una instancia de la clase ClienteManager creada anteriormente para realizar las acciones necesarias contra la base de datos. Cada acción será también responsable de formatear sus resultados al formato de comunicación que hayamos elegido, en nuestro caso JSON.

La acción Clientes es muy sencilla, se limitará a llamar al método ObtenerClientes() y formatear los resultados como JSON. Para hacer esto último basta con crear directamente un objeto JsonResult llamado al método Json() pasándole como parámetro de entrada el objeto a formatear. Todo esto se reduce a una sola linea de código:

[HttpGet]
public JsonResult Clientes()
{
    return Json(this.clientesManager.ObtenerClientes(),
                JsonRequestBehavior.AllowGet);
}

Habréis notado también que hemos precedido el método con el atributo [HttpGet]. Para intentar explicar esto me hace falta seguir hablando de los principios de diseño de REST. Este tipo de servicios utiliza los propios tipos de petición definidos por el protocolo HTTP para diferenciar entre las operaciones a realizar por el servicio web. Así, el propio tipo de petición HTTP realizada (GET, POST, PUT o DELETE), junto con la dirección URL especificada en la llamada, nos determinará la operación a ejecutar por el servicio web. En el caso ya visto, el atributo [HttpGet] nos indica que dicho método se podrá ejecutar al recibirse una petición de tipo GET.

Entenderemos todo esto mejor ahora cuando veamos el código de la acción Cliente(). En esta acción, dependiente del tipo de petición HTTP recibida, tendremos que llamar a un método u otro del servicio web. Así, usaremos POST para las inserciones de clientes, PUT para las actualizaciones, GET para la consulta por ID y DELETE para las eliminaciones. En este caso no precedemos el método por ningún atributo, ya que la misma acción se encargará de tratar diferentes tipos de petición.

public JsonResult Cliente(int? id, Cliente item)
{
    switch (Request.HttpMethod)
    {
        case "POST":
            return Json(clientesManager.InsertarCliente(item));
        case "PUT":
            return Json(clientesManager.ActualizarCliente(item));
        case "GET":
            return Json(clientesManager.ObtenerCliente(id.GetValueOrDefault()),
                        JsonRequestBehavior.AllowGet);
        case "DELETE":
            return Json(clientesManager.EliminarCliente(id.GetValueOrDefault()));
    }

    return Json(new { Error = true, Message = "Operación HTTP desconocida" });
}

Algunos de vosotros seguro que os estáis preguntando cómo distinguirá el servicio cuándo llamar a la acción Clientes() para obtener el listado completo, o a la acción Cliente() para obtener un único cliente por su ID, ya que para ambas operaciones hemos indicado que se recibirá el tipo de petición http GET.

Pues bien, aquí es donde nos va a ayudar el último elemento a añadir al servicio web. Realmente no lo añadiremos, sino que lo modificaremos, ya que es un fichero que ya ha creado Visual Studio por nosotros. Se trata de la clase ApiAreaRegistration. La función de esta clase será la de dirigir las peticiones recibidas hacia una acción u otra del controlador según la URL utilizada al realizarse la llamada al servicio web.

En nuestro caso de ejemplo, vamos a reconocer dos tipos de URL. Una de ellas para acceder a la lista completa de cliente, y otra para realizar cualquier acción sobre un cliente en concreto:

  • Lista de clientes: http://servidor/Api/Clientes
  • Operación sobre cliente: http://servidor/Api/Clientes/Cliente/id_del_cliente

Cada uno de estos patrones tendremos que registrarlos mediante el método MapRoute() dentro del método RegisterArea() que ya tendremos creado dentro de la clase ApiAreaRegistration. Así, para registrar el primer tipo de URL haremos lo siguiente:

context.MapRoute(
    "AccesoClientes",
    "Api/Clientes",
    new
    {
        controller = "Clientes",
        action = "Clientes"
    }
);

Como primer parámetro de MapRoute() indicamos un nombre descriptivo para el patrón de URL. El segundo parámetro es el patrón en sí, que en este caso no tiene partes variables. Por último indicamos el controlador al que se dirigirán las peticiones que sigan este patrón eliminando el sufijo «Controller» (en nuestro caso será el controlador ClientesController) y la acción concreta a ejecutar dentro de dicho controlador (en nuestro caso la acción Clientes()).

Para el segundo tipo de URL será muy similar, con la única diferencia de que ahora habrá una parte final variable que se corresponderá con el ID del cliente y que asignaremos al parámetro «id» de la acción. En este caso además, dirigiremos la petición hacia la acción Cliente(), en vez de Clientes().

context.MapRoute(
    "AccesoCliente",
    "Api/Clientes/Cliente/{id}",
    new
    {
        controller = "Clientes",
        action = "Cliente",
        id = UrlParameter.Optional
    }
);

Como todo esto en cuenta, y por recapitular un poco, las posibles llamadas a nuestro servicio serán las siguientes:

GET  /Api/Clientes

Recuperará el listado completo de clientes y lo devolverá en formato JSON.

GET  /Api/Clientes/Cliente/3

Recuperará el cliente con el ID indicado en la URL y lo devolverá en formato JSON.

POST  /Api/Clientes/Cliente  { Nombre:»nombre», Telefono:1234 }

Insertará un nuevo cliente con los datos aportados en la petición en formato JSON.

PUT  /Api/Clientes/Cliente/3  { Id:3, Nombre:»nombre», Telefono:1234 }

Actualizará el cliente con el ID indicado en la URL con los datos aportados en la petición en formato JSON.

DELETE  /Api/Clientes/Cliente/3

Eliminará el cliente con el ID indicado en la URL.

Llegados aquí, tan sólo tenemos que ejecutar nuestro proyecto y esperar a que se abra el navegador web. En principio no se mostrará un error por no encontrar la página principal de la aplicación, ya que no hemos creado ninguna, pero nos asegurará que el servidor de prueba está funcionando, por lo que nuestro servicio debería responder a peticiones.

Así, si escribimos en la barra de direcciones por ejemplo la siguiente dirección (el puerto puede variar):

http://localhost:1234/Api/Clientes/Cliente/4

deberíamos recibir un fichero en formato JSON que contuviera los datos del cliente con ID = 4 de nuestra base de datos. Sería un fichero con contenido similar al siguiente:

{"Id":4,"Nombre":"cliente4","Telefono":4444}

En el siguiente artículo veremos cómo construir una aplicación Android capaz de acceder a este servicio y procesar los resultados recibidos.

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la página del curso en GitHub.

Curso de Programación Android en PDF

Este curso también está disponible en PDF. Descubre cómo conseguirlo…

¿Te ha sido de utilidad el Curso de Programación Android? ¿Quieres colaborar de forma económica con el proyecto? Puedes contribuir con cualquier cantidad, unos céntimos, unos euros, cualquier aportación será bienvenida. Además, si tu aportación es superior a una pequeña cantidad simbólica recibirás como agradecimiento un documento con la última versión del curso disponible en formato PDF. Sea como sea, muchas gracias por colaborar!

Más información:

También te puede interesar

25 comentarios

Acceso a Servicios Web REST en Android (2/2) | sgoliver.net blog 04/03/2012 - 18:32

[…] a Servicios Web REST en Android (2/2)Por sgoliver en 04/03/2012 en Android, Programación En el artículo anterior dedicado a los servicios web REST hemos visto cómo crear fácilmente un servicio de este tipo […]

Responder
Desarrollo en Android | sgoliver.net blog 04/03/2012 - 18:42

[…] Servicios Web REST en Android (1/2) [Nuevo!] […]

Responder
Juan Carlos 08/03/2012 - 19:00

Muy buen aporte, esto mismo no se podria hacer con java servlet o en su defecto php????

Responder
jariquelme 16/03/2012 - 9:25

Hola,
En teoria lo puedes hacer con cualquier lenguaje, esto es solo una forma de hacerlo.
Realmente necesitas que el servidor tenga un servidor REST y devuelva los datos en formato JSON.
El como lo hace es independiente de una aplicacion Android. Podrias usar PHP, rails, java …

Saludos

Responder
Selene 27/03/2012 - 18:10

Hola, una pregunta, cómo pueda saber si cambia mi local host??, espero q me ayudes muy buen aporte :D

Responder
josefina 26/04/2012 - 6:20

lo estoy haciendo con un conector de mysql , soy nueva en estas cosas pero al probar la url me sale erro 404 que crees que estoy haciendo mal , saludos

Responder
Harry 17/05/2012 - 20:20

Hola, en el metodo «public JsonResult Cliente(int? id, Cliente item)» de la clase ClientesController.cs, establecemos que la búsqueda sea por id que es un entero pero si quiero hacer la consulta con un string???. Hice el cambio lógico en vez de int puse string pero me salia el siguiente error «El tipo string debe ser un tipo de valor distinto de null para poder utilizarlo como parámetro ‘T’ en el tipo o método genérico».. cual sería la solución ya que buscar por id no es muy factible. Gracias.

Responder
Sergio 25/09/2012 - 1:46

Hola, primero muchas gracias por este tutorial, lo estoy llevando a cabo para entender un poco el funcionamiento de REST. Estoy mirando de si puedo aplicarlo para mi proyecto pero no lo tengo muy claro.

Si a parte de todos los métodos que has descrito, necesitaras uno que fuera «ObtenerClientesByNombre» que se le pasara un nombre y te devolviera todos los clientes con ese nombre… como se haría? Parece como si solo se puedan hacer con rest cuatro tipos de consultas, insertar, actualizar, eliminar, obtener un cliente por id, y obtener todos los clientes. NO tengo claro como se podrían abordar otro tipo de peticiones como por ejemplo también uno que devuelva los clientes mayores de 15 y menores de 30 (si hubiera el campo edad en cliente).

Saludos,

Responder
Camilo 12/01/2013 - 19:24

Buenas tardes, Tengo una aplicacion que llama servicios REST, pero a veces me sale esta excepcion :unterminated string a character, solo sale a veces y solo sale cuando ejecuto la aplicacion en el telefono en el emulador no sale.
Para obtener los datos en android utilizo los objetos JSONObject y JSONArray.
Sabe como lo prodria arreglar o como reproducirlo en el emulador.
Gracias

Responder
beto 25/01/2013 - 23:54

hola muy buen post , tengo un problema, al correr el web service me aparece el siguiente error Server Error in ‘/’ Application.
cual podria ser el problema
?????

Responder
beto 26/01/2013 - 0:41

al correr el web service y poner la ruta: http://localhost:1234/Api/Clientes/Cliente/4
logicamente con el puerto correcto

me manda el error: Error in ‘/’ Application.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Responder
WebSite 22/03/2013 - 23:53

Hola compañero ante todo excelente tutorial sobre android estoy aprendiendo muchisimo, pero tengo una duda, que es mejor servicio web REST o SOAP??

Responder
Question 05/04/2013 - 17:22

Al ejecutar la aplicación me da un error 25 en la línea con.Open();
El error me da la siguiente descripción:

Error relacionado con la red o específico de la instancia mientras se establecía una conexión con el servidor SQL Server. No se encontró el servidor o éste no estaba accesible. Compruebe que el nombre de la instancia es correcto y que SQL Server está configurado para admitir conexiones remotas. (provider: SQL Network Interfaces, error: 26 – Error al buscar el servidor o instancia especificado)

Alguien sabe a que se puede deber?

Responder
Mart 17/11/2013 - 7:33

Hola esta muy bien tu ejemplo, he visto varios webservices que usan c# y php con android pero no he encontrado ningun ejemplo de webservices java con android, no podrias hacer un tutorial mas adelante

Responder
Miguel 28/04/2014 - 12:33

Hola, muy buen curso!!
Mira te quería preguntar un problema, cuando subo por POST un objecto el objeto en el servidor me llega con todos los parámetros en null. Haber si me podrías guiar donde podría haber el fallo

Responder
Cristhian 07/07/2014 - 16:06

Hola muy buen tutorial…

Les cuento que tengo un problema en la clase ClientesController, Me da error por no reconocer «Json» y «Request» en los metodos «public JsonResult Clientes()» y
«public JsonResult Cliente(int? id, Cliente item)»

estas son las librerias que ocupo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ServicioWebRest.Areas.Api.Models;

ERROR:
«El nombre ‘Json’ no existe en el contexto actual »
el problema se presenta en esta linea
» return Json(clientesManager.ObtenerClientes(), JsonRequestBehavior.AllowGet); »

«El nombre ‘Request’ no existe en el contexto actual »
el problema se presenta en esta linea
» switch (Request.HttpMethod) «

Responder
jorge 05/08/2014 - 21:50

Hola
Tengo una duda en la parte final del tema:

«Así, si escribimos en la barra de direcciones por ejemplo la siguiente dirección (el puerto puede variar):
http://localhost:1234/Api/Clientes/Cliente/4»

Como sabe el SW que peticion es Get o Delete?
.

Responder
licosi 31/10/2014 - 0:57

Tengo un problema, puedo crear el servicio Rest pero solo puedo acceder al mismo desde la propia PC e incluso desde el emulador de android pero cuando quiero acceder desde otra PC de la Red local no encuentra el Servicio. Me podrian dar alguna idea para solucionarlo?

Responder
Luis Rojas 03/12/2014 - 17:23

Cómo paso mas de un parámetro. Es esto posible? Pues estoy tratando de pasar uno solo, un string, y no lo toma.

Gracias

Responder
Consultas REST en Android: Retrofit | Galideas 03/05/2015 - 0:46

[…] que necesitemos manejar. Hay muy buenos tutoriales sobre esto en internet, podéis ver ejemplos aquí, aquí o aquí (o excelentes vídeos como el de Xamarín aquí) y por tanto no voy a desarrollar […]

Responder
Consultas REST en Android: Retrofit (parte 1) | Galideas 26/05/2015 - 9:36

[…] que necesitemos manejar. Hay muy buenos tutoriales sobre esto en internet, podéis ver ejemplos aquí, aquí o aquí (o excelentes vídeos como el de Xamarín aquí) y por tanto no voy a desarrollar […]

Responder
pachekoli 29/06/2015 - 21:06

No tengo errores pero al descargar el Json lo baja vacio, aun cuando tiene información. Lo estoy leyendo de un servidor y la bd tiene contraseña, modifique la cadena. Pero algo me esta faltando ¿Alguien tiene una Alternativa que probar?, todas las sugerencias se agradecen.
Saludos

Responder
Fabio Camelo 26/10/2015 - 20:13

Excelente tutorial. mil gracias

Responder
Kariky 23/04/2016 - 17:04

Chicos, para los que les da error es que deben fijarse en el connectionstring. Dependiendo de lo que tengan deberán cambiarlo. Por cierto, si no tienen datos en la base de datos les va a retornar vacío el json (a menos que le hayan hecho algún post anteriormente).

La guía está buena, aunque me hubiese gustado más explicación sobre lo que hay que poner en ApiAreaRegistration (y en base a qué). Saludos.

Responder

Responder a Miguel Cancelar respuesta

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies