Implementando características de OData con ASP.NET WebAPI

En esta nueva entrega sobre ASP.NET Web API vamos a hablar sobre las características que este soporta del protocolo Open Data Protocol (de ahora en mas OData).

Open Data Protocol

Open Data Protocol

Antes de comenzar, vamos a realizar una pequeñísima introducción a Open Data Protocol.

OData es un protocolo abierto – open protocol – creado por Microsoft para exponer datos como servicio. Este se basa en estándares conocidos de Internet como HTTP, Atom (AtomPub) y JSON. Como todo protocolo de servicios, uno de los fines principales es poder independizar los datos de la aplicación o sitio web que los utiliza. Los clientes que consumen servicios a través el protocolo OData pueden hacerlo bajo formatos como Atom, JSON o XML plano, pero además incluyendo características como paginación, ordenación y filtrosquerys -.

Otra característica interesante de OData es que nos permite exponer y acceder a información de una gran variedad de fuentes, incluyendo, bases de datos relacionales, sistemas de archivos, sistemas de gestión de contenidos y sitios web tradicionales.

Escenarios de despliegue de OData

Escenarios de despliegue de OData

Ahora bien, de todas las características que ofrece OData, la que nos interesa en este momento es la utilización de convenciones URI que nos permitirán, entre otras cosas, realizar operaciones como navegación, filtrado, orden y paginación de datos en la solicitud de un recurso.

URI Components

URI Components

La utilización de estas convenciones nos permiten, desde la misma URI del recurso, especificar query options que serán aplicadas al momento de obtener un recurso. Podemos ver en el gráfico anterior – URI Components – que las opciones de consultas se especifican al final de la URI.

Ejemplos de query options son:

  • $filter : permite aplicar filtros sobre el resultado.
  • $orderby : permite ordenar por alguna condición el resultado
  • $top : permite recuperar un cierto número de resultados.
  • $skip : permite saltear un cierto número de resultados.

Vayamos a un ejemplo, si quisiera obtener la lista de clientes ordenadas por nombre, debería invocar al servicio utilizando la siguiente URI:

http://localhost:[port]/api/clientes?$orderby=Nombre

Ahora bien, ASP.NET Web API trae soporte para un subconjunto de características del protocolo OData. Una de ellas es que podemos trabajar con las convenciones URI que trabajaran en la interacción con los controladores de nuestra API.

Para trabajar con ellas simplemente debemos modificar el tipo de datos de la respuesta de nuestro método. Recordaran que en post anteriores el método retornaba un objeto IEnumerable:

Método de acción Get() retornando un IEnumerable

Método de acción Get() retornando un IEnumerable

En este caso debemos vamos a modificar la firma y el cuerpo del método para que retorne un objeto IQueryable:

Método de acción Get() retornando un IQueryable

Método de acción Get() retornando un IQueryable

Tal como menciona MSDN, el motivo de esta cambio es que la interfaz IQueryable hereda la interfaz IEnumerable, por lo que si representa una consulta, se pueden enumerar los resultados de esa consulta (la enumeración provoca la ejecución del árbol de expresión asociado a un objeto IQueryable). Es tarea del framework armar la consultas correctamente a partir de las query options enviadas en la URI.

Realizado el cambio, vamos a consumir el servicio como lo veníamos haciendo normalmente utilizando la siguiente URI:

http://localhost:[port]/api/clientes
Datos obtenidos del servicio

Datos obtenidos del servicio

Podemos observar que los resultados vienen en el mismo orden que los habíamos agregamos en el array (es decir, sin estar ordenados por alguna condición). Ahora solicitemos el mismo recurso, especificando que vengan ordenados por el atributo nombre:

http://localhost:[port]/api/clientes?$orderby=Nombre
Datos obtenidos del servicio utilizando las convenciones de URL

Datos obtenidos del servicio utilizando las convenciones de URL

Como vemos, utilizando las convenciones URI, es muy simple establecer condiciones-acciones-funciones en la obtención de los recursos! 🙂

Pero eso no es todo, también podríamos trabajar con paginación y filtros. Simplemente debemos agregar en la URI la query correspondiente de acuerdo a nuestras necesidades, algunos ejemplos:

http://localhost:[port]/api/clientes?$filter=Nombre eq ‘Jous’
  • Filtrar utilizando operadores lógicos:
http://localhost:[port]/api/clientes?$filter=Nombre eq ‘Sebis’ or Nombre eq ‘Jous’
http://localhost:[port]/api/clientes?$top=3&$skip=0

También tenemos disponibles un gran conjunto de opciones de query dentro de las cuales podemos encontrar: Select, Top, OrderBy, Expand, Format, DateTime Functions, Math Functions, Type Functions y muchísimas otras más.

Para finalizar, quería comentarles que OData dispone de un conjunto de API’s de creación y consumo de Servicios OData para trabajar desde el lado del cliente con dispositivos mobiles (WP7, Android, iOS), app webs (Silverligth, ASP.NET, HTML 5 + Javascript, Java, PHP, Ruby) y web CMS (Joomla, Drupal). Y también desde el lado del servidor con custom servers (.NET Server, Java, PHP, Node.JS),  databases (SQL Server, MySql, Azure Data) y cloud app (App Engine, Azure).

Espero que les sea de utilidad.

Nos vemos pronto!

Anuncios

ASP.NET Web API: Validando con Global Action Filters

En esta cuarta entrega sobre ASP.NET Web API veremos como aplicar validaciones a nivel global del proyecto. Si observamos la forma en que manejamos los errores del modelo en el método de acción Post(), podemos identificar un patrón común para todas las validaciones:

Validación del modelo

Validación del modelo

Por lo tanto, porque no gestionarlo de manera global,y despreocuparnos de este tema. ASP.NET MVC nos proporciona un mecanismo para esto, y son los Global Action Filters que nos permiten ejecutar lógica antes o después de un método de acción (sobre este tema ya habíamos hablamos en este post).

Momento de definir el filtro de acción global que llamaremos ValidationActionFilter:

Definición del filtro de acción ValidationActionFilter

Definición del filtro de acción ValidationActionFilter

Acto seguido, registrar el filtro de acción en el método Application_Start() del archivo Global.asax:

Registrando el filtro de acción

Registrando el filtro de acción

Finalmente limpiamos el método de acción Post():

Método de acción Post()

Método de acción Post()

Probemos nuevamente el formulario, y las validaciones deberían actuar de la misma forma:

Validaciones del formulario

Validaciones del formulario

Espero que les haya servido y en próximos post vamos a continuar con más características de ASP.NET Web API.

ASP.NET Web API – Aplicando Validaciones

En esta tercera entrega acerca de ASP.NET Web API veremos como podemos aplicar validaciones dentro de nuestros servicios. Al igual que con ASP.NET MVC, Web API utiliza el Defaul Model Binder para realizar las validaciones, lo cual es una excelente noticia para quienes trabajamos con el framework.

Arranquemos!… el primer paso será agregar los atributos de validación a la clase Cliente, utilizando la librería DataAnnotations para tal fin:

Aplicando los atributos de validación al modelo

Aplicando los atributos de validación al modelo

Hecho esto, tenemos que ambas propiedades del modelo serán “requeridas” (obligatorias) y que el nombre de usuario tendrá como máximo 4 caracteres de longitud. Aclaración: agregué un nuevo atributo – User – a modo de hacer un poco mas completo el ejemplo.

Ahora viene lo interesante, vayamos al método de acción Post() y agreguemos la lógica necesaria para validar que los datos del cliente que llegan del servicio sean correctos:

Método de acción Post() redefinido

Método de acción Post() redefinido

Como verán, hicimos algunos cambios respecto a como a la definición del método de acción Post() de la entrada anterior. Ahora, previo a la creación del cliente, tenemos que validar que el modelo sea correcto – ModelState.IsValid – y en el caso de serlo, agregar de alguna manera los errores a la respuesta HTTP para notificarle al cliente. La forma de hacerlo es consultando las propiedades del ModelState que posean errores para recuperar los “mensajes de error” de las mismas. Luego creamos un objeto del tipo JsonArray – recuerden incluir el namespace System.Json – al cual agregar esta información. Una vez hecho todo esto, armamos la respuesta HTTP que vamos a devolver, incluyendo el código de estado HTTP 400 – Bad Request (el cual vamos a usar para identificar cuando la validación fue incorrecta) y los mensajes de error serealizados.

Momento de ir a la vista y agregar: un nuevo campo de texto para permitir la carga del nombre de usuario y un div donde vamos a visualizar los errores que pueden producirse en la creación del cliente:

Modificando la vista

Modificando la vista

Llego el momento de trabajar en el script, de forma tal que procese el resultado de las validaciones en caso de que las mismas no hayan sido correctas. Lo primero será modificar la función crearCliente():

Modificando la función crearCliente() del script Clientes.js

Modificando la función crearCliente() del script Clientes.js

Como pueden observar, uno de los cambios que hicimos en la función fue agregar una nueva función de callback en los parámetros. Esta nueva función llamada callbackFail se invocará solamente cuando ocurran errores en la validación del modelo, es decir, cuando el valor del código de estado – statusCode – devuelto por el servicio sea HTTP 400 – Bad Request. Para trabajar con los errores, debemos consultar a la propiedad responseText que recibimos en el objeto xhr – del tipo XmlHttpRequest – devuelto por el servicio (es importante serializarla antes de enviarla a la función de callback).

Pueden inspeccionar el resultado del servicio, cuando el modelo no es correcto, y observar la propiedad responseText con el arreglo de los errores:

Resultado del servicio cuando el modelo no es correcto

Resultado del servicio cuando el modelo no es correcto

Ok, llego el momento de modificar el evento click del botón “Crear”:

Modificando el evento click del botón "Crear"

Modificando el evento click del botón “Crear”

Bien, en este punto simplemente lo que hacemos es recibir el array con los mensajes de error y “dibujarlos” en el div que creamos en la vista para tal fin. Queda en ustedes ver la mejor forma de visualizar los errores :).

Probemos lo hecho:

Consumiendo los servicios desde nuestra app

Consumiendo los servicios desde nuestra app

Resumiendo, podemos ver que el manejo de las validaciones no difiere demasiado de la forma en que lo veníamos haciendo en los proyectos ASP.NET MVC. Simplemente tenemos que modificar el formato en que vamos ha devolver las mismas adaptándonos a los estándares REST.

En próximos post vamos a seguir viendo otras características de Web API.

ASP.NET Web API paso a paso

En el post anterior, hicimos una introducción al estilo de arquitectura REST y la forma de implementarlo utilizando ASP.NET Web API, un tipo de proyecto nuevo que nos provee ASP.NET MVC 4. En esta oportunidad vamos a seguir hablando de ASP.NET Web API y la forma de consumir nuestros servicios REST desde una aplicación web. La invocación a los mismos lo haremos por medio de llamadas AJAX utilizando la librería de Javascript jQuery.

En el ejemplo, construiremos una única página en la cual concentraremos todas las operaciones CRUD que se pueden realizar sobre los clientes (por si no lo recuerdan, el modelo utilizado en el post anterior fue precisamente la entidad Cliente). Es importante resaltar, antes de continuar, que en un mismo proyecto pueden convivir sin problemas una aplicación web ASP.NET MVC y los servicios REST implementados con Web API, por lo que no será necesario generar otro proyecto para tal fin.

A trabajar!… el primer paso será agregar  una nueva vista, que vamos a llamar GestionClientes. Para esto agregamos el método de acción GestionClientes() en el controller HomeController:

Creando el método de acción GestionClientes

Creando el método de acción GestionClientes

Acto seguido, crear la vista correspondiente. Para eso hacemos click derecho sobre el método de acción GestionClientes() y seleccionamos la opción “Add View“. En el dialogo que se nos abre elegimos Razor como ViewEngine y la Master Page que viene por defecto en el proyecto:

Agregando la vista GestionClientes

Agregando la vista GestionClientes

Si vamos a la definición de la master page, nos vamos a encontrar con que ya tenemos registrados todos los archivos de scripts de la carpeta Scripts gracias al sistema de compactación y minimización de scripts y CSS que nos provee ASP.NET MVC 4 (por lo que no hará falta agregar la referencia a las librería de jQuery que necesitamos utilizar):

Caching de bundles

Caching de bundles

En caso de no utilizar la master page por defecto o simplemente están trabajando sobre un documento HTML, agregar la referencia a la librería jQuery (en el ejemplo estamos utilizando la versión jquery-1.6.2.js).

El próximo paso es crear el script JS donde estará la lógica desde la cual vamos a realizar las llamadas AJAX a nuestro servicio REST. Dentro de la carpeta Scripts, agregamos un nuevo ítem JScript File llamado Clientes.js:

Agregando el script Clientes.js

Agregando el script Clientes.js

Para terminar esta primer parte, modificamos la vista GestionClientes.cshtml con la siguiente estructura (no me hago responsable del diseño de la misma :)):

Modificando la vista ClientesGestion

Modificando la vista ClientesGestion

Con este paso ya tenemos todo preparado para empezar. Para seguir un cierto orden en el desarrollo, vamos a ir trabajando con cada una de las operaciones CRUD que habíamos definido en el post anterior.

GET – Obtener la representación de una la lista de clientes

En esta primer operación, la intención es poder recuperar la lista de todos los clientes para visualizarlos en la página. Revisemos la entrada correspondiente:

RECURSO MÉTODO OPERACIÓN URI
Lista de Clientes GET Obtener la representación de una la lista de clientes. http://localhost:%5Bport%5D/Api/Clientes/

Muchos ya se habrán dado cuenta de que lo más simple de hacer es una llamada AJAX (utilizando lógicamente el verbo HTTP GET) y recuperar la lista de clientes para visualizarlos de alguna manera en la página… y están en lo correcto, así que manos a la obra!

El primer paso es actualizar el método de acción Get() del controlador ClientesController:

Definiendo el método de acción Get()

Definiendo el método de acción Get()

En este caso no vamos a trabajar contra una base de datos, ya que la intención del post es mostrar la forma de invocar los servicios REST, por lo que vamos a crear una propiedad en el controlador con una lista de objetos Cliente emulando un simplísimo repositorio de datos.

El segundo paso es escribir la lógica necesaria para recuperar y visualizar los clientes en la página. Para eso vamos a agregar lo siguiente dentro del archivo de script Clientes.js:

Script para recuperar los clientes

Script para recuperar los clientes

Momento de comentarles un poco sobre el código. Lo que hicimos fue crear la función recuperarClientes() desde la cual realizamos la petición AJAX para invocar al método Get() del servicio REST utilizando la función $.getJSON() que nos provee jQuery. A la función $.getJSON() le pasamos dos parámetros: el primero es la URL a la cual se hará la llamada, y el segundo una función de callback que se ejecutará una vez que este lista la respuesta del servidor. La función de callback recibirá en una colección de objetos – clientes – JSON el cual vamos a recorrer para armar el HTML que se mostrará en la página (pueden notar que en este caso la negociación cliente-servidor determina que la respuesta no sea un XML, como en el post anterior, sino que sea en formato JSON).

Si ejecutamos la aplicación, y entramos a la página recién creada, veremos la lista de clientes obtenidas desde el servicio ;). Es importante entender que la llamada al servicio se hizo por medio del verbo HTTP GET, y solo tuvimos que especificar la URL del servicio – ‘/api/clientes/’ – sin necesidad de especificar el nombre del método que necesitábamos (internamente el servidor mapeará la petición realizada con el verbo HTTP GET – y sin parámetros -, con el método de acción Get() del controlador ClientesController).

Recuperando y visualizando la lista de clientes

Recuperando y visualizando la lista de clientes

GET – Obtener la representación de un cliente

La segunda operación con la que vamos a trabajar es la búsqueda de un cliente por el Id. Repasemos la operación correspondiente:

RECURSO MÉTODO OPERACIÓN URI
Cliente GET Obtener la representación de un cliente. http://localhost:%5Bport%5D/Api/Clientes/5

A diferencia del método anterior, puede ocurrir que devolvamos un resultado, o que invoquemos al servicio con un Id de un cliente inexistente. En este último caso se debería informar al usuario de dicha situación. Como los servicios web basados en REST intentan trabajar de manera similar al protocolo HTTP, podemos hacer uso de los códigos de estado HTTP  para informa acerca de estos casos. Por ejemplo, podríamos utilizar el código de estado HTTP 404 Not Found si se intenta recuperar un cliente que no existe, y un código de estado HTTP 500 Internal Server Error si ocurrió un error en el procesamiento (este último en realidad ocurre sin necesidad de especificarlo).

Aclarado esto, trabajemos sobre nuestro el método de acción correspondiente:

Definiendo el método de acción Get(int id)

Definiendo el método de acción Get(int id)

Modificamos la vista:

Modificando la vista ClientesGestion

Modificando la vista ClientesGestion

Ahora, es el momento de trabajar nuevamente sobre nuestro script:

Agregando lógica al script Clientes.js

Agregando lógica al script Clientes.js

Veamos rápidamente el código que agregamos al scritp. Antes que nada definimos el evento click del botón “Buscar”  – ver la parte final del código-. En dicho evento vamos a recuperar el Id del cliente que el usuario ingreso en la caja de texto con el atributo Id=“IdCliente” – selector $(‘#IdCliente’). Luego llamamos a la función buscarCliente(id, callback) pasándole además del Id del cliente, una función de callback que se ejecutará en caso de que la búsqueda sea exitosa. Esta función de callback recibirá como parámetro nuestro un objeto cliente – serealizado en  formato JSON – que usaremos para armar la porción de HTML que visualizaremos en la página.

La función buscarCliente(id, callback) recibe como parámetro el Id del Cliente que queremos recuperar, y a partir de ese dato hace la invocación AJAX al servicio. Dentro de los parámetros vamos ha indicar: la URL del servicio – url:‘/api/clientes/’-,  los parámetros que espera el servicio – { id : id } – (el cual va permitir al servidor identificar cual de los dos métodos GET llamar), el verbo HTTP – type:“GET” – y el formato de respuesta eperado – contentType:“application/json;charset=utf-8″.

Un punto importante a tener en cuenta es la forma en que vamos a procesar la respuesta del servicio. Un buen recurso que nos provee la función $.ajax de jQuery es que podemos invocar distintas funciones a partir del código de estado – “statusCode” – que retorne el servicio! 🙂 En este caso, si el código de estado HTTP es 200 OK, invocamos a la función de callback para visualizar la información por pantalla. Por el contrario si el código de estado HTTP es 404 Not Found, le podemos informar al usuario que no se encontró el cliente. También podríamos procesar el código de estado HTTP 500 Internal Server Error cuando ocurran problemas del lado del servidor para notificar al usuario (lo dejo como tarea para el hogar).

Veamos un ejemplo cuando buscamos un cliente que existe:

Búsqueda de clientes en la vista

Búsqueda de clientes en la vista

Ahora un ejemplo intentando buscar un cliente inexistente:

Cliente no encontrado!

Cliente no encontrado!

POST – Crear un cliente

Ahora llego el momento de poder crear un nuevo cliente. Inspeccionemos la entrada:

RECURSO MÉTODO OPERACIÓN URI
Cliente POST Crear un cliente. http://localhost:%5Bport%5D/Api/Clientes/{cliente}

Empecemos con el método de acción, el cual va a tener la siguiente estructura:

Definiendo el método de acción Post

Definiendo el método de acción Post

Respecto de las operaciones anteriores, la definición de este método es algo diferente. Pueden ver que en este caso, el parámetro que recibe es el cliente que queremos crear (veremos mas adelante como enviarlo). La respuesta también es algo diferente a lo que veníamos trabajando. En este caso, luego de que hayamos creamos el nuevo recurso (cliente) vamos a armar el mensaje de respuesta HTTP que viajará en el encabezado de la misma y que contendrá, entre otras cosas, la ubicación del nuevo recurso (el cual se encuentra bajo la URI “/api/clientes/idNuevoCliente”) y el código de estado que corresponde a dicha operación: HTTP 201 Created (HttpStatusCode.Created).

En la vista vamos a agregar lo siguiente:

Actualizando la vista GestionClientes

Actualizando la vista GestionClientes

Momento de trabajar nuevamente en el script:

Actualizando el script Clientes.js

Actualizando el script Clientes.js

En cuanto a la asignación al evento “click” del botón “Crear cliente” es muy similar a la que hicimos en la búsqueda de clientes. La función que vamos a invocar es crearCliente(nuevoCliente, callback) y la función de callback que le pasaremos mostrará en una ventana modal el Id del nuevo cliente. En esta caso la función no espera un Id, lo que  debemos pasarle es un objeto javascript con la estructura de la entidad Cliente, que luego será serealizado y enviado al servicio.

Dentro de la función crearCliente, lo que vamos a hacer es una invocación AJAX, utilizando el verbo HTTP POST (la cual se mapeará con el método Post() del servicio). En los parámetros – data – vamos a enviar los datos del cliente aplicándole la función JSON.stringify, la cual nos va a permitir serializar nuestro objeto javascript a JSON string. El resto es historia conocida, solo que este caso nos importa el código de estado HTTP 201 Create para invocar a la función de callback.

Vamos a crear el cliente:

Creando un cliente

Creando un cliente

Cargamos el nombre del cliente y presionamos “Crear”:

Cliente creado existosamente

Cliente creado existosamente

POST – Actualizar un cliente

La próxima operación con la que vamos a trabajar en la actualización de un cliente. Revisemos la tabla:

RECURSO MÉTODO OPERACIÓN URI
Cliente POST Actualizar un cliente. http://localhost:%5Bport%5D/Api/Clientes/{cliente}

Como vemos, el verbo HTTP que vamos a utilizar en esta operación es PUT. Trabajemos entonces en el método de acción correspondiente:

Definiendo el método de acción Put()

Definiendo el método de acción Put()

A diferencia del método POST, este no retorna ningún resultado. Solamente en el caso de que el cliente no exista, devolveremos el código de estado HTTP 404 Not Found.

En la vista agregamos lo siguiente:

Modificando la vista GestionClientes

Modificando la vista GestionClientes

Y agregamos al script la lógica necesaria para poder actualizar un cliente:

Actualizamos el script Clientes.js

Actualizamos el script Clientes.js

Lo que hicimos es muy similar a la creación de un cliente. El cambio más importante, es que la llamada la hacemos utilizando el verbo HTTP PUT.

Ejemplo de la edición de un cliente:

Editando un cliente

Editando un cliente

DELETE – Eliminar un cliente

La última operación en la que vamos a trabajar es la eliminación de un cliente. Revisemos la tabla:

RECURSO MÉTODO OPERACIÓN URI
Cliente DELETE Eliminar un cliente. http://localhost:%5Bport%5D/Api/Clientes/5

Trabajemos sobre el método de acción correspondiente a esta operación:

Definiendo el método de acción Delete()

Definiendo el método de acción Delete()

La lógica del método de acción es bastante simple, el primer paso es validar que el cliente que intentamos eliminar exista (de lo contrario retornamos un mensaje con el código de estado HTTP 404 Not Found). De ser afirmativo, realizamos la eliminación propiamente dicha y retornamos un mensaje con el código de estado HTTP 204 No Content.

En la vista agregamos lo siguiente:

Modificando la vista GestionClientes

Modificando la vista GestionClientes

Modifiquemos por última vez el script:

Modificando el script Clientes.js

Modificando el script Clientes.js

A esta altura, no habrá notado nada raro en esta implementación ;). Probemos:

Eliminando un cliente

Eliminando un cliente

Resumiendo, la intención de este post fue mostrarles como podemos realizar un simple AMB de clientes utilizando Web API para exponer nuestros servicios REST y jQuery para consumirlos desde el cliente. También mostrarle la importancia de los verbos HTTP para describir las distintas operaciones que podemos realizar sobre los recursos, y no quedarnos simplemente en el uso de los verbos GET o POST para tal fin.

En próximos post vamos a ver como integrar Web API con el mecanismo de routing, el soporte de Model Bindings, Validations y Actions Filters y como integrar OData.

REST con ASP.NET Web API

Una de las novedades que más entusiasmaron de la versión beta de ASP.NET MVC 4  son los templates de proyectos ASP.NET Web API. Estos nuevos “tipos” de proyectos nos permiten crear, de una manera muy simple, aplicaciones cuyo propósito es exponer servicios bajo el protocolo HTTP utilizando el estilo de arquitectura REST  (Representational State Transfer).

Antes de continuar con Web API, veamos de que se trata REST.

REST (Representational State Transfer) es un estilo de arquitectura de software para sistemas hipermedias distribuidos tales como la Web. El término fue introducido en la tesis doctoral de Roy Fielding  en el año 2000, quien es uno de los principales autores de la especificación de HTTP.

Los servicios web basados en REST intentan trabajar de manera similar al protocolo HTTP, ya que la interfaz de los mismos será establecida a partir de un conjunto conocido de operaciones estándar (por ejemplo GET, POST, PUT,…). De esta forma, nos abstraernos de los protocolos basados en patrones de intercambio de mensajes, como los utilizados en los servicios web basados en SOA (de seguro estará pensando en el viejo y conocido protocolo de servicios web SOAP).

Es importante que quede claro que REST no es un estándar, sino un estilo de arquitectura que se basa en ciertos estándares, como HTTP, URL, XML, JSON y MIME entre otros.

Volviendo a Web API, algunas de las características  de este framework son:

  • Integración con el mecanismo de routing.
  • Negociación de contenidos (cliente y servidor pueden negocias el formato del intercambio de información).
  • Soporte de Model Bindings, Validations y Actions Filters.
  • Soporte de consultas con OData.
  • Hosting autocontenido (podes publicar nuestra API en IIS o directamente con un ejecutable).

Que mejor forma de explicar todo lo que estuvimos viendo que un ejemplo ;). Para eso vamos a crear un nuevo proyecto ASP.NET MVC 4 al que llamaremos MvcWebApi. Pero ojo, para trabajar Web API debemos seleccionar, dentro de las templates del framework, la nueva plantilla de proyectos “Web Api”:

Template de proyecto Web API

Template de proyecto Web API

Podemos observar que la estructura del proyecto es similar a la de una aplicación web ASP.NET MVCtradicional” (por ejemplo los directorios utilizados por convención del framework siguen existiendo: Models, Views y Controllers como así también los archivos de configuración).

Estructura de un proyecto ASP.NET Web API

Estructura de un proyecto ASP.NET Web API

Analicemos el controlador que Visual Studio nos genera por defecto:

Definición de ValuesController

Definición de ValuesController

El primer “gran cambio” con el cual nos vamos a encontrar es que los controladores ya no heredan de Controller sino que lo hacen de ApiController. Este nuevo tipo de controlador me permite que los métodos  de acción no retornen “vistas” (ActionResult) sino que, por el contrario, devuelvan los datos propiamente dichos (el formato en que viajaran los datos, Json o XML por ejemplo, se negociara entre el cliente y el servidor). Por último, Web API trabaja por convención en lo que respecta a los nombres de los métodos de acción y los verbos HTTP, por lo tanto no es necesario decorar un método con el atributo [HttpPost] para establecer que es un método POST. Lo que tenemos que hacer es simplemente llamar al método de acción Post() (también podemos modificar el nombre del método,  siempre que el mismo termine con el nombre del verbo HTTP, como por ejemplo: ClientPost()).

Detengamonos un momento en este último punto, y retornemos a REST. Un aspecto muy importante de este estilo de arquitectura es que trabaja con recursos. Esto que quiere decir?… que cada servicio que invoquemos, intentará realizar una operación, de un conjunto conocido de operaciones, sobre un recurso o una serie de recursos (cada uno de estos recursos serán identificados mediante URIs como veremos más adelante).

Dicho esto, se podrán imaginar que existe cierta similitud entre los tipos de petición HTTP y las operaciones que podemos realizar sobre los recursos con nuestro servicio. Una aproximación podría ser la siguiente:

HTTP OPERACIÓN ACCIÓN
POST CREATE Crear un nuevo recurso
GET RETRIEVE Obtener la representación de un recurso
PUT UPDATE Actualizar un recurso
DELETE DELETE Eliminar un recurso

Sabiendo esto, vamos a definir las operaciones de nuestro servicio (que por el momento trabajara con el recurso “Cliente”):

RECURSO MÉTODO
Cliente GET Obtener la representación de un cliente
Todos los clientes GET Obtener la representación de una la lista de clientes
Cliente POST Crear un cliente
Cliente PUT Actualizar un cliente
Cliente DELETE Eliminar un cliente

Volvamos al proyecto para definir el modelo que representará al recursoCliente”. Para eso vamos a agregar la clase Cliente dentro de la carpeta “Models” > click derecho sobre Models > Add > Class > Cliente.cs:

Definición del modelo Cliente

Definición del modelo Cliente

Ahora es el momento de trabajar sobre el controlador. Para eso vamos a crear un nuevo controller  llamado ClientesController haciendo click derecho sobre el directorio Controllers > Add > Controller… y una vez que se nos despligue la ventana “Add Controller” seleccionaremos dentro de los templates disponible la opción “Empty API Controller”:

Creando nuestro API Controller

Creando nuestro API Controller

Escribamos las acciones (operaciones) usando como en base lo que definimos en la tabla anterior:

Definición de ClientesController

Definición de ClientesController

Si ejecutamos el proyecto e intentamos recuperar un cliente utilizando nuestro servicio REST, nos encontraremos con que no se encuentra el recurso solicitado :(:

Error al acceder a nuestro servicio

Error al acceder a nuestro servicio

Por qué ocurrió esto? Si inspeccionamos las entradas en el mecanismo de routing de ASP.NET MVC (dentro de Global.asax), nos vamos a encontrar con una “nueva” entrada llamada DefaultApi que será utilizada por nuestra Web API REST. Como observación, van a notar que la misma es registrada por el método MapHttpRoute, a diferencia de los mapeos tradicionales de ASP.NET MVC que son realizados con el método MapRoute.

DefaultApi

DefaultApi

Conclusión, cuando llamemos a las URL de nuestros servicios REST, vamos hacerlo anteponiendo “api” en la URL. Por ejemplo, para recuperar la lista de clientes debemos acceder de la siguiente manera:

http://localhost:49171/Api/Clientes

Pasemos de la teoría a la práctica 🙂

Nuestro servicio REST en marcha!

Nuestro servicio REST en marcha!

En este caso la negociación entre cliente-servidor definió que el contenido devuelto sea en formato XML, sin embargo esto no debe ser necesariamente así (veremos en otros post como definir el formato que más cómodo-útil nos resulte).

Habrán notado también es que no fue necesario especificar el nombré de la acción en la URL (es más, si prestan atención a la regla DefaultApi del enrutador, la acción no es tenida en cuenta). Para saber qué método se debe invocar ante cada petición, lo que hace el framework es trabajar por convención, esto quiere decir que ante cada request, se accederá al método de acción llamado de la misma forma que el verbo HTTP que lo invoca,  teniendo en cuenta también los parámetros enviados.

Veamos como quedaría la tabla teniendo en cuanta las operaciones a realizar sobre nuestro recurso:

RECURSO MÉTODO
Cliente GET http://localhost:49171/Api/Clientes/5
Todos los clientes GET http://localhost:49171/Api/Clientes/5/sebis
Cliente POST http://localhost:49171/Api/Clientes/5
Cliente PUT http://localhost:49171/Api/Clientes
Cliente DELETE http://localhost:49171/Api/Clientes/5/sebis

Otra cosa interesante, es que a diferencia de las aplicaciones web ASP.NET MVC, podemos definir más de un método con el mismo nombre. Por ejemplo podemos tener los métodos Get(), Get(int id) y Get(int id, string name). Para este último caso, simplemente debemos agregar un nuevo mapeo HTTP en el mecanismo de routing:

Definiendo nuestra entrada personalizada

Definiendo nuestra entrada personalizada

El procesador se encargará de acceder al método correspondiente a partir del tipo de petición realizada (GET, POST, PUT…) y de los parámetros enviados.

A esta altura muchos se preguntarán por qué usar servicios basados en REST con Web API si ya disponemos en .NET de otras tecnologías o frameworks para trabajar con web services (ASMX, WSE, WCF,… , WCF Web Api)?  Una respuesta es que ASP.NET Web Api integra de una manera muy sencilla lo mejor de WCF Web API y ASP.NET MVC – excelente noticia quienes desarrollamos con ASP.NET MVC :). Otra buena respuesta a esta pregunta es que REST esta construido sobre los pilares de la web, y esta por demás decir la misma ha sido muy exitosa. Recuerdo un artículo donde decía que “la Web ha sido la única aplicación distribuida que ha conseguido ser escalable al tamaño de Internet” y debido a que REST se basa en ella, podemos decir con seguridad que estamos tomando el camino correcto.

Espero que les haya sido de utilidad, y en próximos post vamos a ver la forma de utilizar los servicios por medio de jQuery y otras características de Web API.

Puedes encontrar este articulo en MSExpertos.