martes, 10 de enero de 2017

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

En el artículo anterior dedicado a los servicios web REST hemos visto cómo crear fácilmente un servicio de este tipo utilizando el framework ASP.NET MVC 3. En esta segunda parte vamos a describir cómo podemos construir una aplicación Android que acceda a este servicio web REST.
Y tal como hicimos en el caso de SOAP, vamos a crear una aplicación de ejemplo que llame a las distintas funciones de nuestro servicio web. En este caso la aplicación se compondrá de 5 botones, uno por cada una de las acciones que hemos implementado en el servicio web (insertar, actualizar, eliminar, recuperar un cliente, y listar todos los clientes).
captura-inicial-rest
A diferencia del caso de SOAP, en esta ocasión no vamos a utilizar ninguna librería externa para acceder al servicio web, ya que Android incluye todo lo necesario para realizar la conexión y llamada a los métodos del servicio, y tratamiento de resultados en formato JSON.
Como ya hemos comentado, al trabajar con servicios web de tipo REST, las llamadas al servicio no se harán a través de una única URL, sino que se determinará la acción a realizar según la URL accedida y la acción HTTP utilizada para realizar la petición (GETPOSTPUT o DELETE). En los siguientes apartados veremos uno a uno la implementación de estos botones.
Insertar un nuevo cliente
Como ya comentamos en el artículo anterior, la inserción de un nuevo cliente la realizaremos a través de la siguiente URL:
http://10.0.2.2:2731/Api/Clientes/Cliente
Utilizaremos la acción http POST y tendremos que incluir en la petición un objeto en formato JSON que contenga los datos del nuevo cliente (tan sólo Nombre y Teléfono, ya que el ID se calculará automáticamente). El formato de este objeto de entrada será análogo al siguiente:
{Nombre:”cccc”, Telefono:12345678}
Pues bien, para conseguir esto comenzaremos por crear un nuevo objeto HttpClient, que será el encargado de realizar la comunicación HTTP con el servidor a partir de los datos que nosotros le proporcionemos. Tras esto crearemos la petición POST creando un nuevo objeto HttpPost e indicando la URL de llamada al servicio. Modificaremos mediante setHeader() el atributo http content-type para indicar que el formato de los datos que utilizaremos en la comunicación, que como ya indicamos será JSON (cuyo MIME-Type correspondiente es “application/json“).
1
2
3
4
5
6
HttpClient httpClient = new DefaultHttpClient();
 
HttpPost post =
 
post.setHeader("content-type", "application/json");
El siguiente paso será crear el objeto JSON a incluir con la petición, que deberá contener los datos del nuevo cliente a insertar. Para ello creamos un nuevo objeto JSONObject y le añadimos mediante el método put() los dos atributos necesarios (nombre y teléfono) con sus valores correspondientes, que los obtenemos de los cuadros de texto de la interfaz, llamados txtNombre y txtTelefono.
Por último asociaremos este objeto JSON a nuestra petición HTTP convirtiéndolo primero al tipo StringEntity e incluyéndolo finalmente en la petición mediante el método setEntity().
1
2
3
4
5
6
7
8
//Construimos el objeto cliente en formato JSON
JSONObject dato = new JSONObject();
 
dato.put("Nombre", txtNombre.getText().toString());
dato.put("Telefono", Integer.parseInt(txtTelefono.getText().toString()));
 
StringEntity entity = new StringEntity(dato.toString());
post.setEntity(entity);
Una vez creada nuestra petición HTTP y asociado el dato de entrada, tan sólo nos queda realizar la llamada al servicio mediante el método execute()del objeto HttpClient y recuperar el resultado mediante getEntity(). Este resultado lo recibimos en forma de objeto HttpEntity, pero lo podemos convertir fácilmente en una cadena de texto mediante el método estático EntityUtils.toString().
1
2
3
4
5
HttpResponse resp = httpClient.execute(post);
String respStr = EntityUtils.toString(resp.getEntity());
 
if(respStr.equals("true"))
    lblResultado.setText("Insertado OK.");
En nuestro caso, el método de inserción devuelve únicamente un valor booleano indicando si el registro se ha insertado correctamente en la base de datos, por lo que tan sólo tendremos que verificar el valor de este booleano (“true” o “false”) para conocer el resultado de la operación, que mostraremos en la interfaz en una etiqueta de texto llamada lblResultado.
Como ya dijimos en el apartado anterior sobre servicios SOAP, a partir de la versión 3 de Android no se permite realizar operaciones de larga duración dentro del hilo principal de la aplicación, entre ellas conexiones a internet como estamos haciendo en esta ocasión. Para solucionar este problema y que la aplicación funcione correctamente en todas las versiones de Android debemos hacer la llamada al servicio mediante una tarea asíncrona, o AsynTask, que se ejecute en segundo plano. Una vez más no entraré en detalles porque el curso contiene un capítulo dedicado exclusivamente a este tema. A modo de ejemplo, el código anterior trasladado a una AsyncTask quedaría de la siguiente forma:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
private class TareaWSInsertar extends AsyncTask<String,Integer,Boolean> {
 
    protected Boolean doInBackground(String... params) {
 
        boolean resul = true;
 
        HttpClient httpClient = new DefaultHttpClient();
 
    HttpPost post = new
             HttpPost("http://10.0.2.2:2731/Api/Clientes/Cliente");
 
    post.setHeader("content-type", "application/json");
 
    try
        {
        //Construimos el objeto cliente en formato JSON
        JSONObject dato = new JSONObject();
 
        dato.put("Nombre", params[0]);
        dato.put("Telefono", Integer.parseInt(params[1]));
 
        StringEntity entity = new StringEntity(dato.toString());
        post.setEntity(entity);
 
                HttpResponse resp = httpClient.execute(post);
            String respStr = EntityUtils.toString(resp.getEntity());
 
            if(!respStr.equals("true"))
                resul = false;
        }
        catch(Exception ex)
        {
            Log.e("ServicioRest","Error!", ex);
            resul = false;
        }
 
        return resul;
    }
 
    protected void onPostExecute(Boolean result) {
 
        if (result)
        {
            lblResultado.setText("Insertado OK.");
        }
    }
}
Y la llamada a la tarea asíncrona desde el evento onClick del botón de Insertar sería tan sencilla como ésta:
1
2
3
4
5
6
7
8
9
10
btnInsertar.setOnClickListener(new OnClickListener() {
 
    @Override
    public void onClick(View v) {
        TareaWSInsertar tarea = new TareaWSInsertar();
        tarea.execute(
            txtNombre.getText().toString(),
            txtTelefono.getText().toString());
    }
});
Actualizar un cliente existente
La URL utilizada para la actualización de clientes será la misma que la anterior:
http://10.0.2.2:2731/Api/Clientes/Cliente
Pero en este caso, el objeto JSON a enviar como entrada deberá contener no sólo los nuevos valores de nombre y teléfono sino también el ID del cliente a actualizar, por lo que tendría una estructura análoga a la siguiente:
{Id:123, Nombre:”cccc”, Telefono:12345678}
Para actualizar el cliente procederemos de una forma muy similar a la ya comentada para la inserción, con las únicas diferencias de que en este caso la acción HTTP utilizada será PUT (objeto HttpPut) y que el objeto JSON de entrada tendrá el campo ID adicional.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
HttpClient httpClient = new DefaultHttpClient();
 
HttpPut put = new HttpPut("http://10.0.2.2:2731/Api/Clientes/Cliente");
put.setHeader("content-type", "application/json");
 
try
{
    //Construimos el objeto cliente en formato JSON
    JSONObject dato = new JSONObject();
 
    dato.put("Id", Integer.parseInt(txtId.getText().toString()));
    dato.put("Nombre", txtNombre.getText().toString());
    dato.put("Telefono", Integer.parseInt(txtTelefono.getText().toString()));
 
    StringEntity entity = new StringEntity(dato.toString());
    put.setEntity(entity);
 
        HttpResponse resp = httpClient.execute(put);
        String respStr = EntityUtils.toString(resp.getEntity());
 
        if(respStr.equals("true"))
            lblResultado.setText("Actualizado OK.");
}
catch(Exception ex)
{
        Log.e("ServicioRest","Error!", ex);
}
Eliminación de un cliente
La eliminación de un cliente la realizaremos a través de la URL siguiente:
http://10.0.2.2:2731/Api/Clientes/Cliente/id_cliente
donde id_cliente será el ID del cliente a eliminar. Además, utilizaremos la acción http DELETE (objeto HttpDelete) para identificar la operación que queremos realizar. En este caso no será necesario pasar ningún objeto de entrada junto con la petición, por lo que el código quedará aún más sencillo que los dos casos anteriores.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HttpClient httpClient = new DefaultHttpClient();
 
String id = txtId.getText().toString();
 
HttpDelete del =
    new HttpDelete("http://10.0.2.2:2731/Api/Clientes/Cliente/" + id);
 
del.setHeader("content-type", "application/json");
 
try
{
        HttpResponse resp = httpClient.execute(del);
        String respStr = EntityUtils.toString(resp.getEntity());
 
        if(respStr.equals("true"))
            lblResultado.setText("Eliminado OK.");
}
catch(Exception ex)
{
        Log.e("ServicioRest","Error!", ex);
}
Como podéis ver, al principio del método obtenemos el ID del cliente desde la interfaz de la aplicación y lo concatenamos con la URL base para formar la URL completa de llamada al servicio.
Obtener un cliente
Esta operación es un poco distinta a las anteriores, ya que en este caso el resultado devuelto por el servicio será un objeto JSON y no un valor simple como en los casos anteriores. Al igual que en el caso de eliminación de clientes, la URL a utilizar será del tipo:
http://10.0.2.2:2731/Api/Clientes/Cliente/id_cliente
En este caso utilizaremos un tipo de petición http GET (objeto HttpGet) y la forma de realizar la llamada será análoga a las anteriores. Donde aparecerán las diferencias será a la hora de tratar el resultado devuelto por el servicio tras llamar al método getEntity(). Lo que haremos será crear un nuevo objeto JSONObject a partir del resultado textual de getEntity(). Hecho esto, podremos acceder a los atributos del objeto utilizando para ello los métodos get() correspondientes, según el tipo de cada atributo (getInt()getString(), etc). Tras esto mostraremos los datos del cliente recuperado en la etiqueta de resultados de la interfaz (lblResultados).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
HttpClient httpClient = new DefaultHttpClient();
 
String id = txtId.getText().toString();
 
HttpGet del =
    new HttpGet("http://10.0.2.2:2731/Api/Clientes/Cliente/" + id);
 
del.setHeader("content-type", "application/json");
 
try
{
        HttpResponse resp = httpClient.execute(del);
        String respStr = EntityUtils.toString(resp.getEntity());
 
        JSONObject respJSON = new JSONObject(respStr);
 
        int idCli = respJSON.getInt("Id");
        String nombCli = respJSON.getString("Nombre");
        int telefCli = respJSON.getInt("Telefono");
 
        lblResultado.setText("" + idCli + "-" + nombCli + "-" + telefCli);
}
catch(Exception ex)
{
        Log.e("ServicioRest","Error!", ex);
}
Una vez más como podéis comprobar el código es muy similar al ya visto para el resto de operaciones.
Obtener listado completo de clientes
Por último vamos a ver cómo podemos obtener el listado completo de clientes. El interés de esta operación está en que el resultado recuperado de la llamada al servicio será un array de objetos de tipo cliente, por supuesto en formato JSON. La acción http utilizada será una vez más la acción GET, y la URL para recuperar el listado de clientes será:
http://10.0.2.2:2731/Api/Clientes
De nuevo, la forma de llamar al servicio será análoga a las anteriores hasta la llamada a getEntity() para recuperar los resultados. En esta ocasión, dado que recibimos un array de elementos, convertiremos este resultado a un objeto JSONArray, y hecho esto podremos acceder a cada uno de los elementos del array mediante una llamada a getJSONObject(), al que iremos pasando el índice de cada elemento. Para saber cuántos elementos contiene el array podremos utilizar el método length() del objeto JSONArray. Por último, el acceso a los atributos de cada elemento del array lo realizamos exactamente igual como ya lo hicimos en la operación anterior de obtención de cliente por ID.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
HttpClient httpClient = new DefaultHttpClient();
 
HttpGet del =
    new HttpGet("http://10.0.2.2:2731/Api/Clientes");
 
del.setHeader("content-type", "application/json");
 
try
{
        HttpResponse resp = httpClient.execute(del);
        String respStr = EntityUtils.toString(resp.getEntity());
 
        JSONArray respJSON = new JSONArray(respStr);
 
        String[] clientes = new String[respJSON.length()];
 
        for(int i=0; i<respJSON.length(); i++)
        {
            JSONObject obj = respJSON.getJSONObject(i);
 
            int idCli = obj.getInt("Id");
            String nombCli = obj.getString("Nombre");
            int telefCli = obj.getInt("Telefono");
 
            clientes[i] = "" + idCli + "-" + nombCli + "-" + telefCli;
        }
 
        //Rellenamos la lista con los resultados
        ArrayAdapter<String> adaptador =
                new ArrayAdapter<String>(ServicioWebRest.this,
                android.R.layout.simple_list_item_1, clientes);
 
    lstClientes.setAdapter(adaptador);
}
catch(Exception ex)
{
        Log.e("ServicioRest","Error!", ex);
}
Tras obtener nuestro array de clientes, para mostrar los resultados hemos añadido a la interfas de nuestra aplicación de ejemplo un control tipo ListView (llamado lstClientes) que hemos rellenado a través de su adaptador con los datos de los clientes recuperados.
A modo de ejemplo, en la siguiente imagen puede verse el resultado de ejecutar la operación de listado completo de clientes:

No hay comentarios:

Publicar un comentario