Servicios Web, Parte II: Xojo Web, a tu servicio (API 2.0)

En un artículo anterior vimos como crear una app web que actuara como un servicio web mediante la implementación de una API consistente en un par de métodos, y el uso de una base de datos SQLite como backend para los datos.

En esta segunda parte nos centraremos en la aplicación Desktop que actuará como cliente y que estará a cargo de realizar las peticiones sobre la API públic de nuestro servicio web. Esta app desktop enviará nuevos datos a nuestro servidor web que serán añadidos a la base de datos.

Los principales temas tratados son:

  • Crear una subclase de la clase URLConnection
  • Tratar con los datos recibidos desde el servidor como resultado de la petición realizada
  • Codificar un JSONItem para el envío de datos al servicio web.

Como se indicaba en el anterior artículo, el ejemplo no incluye las habituales (y recomendadas) operaciones de verificación para los datos proporcionados y recibidos desde el servidor, sino que nos centramos en el principal tema tratado.

Crear una subclase de URLConnection

Comencemos creando un nuevo proyecto desktop. Añade una nueva Clase usando la opción Insert > Class en combinación con el Panel Inspector para asignar URLConnection como su tipo de dato Super tal y como se muestra en la imagen:

Con la clase recién añadida aún seleccionada en el Navegador, añade una nueva propiedad (Insert > Property). Utilizaremos esta propiedad con los datos recibidos desde nuestro servicio web. Con la propiedad recién añadida aun seleccionada, utiliza el Panel Inspector para definir su tipo de dato y Nombre con los siguientes valores:

  • Name: List
  • Type: DesktopListBox
  • Scope: Private

Observar que el ámbito está definido como Private. Esto significa que se puede acceder a la propiedad sólo desde las instancias de la clase, y no desde cualquier otro tipo de dato.

URLConnection: Comunicaciones asíncronas

¿Por qué querríamos mantener una referencia a un control de ListBox en nuestra clase URLConnection? Tal y como ocurre con cualquier otro problema, podemos tomar varios caminos para implementar una solución. En este caso, se trata de un modo bastante conveniente de obtener una referencia al control sobre el cual realizaremos la actualización de los datos recibidos cuando usamos URLConnection de forma asíncrona.

Una vez que iniciamos la petición contra el servicio web, la ejecución de la aplicación no se queda suspendida hasta recibir la respuesta. Esto permite que la interfaz de usuario no se quede bloqueada. En este caso, la instancia de la clase será la responsable de recibir los datos desde el servicio web de modo asíncrono mediante el evento ContentReceived.

De hecho este es nuestro siguiente paso. Con la subclase URLConnection aun seleccionada en el Navegador, añade un nuevo Evento (Insert > Event Handler…). En la ventana resultante, selecciona la opción PageReceived en el listado y confirma la selección, de modo que el evento se añada a la clase.

Ahora, con el evento recién añadido aun seleccionado, escribe el siguiente fragmento de código en el Editor asociado:

#Pragma Unused url

If HTTPStatus = 200 Then // We received an OK as the status for our request
  If Content.Length <> 0 Then // And we have data to process as part of the reply
    List.RemoveAllRows // So we delete previous existing entries in the associated ListBox Control
    content = content.DefineEncoding(Encodings.UTF8) // We set the encoding for the received data
    
    Var items As Dictionary = ParseJSON(content) // And proceed to create a new dictionary from the received data in JSON format
    items = items.Value("AllAlbums") // We get all the items for the key 'AllAlbums'…
    For Each item As DictionaryEntry In items // …iterating on them…
      Dim tempDict As Dictionary = item.Value // …and retrieving the dictionary (JSON item) for it…
      Dim title As String = tempDict.Value("title") // …so we finally access the desired value
      list.AddRow title
    Next
  End If
End If

El código está comentado de modo que puedas saber lo que ocurre en cada línea del proceso, pero conviene resaltar que el evento ContentReceived nos proporciona todos los parámetros que necesitamos para trabajar con los datos enviados desde el servicio web:

  • URL: El URL devuelto como respuesta de la petición.
  • HTTPStatus: El código de estado HTTP que deberías comprobar para verificar el éxito de la petición.
  • Content: Esta es una String que contiene los datos asociados con la respuesta por parte del servidor.

También puedes añadir un manejador de evento adicional a nuestra subclase: Error. Este se disparará cuando se produzca un error en la realización de las peticiones realizadas desde la instancia.

Con los eventos y la propiedad añadidos es hora de crear el par de métodos encargados de indicar a nuestra subclase URLConnection que lance las peticiones. Para nuestro ejemplo, el nombre de dichos métodos están directamente relacionados con las operaciones que queremos realizar sobre la API del servicio web creado en la primera parte de este tutorial.

De modo que, con la clase URLConnection aún seleccionada en el Navegador, añade un nuevo método (Insert > Method), usando los siguientes valores en el panel Inspector asociado. Este es el método encargado de solicitar a nuestro servicio web el nombre de todos los álbumes disponibles. Por supuesto, esperamos recibir la respuesta a través del evento ContentReceived:

  • Method Name: GetRequest
  • Parameters: theList As DesktopListBox, theURL as String
  • Scope: Public

Como puedes ver, este método espera recibir una referencia a un control DesktopoListBox, así como el texto correspondiente al URL que debería ser el punto de llamada para nuestro servicio web. Escribe ahora el siguiente código en el Editor de Código asociado con el método recién añadido:

List = theList
self.send("GET", theURL)

Sencillo, ¿verdad? Como puedes ver, guardamos la referencia al control DesktopListBox en la propiedad de la instancia, de modo que podamos usarlo posteriormente para actualizar sus contenidos con los datos recibidos. Luego usamos el método Send de la clase con el verbo GET y el URL en el que debería de estar escuchando nuestro servicio web. Como se indicaba anteriormente, esta es una operación asíncrona por lo que dejaremos que nuestro objeto reaccione a través de los eventos ContentReceived o Error.

URLConnection: Enviar datos como parte de la petición

Añade un nuevo método a la subclase utilizando los siguientes valores en el Panel Inspector resultante. Este es el método que nos permitirá enviar datos al servicio web de modo que se añadan a la base de datos del backend:

  • Method Name: SendItem
  • Parameters: Item As JSONItem, theURL As String
  • Scope: Public

En esta ocasión el método espera recibir un objeto JSONItem (a través de la variable Item) y una instancia de String que debería corresponderse con el URL del punto de entrada en el servicio web. Escribe el siguiente código en el Editor de Código asociado para el método:

Self.SetRequestContent( item.ToString, "application/json" )
self.Send("POST", theURL)

Las instancias de URLConnection nos permiten asociar información adicional (datos) para la petición realizada, además de otros valores añadidos a través de las cabeceras HTTP (Head), usando para ello el método SetRequestContent. Este método espera dos parámetros: una String con el valor que queremos asignar, y la definición del tipo de dato que estamos enviando (esto es, el tipo MIME) como una instancia de String.

Por último lanzamos la petición en la segunda línea de código usando para ello el URL asignado en el parámetro theURL en combinación con el verbo POST.

Diseñar la Interfaz de Usuario

Ya hemos terminado con toda la lógica para nuestra aplicación de ejemplo mediante la subclase URLConnection. Ahora es el momento de diseñar una interfaz de usuario minimalista de modo que podamos verificar la correcta funcionalidad de nuestro cliente contra el servicio web.

Selecciona el objeto Window1 y añade los controles requeridos de modo que tenga un aspecto como el mostrado en la siguiente imagen (de arriba hacia abajo): Un DesktopListBox, un par de DesktopTextField con dos DesktopLabels asociadas y dos DesktopPushButtons con las etiquetas “Request” y “Send”.

A continuación añade una instancia de la subclase URLConnection que hemos creado. Para ello, sólo has de arrastrar la subclase creada desde el Navegador hasta el Editor de Diseño de Window1. Al hacerlo se añadirá una nueva instancia de la subclase en el área de la bandeja (franja inferior del Editor de Diseño), tal y como se muestra en la siguiente imagen:

El único código presente en la interfaz de usuario es el que añadiremos a los dos botones. Haz doble click en el etiquetado “Request” y añade la siguiente línea de código en su manejador de evento Pressed:

MyConnection1.getRequest(AlbumListbox, "http://127.0.0.1:8081/GetAll")

Este llama al método getRequest en la instancia creada a partir de nuestra subclase, enviando como parámetros el control “ListBox1” y el texto correspondiente al URL (local) en el que debería de estar escuchando el servicio web.

Haz doble clic en el botón etiquetado “Send” para añadir el manejador de evento Pressed, y escribe el siguiente fragmento de código en el Editor de Código asociado:

Var d As New Dictionary
d.Value("Title") = TitleField.Text
d.value("ArtistId") = ArtistIDField.Text
Var item As New JSONItem
item.Value("newAlbum") = d

MyConnection1.sendItem(item,"http://127.0.0.1:8081/AddAlbum")

Como puedes ver no hay nada mágico en ello. Simplemente creamos un nuevo diccionario usando las claves esperadas en el lado de nuestro servicio web para acceder a los datos subyacentes del registro. Además, puedes ver cuán sencillo resulta crear un nuevo JSONItem a partir de un diccionario.

A continuación simplemente llamamos al método sendItem en la instancia de nuestra subclase URLConnection, pasando los parámetros esperados: una instancia de JSONItem y el URL correspondiente al punto de llamada para la API remota.

¡Listo para atender vuestras solicitudes!

Ya hemos terminado de crear nuestra app cliente. Ejecuta el servicio web creado en la primera parte del tutorial (asegúrate de que esté escuchando en el puerto 8081). A continuación, ejecuta el cliente desktop y pulsa sobre los botones para “enviar” o “solicitar” información. Verás que con el botón de Request el ListBox se actualizará con las entradas correspondientes a todos los álbumes disponibles en la base de datos de ejemplo, mientras que con el botón “Send” se añadirán nuevos registros con el título y el ID que hayas introducido en los dos campos de texto.

En conclusión, Xojo nos permite crear tanto el lado del servidor como múltiples clientes multiplataforma en un tiempo récord y de forma realmente sencilla. Obviamente, los ejemplos utilizados en estos dos artículo no son, de lejos, soluciones completas que puedas usar “tal cual”, pero te proporcionan las bases suficientes como para que puedas crear soluciones más robustas y completas que se ajusten a tus propias necesidades.

Deja un comentario

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