WCF REST /Conditional GET: Save Bandwidth

Aunque para muchos es desconocido, el estilo REST es cada vez más usado dentro de muchas aplicaciones, numerosos son los ejemplos, Data Services, muchas de las API’s de AZURE y por su puesto en otras plataformas como Google, Amazon etc….

La llegada de .NET 3.5 nos permitió crear servicios REST de una forma simétrica a como hacíamos nuestros servicios SOAP, es lo que tiene tener una arquitectura extensible y plugable, gracias a unos pequeños cambios en los protocolos de mensajería y dispatcher ( básicamente establecer SoapVersion a None y asignación de métodos a ejecutar por medio de identificadores de recursos y no por la cabecera Action  de los sobres). Una de las cosas que no se suelen comentar dentro de los servicios REST es la posibilidad de tocar las cabeceras HTTP para obtener muchas de las posiblidades que los programadores Web ya conocen y utilizan habitualmente. A lo largo de este artículo hablaremos de un par de cabeceras interesantes que tiene que ver con el manejo de la cache como son Is-Modified-Since y If-None-Match. Estas dos cabeceras vienen a resolver ciertos problemas de cache cómo son la imposibilidad de los clientes de de tolerar ciertos estados (Cache-Control,Pragma ) o expiraciones de ‘caching hints’ como Expires.

Como bien dice la especificación de HTTP sobre temas de cache, la mejora de disponer de cache no solamente viene por la eliminación de peticiones al servidor sino también por eliminar las respuestas completas que estos nos den. Las cabeceras mencionadas anteriormente tiene este último propósito, eliminar respuestas completas, por medio del uso de un código de estado 304, también conocido como Not-Modified. Los que me conocéis sabéis que me resulta mucho más sencillo explicar las cosas con algún ejemplo de código por lo que vamos al trabajoJ.

Vamos a suponer que disponemos de una interfaz de servicio REST muy simple, como la mostrada a continuación:

Si alojamos este servicio convenientemente y hacemos repetidas peticiones a ‘http://dominio/servicio/Users/13’ podremos ver, mediante alguna herramienta de inspección del tráfico HTTP como Fiddler, como esta petición es procesada en el servidor y este devuelve siempre respuestas completas.

 

REST_Figure1

Nuestra idea de uso de las cabeceras anteriormente mencionadas es la de disponer de un mecanismo para averiguar si lo que el cliente de nuestros servicios REST está pidiendo es un elemento previamente consultado y no modificado en el servidor.

Empezaremos viendo como incorporar Is-Modified-Since dentro del código de nuestro método de servicio, ver código siguiente:

 

Tal y como podrá observar en el fragmento de código anterior una vez obtenido el usuario solicitado establecemos dentro del contexto de respuesta al cliente el elemento LastModified, valor de la cabecera Is-Modified-Since. Con esta simple opción conseguimos que el cliente reciba el valor de esta header y pueda entregárnosla en futuras peticiones para verificar si le damos una respuesta completa o bien un código de estado 304 y obtenga el resultado de la petición de la caché del navegador, por ejemplo.

Volvamos a realizar un par de peticiones ahora con este pequeño cambio y veremos como la respuesta del servidor incluye nuestra nueva cabecera.

 

 

REST_Figure2

 

Una vez que ya sabemos cómo enviar nuestra cabecera solamente nos queda verificar el valor de la misma dentro del código de nuestro servicio con el fin de determinar si al cliente le enviamos la respuesta completa o el valor de ‘No hay cambios en la petición’. Esto lo conseguimos dentro del método de nuestro código anterior ChechIfModifiedSince que presentamos a continuación.

 

 

Fíjese como este método lo único que realiza es la comparación de la header con un valor, en nuestro caso por sencillez dentro del elemento User, que nos permita evaluar si el elemento ha cambiado comparando para ello un par de elementos de tipo DateTime y estableciendo como código de salida el valor 304, NotModified, en caso afirmativo. Hecho este trabajo puede probar a realizar distintas peticiones al servidor y verá como este mecanismo reduce el ancho de banda necesario para nuestros servicios puesto que las respuestas no serán completas sino un simple código 304.

El funcionamiento de la cabecera If-None-Match es realmente similar a If-Modified-Since, la principal diferencia es que la comparación de cambio no se realiza sobre un campo fecha sino sobre un elemento conocido como etag o entity tag, el cual no es más que la expresión de una entidad en un punto en el tiempo, pudiendo establecerse como un hash un guid o lo que nosotros deseemos. Este valor de etag es el que utilizaremos para saber si una entidad ha cambiado y proceder a dar una respuesta completa al servidor o bien devolver un 304 como anteriormente realizamos.

 

 

P.D: Entity Tag también es utilizado en ADO.NET Data Services para manejar la concurrencia optimista, podéis ver una referencia aqui

Espero que os resulte de utilidad,

Unai Zorrilla