REST + AJAX = Aplicaciones WEB performantes
October 6, 2009 | Filed Under Artículos, Novedades |Por Soledad Pano y Federico Freire.
La construcción de aplicaciones web demanda cada vez más desafíos en cuanto a performance e interfaces de usuario ricas. En este artículo se presenta una solución web en donde estas premisas se cumplen haciendo uso de técnicas AJAX y servicios REST. En términos generales se trata de una aplicación que sirve páginas estáticas (o prácticamente estáticas) que mediante posteriores llamadas AJAX consultan los datos dinámicos. Este traspaso de datos se realiza mediante solicitudes HTTP con URLs tipo REST y utilizando JSON como formato de serialización, prescindiendo del protocolo SOAP. Este tipo de arquitectura aporta flexibilidad permitiendo separar los servidores web que sirven las páginas estáticas (altamente cacheables, poca carga), de los servidores de aplicación que hostean los servicios REST (también cacheables, pero en menor medida y con mayor carga de trabajo). Por otro lado, dado que la lógica de renderización ocurre en el cliente, se reduce notablemente el trabajo del lado servidor. De esta forma, además de mejorar la percepción del usuario, se reduce la carga en el servidor y mejoran los tiempos de respuesta.
El escenario planteado es el siguiente: Se tiene por un lado un servidor web que sirve el contenido “estático” que es el marco de la página (header, footer, templates) pero sin datos, de ahí que es prácticamente estático (incluso podrían ser directamente páginas HTML). Una vez que la página llega al cliente web, se solicitan y/o modifica los datos mediante uno o varios llamados AJAX hacia los servicios REST (Representational State Transfer). Los datos viajan serializados en formato JSON (JavaScript Object Notation), que es un formato liviano para el transporte y fácil de manipular mediante JavasSript para su renderizado. Los servidores de contenido pueden estar físicamente separados de los de servicio o pueden compartir también el mismo nodo según la necesidad.

Las ventajas de este tipo de arquitectura son las siguientes:
Implementación
Con el avance de los frameworks para desarrollo web, tanto server-side como client-side, la implementación de este tipo de arquitectura se facilita notablemente. En el .Net Framework 3.5 se agrega a WCF soporte para servicios REST y manejo de JSON. También el nuevo framework de ASP.NET MVC contempla operaciones ajax-friendly mediante los JsonResults. El framework de ASP.NET AJAX permite también reutilizar una capa de servicios web existente, agregando simplemente nuevos bindings. En sí lo único que se requiere del lado server es algo que responda solicitudes HTTP y devuelva los datos en formato JSON.
Ahora, dado que toda la lógica de renderizado radica del lado cliente, se deberá poner más esfuerzo en hacer las aplicaciones seguras y lidiar con problemas client-side como la capacidad multibrowser. Si bien en general las herramientas y el lenguaje del lado cliente son menos poderosos que los del lado servidor, con librerías javascript como JQuery o MS ASP.NET AJAX, se facilita bastante la tarea. En este artículo se mostrará un ejemplo sencillo de servicio REST con WCF y la utilización de JQUERY del lado cliente para renderizar los datos. Y otro ejemplo de implementación utilizando las librerías cliente de ASP.NET AJAX, las cuales simplifican aún más la implementación client-side.
WCF Rest Services
En el .Net framework 3.5, WCF incluye el nuevo webHttpBinding que permite publicar un servicio usando la semántica HTTP estándar de REST. Este nuevo binding provee un modo oficial para publicar un endpoint a través de HTTP plano (no SOAP) accesible directamente a través de un GET o POST a una URL. Además se agregan las siguientes características:
En el código de ejemplo, el proyecto RestSample contiene un servicio REST de ejemplo que devuelve espectáculos teatrales. Para la creación del servicio se deben referenciar los assemblies System.ServiceModel, System.ServiceModel.Web y System.Runtime.Serialization y en el archivo web.config exponer el siguiente endpoint:
<system.serviceModel>
<services>
<service name=”AjaxSample.Services.ShowsService“>
<endpoint address=”" behaviorConfiguration=”AjaxBehavior” binding=”webHttpBinding” contract=”AjaxSample.Services.IShowsService“/>
</service>
</services>
<behaviors>
<behavior name=”AjaxBehavior“>
<webHttp/>
</behavior>
</behaviors>
</system.serviceModel>
Otra opción, si se quiere evitar la configuración en el archivo web.config, es utilizar el WebServiceHostFactory directamente en el archivo .svc.
En la interfaz del servicio se asocia cada operación a los verbos HTTP mediante los atributos WebGet o WebInvoke y se indica la URL asociada a cada operación. Notar que los parámetros que aparezcan en el UriTemplate entre llaves deben tener el mismo nombre que los parámetros del método y estos últimos deben ser además necesariamente de tipo string.
[AjaxBehavior]
public interface IShowsService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "Categories", BodyStyle = WebMessageBodyStyle.Bare)]
List<Category> GetCategories();
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "Shows/{categoryId}", BodyStyle = WebMessageBodyStyle.Bare)]
List<Show> GetShows(string categoryId);
}
Para probar el servicio, basta con pegar la URL en un browser (por ej http://localhost:44154/Services/ShowsService.svc/Categories). Usando un debugger de HTTP como Firebug o Fiddler, se puede ver en detalle la comunicación. Se observa por ejemplo entre los headers de respuesta que el content-type es application/json y que la respuesta contiene no más que los datos serializados en formato JSON:


Como se puede ver, el formato JSON es muy liviano y no hay overhead de ningún protocolo. Cuando los objetos son muy complejos, se puede visualizar el Json de forma más amigable con herramientas como Firebug o Json Viewer.


El proyecto de CodePlex WCF REST Starter Kit contiene además extensiones para la implementación de estos servicios, como manejo de caché, errores, seguridad, etc, además de código de ejemplo.
Configurando el servicio con compatibilidad con ASP.NET se puede acceder al HTTPContext y setear acceder a los headers de solicitud y respuesta para realizar las customizaciones que sean necesarias.
Implementación Client-Side usando JQuery
Para la implementación client-side se eligió una página HTML para mostrar que se puede usar una página totalmente estática, aunque en un escenario real probablemente se quieran utilizar algunas características de las páginas dinámicas como regionalización, master pages, etc. En el proyecto RestSample se hizo usó de la biblioteca de JavaScript JQuery. JQuery es una biblioteca open source muy popular de JavaScript que además ha sido adoptada por Microsoft quien la incluye por ejemplo de forma estándar en las aplicaciones de Microsoft ASP.NET MVC. JQuery permite acceder y manipular fácilmente elementos de un documento HTML utilizando una sintaxis de selección similar a la utilizada en las hojas de estilo en cascada. También facilita la implementación de llamadas AJAX, abstrayéndonos del problema de hacer las aplicaciones multibrowser.
En la página WebApp/index.html se puede ver el llamado al servicio ShowsService y la correspondiente manipulación de datos para ser mostrados en la página.
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <title></title> <script type="text/javascript" src="Scripts/jquery-1.2.6.min.js"></script> <script type="text/javascript"> function onInit() { var categoriesURL = "../Services/ShowsService.svc/Categories"; // Call Web service proxy from script $.ajax({ url: categoriesURL, type: "GET", dataType: "json", success: getCategoriesSucceded }); } function getCategoriesSucceded(results) { var selectCategory = $("#selectCategoryView"); $.each(results, function() { selectCategory.append("<option value='" + this.Id + "'>" + this.Name + "</option>"); }); } $(document).ready(onInit); </script> </head> <body> <h2>Shows Categories</h2> <div class="categoriesContainer"> <select id="selectCategoryView"> </select> </div> </body> </html>
La página resultante es la que se ve en la figura:

Y en el Firebug podemos observar las consultas AJAX realizadas para traer los datos de categorías y de shows por categoría.

Microsoft ASP.NET AJAX
Hace unos años que Microsoft viene avanzando con tecnologías AJAX. El framework de ASP.NET Ajax de hace unos años, permite mejorar la respuesta de aplicaciones ASP.NET existentes, utilizando el UpdatePanel, pero no llega a ser tan performante como las aplicaciones AJAX puras aquí descriptas. Es por eso que la plataforma .Net también provee un framework de AJAX únicamente client-side. La biblioteca de ASP.NET AJAX client-side provee algunas herramientas interesantes para la construcción de aplicaciones de cliente rico, como la simplificación del desarrollo multibrowser, la llamada a servicios mediante proxies de javascript y la creación de controles HTML. Esta librería se incluye con ASP.NET 3.5 o se puede bajar de forma independiente de Microsoft AJAX Library. Por otro lado, la versión 4.0 de la cual puede verse un preview en ASP.NET AJAX Preview on CodePlex contiene varias características poderosas que incluyen:
- Templates client-side que permiten renderizar los datos completamente en el browser indicándolo en forma declarativa.
- Control DataView del lado cliente para crear una interfaz de usuario dinámica orientada a datos.
- Binding automático entre datos y controles HTML.
- Integración completa con WCF y ADO.NET Data Services con código cliente, incluyendo control de cambios del lado cliente.
En el proyecto AjaxSample incluido en el código de ejemplo se implementó la misma aplicación de ShowsService pero implementada con la biblioteca de ASP.NET AJAX client-side. Notar que en vez de JQuery se referencias a los JS correspondientes a esta biblioteca, y que se utiliza una referencia a ShowsService.svc/jsdebug para generar un proxy del servicio del lado JavaScript y acceder a sus operaciones de forma transparente.
Una de las características más sobresalientes del framework de ASP.NET AJAX es la posibilidad de utilizar templates. Esto permite incluir en la página HTML el formato en donde irán los datos, poniendo entre llaves las propiedades que se reemplazará luego por los datos. Como el mismo está asociado a un control JS de tipo Sys.UI.DataView, al volver los datos provenientes del servicio el framework se encargará de dibujarlos en el template correspondiente de forma automática.
<html> <head> <script type="text/javascript" src="MicrosoftAjax/MicrosoftAjax.debug.js"></script> <script type="text/javascript" src="MicrosoftAjax/MicrosoftAjaxTemplates.debug.js"></script> <script type="text/javascript" src="../Services/ShowsService.svc/jsdebug"></script> <script type="text/javascript"> function pageLoad() { // Create DataView ddlCategory = $get("selectCategoryView"); categoriesView = $create(Sys.UI.DataView, null, null, null, ddlCategory); // Call Web service proxy from script IShowsService.GetCategories(getCategoriesSucceded); } function getCategoriesSucceded(results) { // Set returned data on DataView categoriesView.set_data(results); } </script> </head> <body> <h2>Shows Categories</h2> <div class="categoriesContainer"> <select id="selectCategoryView" class="sys-template"> <option value="{{Id}}">{{Name }}</option> </select> </div> </body> </html>
Conclusión
En este artículo se presentó una forma novedosa para construir aplicaciones de cliente rico altamente performantes. Además se mostraron algunas de las herramientas existentes actualmente para facilitar la tarea de su implementación. Es cierto que también se debe lidiar con algunos problemas que surgen en una implementación real, como ser la seguridad, la navegación con los botones del browser, la accesibilidad, clientes con javascript deshabilitado, SEO (Search Engine Optimization), cross-site scripting, etc. No obstante, todos estos problemas tienen solución y es totalmente factible la implementación de este tipo de soluciones en un caso real. Así que los invitamos a aprovechar al máximo los motores del lado cliente y empezar a escribir aplicaciones AJAX que mejoren la performance y la experiencia de usuario.