Consumo de servicios web de RESTful

La integración de un servicio web en una aplicación es un escenario común. En este artículo se muestra cómo consumir un servicio web RESTful desde una aplicación Xamarin.Forms.

Transferencia de estado representacional (REST) es un estilo arquitectónico para compilar servicios web. Las solicitudes REST se realizan a través de HTTP con los mismos verbos HTTP que usan los exploradores web para recuperar páginas web y enviar datos a los servidores. Los verbos son:

  • GET: esta operación se usa para recuperar datos del servicio web.
  • POST: esta operación se usa para crear un nuevo elemento de datos en el servicio web.
  • PUT: esta operación se usa para actualizar un elemento de datos en el servicio web.
  • PATCH: esta operación se usa para actualizar un elemento de datos en el servicio web describiendo un conjunto de instrucciones sobre cómo se debe modificar el elemento. Este verbo no se usa en la aplicación de ejemplo.
  • DELETE: esta operación se usa para eliminar un elemento de datos en el servicio web.

Las API de servicio web que se adhieren a REST se denominan API de RESTful y se definen mediante:

  • Identificador URI base.
  • Métodos HTTP, como GET, POST, PUT, PATCH o DELETE.
  • Un tipo de medio para los datos, como notación de objetos JavaScript (JSON).

Normalmente, los servicios web RESTful usan mensajes JSON para devolver datos al cliente. JSON es un formato de intercambio de datos basado en texto que genera cargas compactas, lo que reduce los requisitos de ancho de banda al enviar datos. La aplicación de ejemplo usa la biblioteca de código abierto NewtonSoft JSON.NET para serializar y deserializar mensajes.

La simplicidad de REST ha ayudado a convertirlo en el método principal para acceder a servicios web en aplicaciones móviles.

Cuando se ejecute la aplicación de ejemplo, se conectará a un servicio REST hospedado localmente, como se muestra en la captura de pantalla siguiente:

Aplicación de ejemplo

Nota:

En iOS 9 y versiones posteriores, App Transport Security (ATS) exige conexiones seguras entre los recursos de Internet (como el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de información confidencial. Dado que ATS está habilitado de forma predeterminada en las aplicaciones compiladas para iOS 9, todas las conexiones estarán sujetas a los requisitos de seguridad de ATS. Si las conexiones no cumplen estos requisitos, producirán un error con una excepción.

ATS puede optar por no participar si no es posible usar el protocolo HTTPS y la comunicación segura para los recursos de Internet. Esto se puede lograr actualizando el archivo Info.plist de la aplicación. Para obtener más información, consulte Seguridad de transporte de aplicación.

Consumo del servicio web

El servicio REST se escribe mediante ASP.NET Core y proporciona las siguientes operaciones:

Operación Método HTTP Dirección URL relativa Parámetros
Obtención de una lista de tareas pendientes OBTENER /api/todoitems/
Crear un nuevo elemento de tareas pendientes PUBLICAR /api/todoitems/ Un TodoItem con formato JSON
Actualizar una tarea pendiente PUT /api/todoitems/ Un TodoItem con formato JSON
Eliminar una tarea pendiente Delete /api/todoitems/{id}

La mayoría de los URI incluyen el TodoItem id. en la ruta de acceso. Por ejemplo, para eliminar el TodoItem cuyo identificador es 6bb8a868-dba1-4f1a-93b7-24ebce87e243, el cliente envía una solicitud DELETE a http://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243. Para obtener más información sobre el modelo de datos usado en la aplicación de ejemplo, consulte Modelado de los datos.

Cuando el marco de API web recibe una solicitud, enruta la solicitud a una acción. Estas acciones son simplemente métodos públicos en la clase TodoItemsController. El marco de trabajo usa el middleware de enrutamiento para buscar coincidencias con las direcciones URL de las solicitudes entrantes y asignarlas a acciones. Las API de REST deben usar el enrutamiento de atributos del modelo de la funcionalidad de la aplicación como un conjunto de recursos cuyas operaciones se representan mediante verbos HTTP. El enrutamiento mediante atributos utiliza un conjunto de atributos para asignar acciones directamente a las plantillas de ruta. Para obtener más información sobre el enrutamiento de atributos, consulta Enrutamiento de atributos para las API REST. Para obtener más información sobre cómo crear el servicio REST mediante ASP.NET Core, consulte Creación de servicios back-end para aplicaciones móviles nativas.

La clase HttpClient se usa para enviar y recibir solicitudes a través de HTTP. Proporciona funcionalidad para enviar solicitudes HTTP y recibir respuestas HTTP de un recurso identificado por URI. Cada una de estas solicitudes se envía como una operación asincrónica. Para obtener más información sobre las operaciones asincrónicas, consulte Introducción a la compatibilidad asincrónica.

La clase HttpResponseMessage representa un mensaje de respuesta HTTP recibido del servicio web después de realizar una solicitud HTTP. Contiene información sobre la respuesta, incluido el código de estado, los encabezados y cualquier cuerpo. La clase HttpContent representa el cuerpo HTTP y los encabezados de contenido, como Content-Type y Content-Encoding. El contenido se puede leer mediante cualquiera de los métodos ReadAs, como ReadAsStringAsync y ReadAsByteArrayAsync, según el formato de los datos.

Creación del objeto HTTPClient

La instancia de HttpClient se declara en el nivel de clase para que el objeto resida mientras la aplicación necesite realizar solicitudes HTTP, como se muestra en el ejemplo de código siguiente:

public class RestService : IRestService
{
  HttpClient client;
  ...

  public RestService ()
  {
    client = new HttpClient ();
    ...
  }
  ...
}

Recuperación de datos

El método HttpClient.GetAsync se usa para enviar la solicitud GET al servicio web especificado por el URI y, a continuación, recibir la respuesta del servicio web, como se muestra en el ejemplo de código siguiente:

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));
  ...
  HttpResponseMessage response = await client.GetAsync (uri);
  if (response.IsSuccessStatusCode)
  {
      string content = await response.Content.ReadAsStringAsync ();
      Items = JsonSerializer.Deserialize<List<TodoItem>>(content, serializerOptions);
  }
  ...
}

El servicio REST envía un código de estado HTTP en la propiedad HttpResponseMessage.IsSuccessStatusCode, para indicar si la solicitud HTTP se realizó correctamente o no. Para esta operación, el servicio REST envía el código de estado HTTP 200 (CORRECTO) en la respuesta, lo que indica que la solicitud se realizó correctamente y que la información solicitada está en la respuesta.

Si la operación HTTP se realizó correctamente, se lee el contenido de la respuesta para mostrar. La propiedad HttpResponseMessage.Content representa el contenido de la respuesta HTTP y el método HttpContent.ReadAsStringAsync escribe de forma asincrónica el contenido HTTP en una cadena. A continuación, este contenido se deserializa de JSON a un List de TodoItem instancias.

Advertencia

El uso del método ReadAsStringAsync para recuperar una respuesta grande puede tener un impacto negativo en el rendimiento. En tales circunstancias, la respuesta debe deserializarse directamente para evitar tener que almacenarla completamente en búfer.

Crear datos

El método HttpClient.PostAsync se usa para enviar la solicitud POST al servicio web especificado por el URI y, a continuación, para recibir la respuesta del servicio web, como se muestra en el ejemplo de código siguiente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));

  ...
  string json = JsonSerializer.Serialize<TodoItem>(item, serializerOptions);
  StringContent content = new StringContent (json, Encoding.UTF8, "application/json");

  HttpResponseMessage response = null;
  if (isNewItem)
  {
    response = await client.PostAsync (uri, content);
  }
  ...

  if (response.IsSuccessStatusCode)
  {
    Debug.WriteLine (@"\tTodoItem successfully saved.");
  }
  ...
}

La instancia de TodoItem se serializa en una carga JSON para enviar al servicio web. A continuación, esta carga se inserta en el cuerpo del contenido HTTP que se enviará al servicio web antes de realizar la solicitud con el método PostAsync.

El servicio REST envía un código de estado HTTP en la propiedad HttpResponseMessage.IsSuccessStatusCode, para indicar si la solicitud HTTP se realizó correctamente o no. Las respuestas comunes para esta operación son:

  • 201 (CREATED): la solicitud dio lugar a que se creara un nuevo recurso antes de enviar la respuesta.
  • 400 (BAD REQUEST): el servidor no entiende la solicitud.
  • 409 (CONFLICT): no se pudo realizar la solicitud debido a un conflicto en el servidor.

Actualizar datos

El método HttpClient.PutAsync se usa para enviar la solicitud PUT al servicio web especificado por el URI y, a continuación, recibir la respuesta del servicio web, como se muestra en el ejemplo de código siguiente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  response = await client.PutAsync (uri, content);
  ...
}

La operación del método PutAsync es idéntica al método PostAsync que se usa para crear datos en el servicio web. Sin embargo, las posibles respuestas enviadas desde el servicio web difieren.

El servicio REST envía un código de estado HTTP en la propiedad HttpResponseMessage.IsSuccessStatusCode, para indicar si la solicitud HTTP se realizó correctamente o no. Las respuestas comunes para esta operación son:

  • 204 (NO CONTENT): la solicitud se ha procesado correctamente y la respuesta está en blanco intencionadamente.
  • 400 (BAD REQUEST): el servidor no entiende la solicitud.
  • 404 (NOT FOUND): el recurso solicitado no existe en el servidor.

Eliminación de datos

El método HttpClient.DeleteAsync se usa para enviar la solicitud DELETE al servicio web especificado por el URI y, a continuación, recibir la respuesta del servicio web, como se muestra en el ejemplo de código siguiente:

public async Task DeleteTodoItemAsync (string id)
{
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, id));
  ...
  HttpResponseMessage response = await client.DeleteAsync (uri);
  if (response.IsSuccessStatusCode)
  {
    Debug.WriteLine (@"\tTodoItem successfully deleted.");
  }
  ...
}

El servicio REST envía un código de estado HTTP en la propiedad HttpResponseMessage.IsSuccessStatusCode, para indicar si la solicitud HTTP se realizó correctamente o no. Las respuestas comunes para esta operación son:

  • 204 (NO CONTENT): la solicitud se ha procesado correctamente y la respuesta está en blanco intencionadamente.
  • 400 (BAD REQUEST): el servidor no entiende la solicitud.
  • 404 (NOT FOUND): el recurso solicitado no existe en el servidor.

Desarrollo local

Si va a desarrollar el servicio web REST localmente con un marco como ASP.NET Core Web API, puede depurar el servicio web y la aplicación móvil al mismo tiempo. En este escenario, debe habilitar el tráfico HTTP de texto no cifrado para el simulador de iOS y Android emulator. Para obtener información sobre cómo configurar el proyecto para permitir la comunicación, consulte Conexión a servicios web locales.