sábado, 10 de mayo de 2014

Implementar Servicio REST Parte I

En esta oportunidad vamos a aprender a implementar un servicio REST sencillo para entender como funciona esta tecnología y posteriormente en una siguiente entrega convertiremos este mismo ejemplo aplicando Entity Framework la consistencia de los datos.
Pues bien lo primero que debemos entender que significa REST y para ello nos basaremos en la explicación que nos brinda Wikipedia:

La Transferencia de Estado Representacional (Representational State Transfer) o REST es una técnica de arquitectura software para sistemas hipermedia distribuidos como la World Wide Web. El término se originó en el año 2000, en una tesis doctoral sobre la web escrita por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP y ha pasado a ser ampliamente utilizado por la comunidad de desarrollo.
Si bien el término REST se refería originalmente a un conjunto de principios de arquitectura —descritos más abajo—, en la actualidad se usa en el sentido más amplio para describir cualquier interfaz web simple que utiliza XML y HTTP, sin las abstracciones adicionales de los protocolos basados en patrones de intercambio de mensajes como el protocolo de servicios web SOAP. Es posible diseñar sistemas de servicios web de acuerdo con el estilo arquitectural REST de Fielding y también es posible diseñar interfaces XMLHTTP de acuerdo con el estilo de llamada a procedimiento remoto (RPC), pero sin usar SOAP. Estos dos usos diferentes del término REST causan cierta confusión en las discusiones técnicas, aunque RPC no es un ejemplo de REST.
Los sistemas que siguen los principios REST se llaman con frecuencia RESTful.

REST afirma que la web ha disfrutado de escalabilidad como resultado de una serie de diseños fundamentales clave:
  • Un protocolo cliente/servidor sin estado: cada mensaje HTTP contiene toda la información necesaria para comprender la petición. Como resultado, ni el cliente ni el servidor necesitan recordar ningún estado de las comunicaciones entre mensajes. Sin embargo, en la práctica, muchas aplicaciones basadas en HTTP utilizan cookies y otros mecanismos para mantener el estado de la sesión (algunas de estas prácticas, como la reescritura de URLs, no son permitidas por REST)
  • Un conjunto de operaciones bien definidas que se aplican a todos los recursos de información: HTTP en sí define un conjunto pequeño de operaciones, las más importantes sonPOSTGETPUT y DELETE. Con frecuencia estas operaciones se equiparan a las operaciones CRUD en bases de datos (ABMC en castellano: Alta, Baja, Modificación y Consulta) que se requieren para la persistencia de datos, aunque POST no encaja exactamente en este esquema.
  • Una sintaxis universal para identificar los recursos. En un sistema REST, cada recurso es direccionable únicamente a través de su URI.
  • El uso de hipermedios, tanto para la información de la aplicación como para las transiciones de estado de la aplicación: la representación de este estado en un sistema REST sontípicamente HTML o XML. Como resultado de esto, es posible navegar de un recurso REST a muchos otros, simplemente siguiendo enlaces sin requerir el uso de registros u otra infraestructura adicional.

Pues entonces en base a la explicación que hemos tomado de Wikipedia procederemos entonces a entender como aplicarlo. El ejemplo se desarrollará en VS2012 con la versión  3 de Razor:

Lo primero que haremos será crear un proyecto dando clic en el menú File -> New -> Project y crearemos una aplicación Web MVC 4 con el nombre AppWebApiRest, como se muestra en la siguiente imagen:



Posteriormente debemos seleccionar el tipo de proyecto que deseamos realizar y debemos seleccionar una proyecto Web API como lo muestra la siguiente imagen y damos clic en "Ok":



Entonces el proyecto se generará con la siguiente estructura:


Como podemos observar en el árbol de directorios del proyecto parece un proyecto cualquiera de MVC pues se mantiene la misma estructura de directorios, ya que recuerden que la tecnología que usamos aplica como estándar el patrón. A continuación haré una breve explicación de los directorios más importantes:

  • App_Start: Este directorio contiene la configuración inicial de nuestra aplicación, más adelante explicaremos el contenido de los archivos que utilizaremos de esta carpeta.
  • Content: En este directorio se alojan los temas, css y cualquier contenido estático que deseemos utilizar en nuestro proyecto. Recuerden que esto no es una camisa de fuerza podemos crear nuestros archivos en otros directorios, pero nosotros nos basaremos en el standar, esto para que todo sea más sencillo en nuestro proceso de aprendizaje.
  • Controllers: En este directorio se ubicarán los controladores que deseemos crear en nuestra aplicación MVC. Siempre siguiendo el standar acá es donde lo crearemos. Recuerden que por defecto se nos crearon dos controladores, mostraremos el contenido pero solamente utilizaremos el HomeController de los que se nos han creado por defecto.
  • Scripts: En este directorio se incluyen todos los scripts que por defecto el IDE considera que son necesarios para incluir en nuestra aplicación(por el tipo seleccionado). Pues entonces acá también podemos agregar los scripts que generemos en nuestro caso generaremos el archivo que realizará las peticiones al servicio que generaremos más adelante.
  • Views: En este directorio almacenamos las vistas que deseemos crear. En nuestro ejemplo solamente generaremos una, ya que este post será para explicar la lógica básica de la implementación de este tipo de servicios:
  • Shared: Este subdirectorio pertenece al directorio Views y en el podremos depositar cualquier vista parcial o Layout que sería el equivalente a los "Masterpages" de la tecnología de WebForms.

Ya que tenemos nuestro proyecto iniciaremos a crear la entidad que manejaremos en nuestro ejemplo, para ello debemos hacer clic derecho sobre el directorio "Models" y en el submenú seleccionaremos Add -> New item -> Class. El nombre de la clase deberá ser "Cliente" y su contenido será el siguiente:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApiRest.Models
{
    public class Cliente
    {
        public int Id { get; set; }
        public string Nombre { get; set; }
        public string Apellido { get; set; }
    }
}


Como podemos ver esta entidad solamente posee tres propiedades, esto debido a que realizaremos un ejemplo básico donde almacenaremos solamente un ID que se autogenerará y los Nombres y Apellidos del cliente. Ya que esta aplicación pretende hacer una pequeña agenda para almacenar clientes, buscarlos, editarlos y eliminarlos en síntesis un CRUD. Sin embargo me gustaría enfatizar que por el momento esto se hará en memoria, es decir que aún no habrá consistencia de datos porque por  el momento ese no es el objetivo de esta entrega.

Pues bien, ahora debemos crear el controlador que nos permitirá interactuar entre la vista y el modelo. Para ello debemos dar clic derecho sobre el directorio "Controllers" y seleccionar la opción Add -> New item ->Web API Controller Class.

Siguiendo el estándar de MVC tendrá el nombre ClientesController, cuando se agregue el código veremos que esta clase deriva de la clase ApiController y no de la clase Controller como un controlador de las aplicaciones comunes de MVC.

Su contenido sería el siguiente:


En el podemos observar la definición de métodos, pero estos métodos son diferentes a lo que podemos observar en un controlador típico de una aplicación MVC. Justamente es por eso que deriva de una clase distinta porque su comportamiento es distinto al de un controlador de una aplicación común. Y en base a lo que pudimos extraer de wikipedia y otros medios podemos concluir lo siguiente para explicar el porque de los cambios de un controlador estándar:

  • Al derivarse de esta nueva clase se les permite los métodos de acción que se encuentren dentro de la clase no retornar necesariamente vistas, es decir que su tipo de retorno sea un ActionResult o ViewResult, sino devolver los datos puros, sin ningún tipo de formato mediante JSON, XML, WFC o cualquier otra tecnología mediante la cual se negocie (entre cliente y servidor) con el servicio REST cuando la implementación solicite la información.
  • Así mismo esta tecnología por convención respeta que los nombres de los métodos de acción sean los mismos que los verbos HTTP (GET,PUT,DELETE Y POST), evitando el uso de etiquetas para indicar que método debe ejecutar la acción. Sin embargo se pueden nombrar de una manera diferente y se le debe anteponer una etiqueta indicando el verbo al que responderá o bien indicar en la declaración de las rutas que responderá a una ruta como en una aplicación MVC estándar {controlador}/{acción}, aunque este no es el funcionamiento regular de este tipo de aplicaciones, pero puede ser una forma personalizada de hacerlo si es que así nos sentimos más cómodos. Posteriormente explicaremos la definición de las rutas, si no te encuentras familiarizado por el momento no te preocupes. Ejemplo de lo que implica cada uno de los verbos:



Ahora entonces debemos eliminar el contenido de la clase "ClientesController" y lo reemplazaremos por lo siguiente:

namespace WebApiRest.Controllers
{
    public class ClientesController : ApiController
    {
        private List<Cliente> clientes = new List<Cliente>
        {
            new Cliente() {Id = 1,Nombre = "Luis",Apellido = "Chavez"},
            new Cliente() {Id = 2,Nombre = "Juan",Apellido = "Perez"},
            new Cliente() {Id = 3,Nombre = "Antonio",Apellido = "Fuentes"}
        };
      //GET /api/clientes
        public IEnumerable<Cliente> Get()
        {
            return clientes;
        }

        //GET /api/clientes/1
        public Cliente Get(int id)
        {
            var cliente = clientes.SingleOrDefault(c => c.Id == id);
            if (cliente != null)
            {
                return cliente;
            }
            return null;
        }

        //POST /api/clientes/5/Luis
        [ResponseType(typeof(Cliente))]
        public IHttpActionResult Post(Cliente nuevoCliente)
        {
            nuevoCliente.Id = clientes.Select(c => c.Id).Max() + 1;
            clientes.Add(nuevoCliente);
            //return Ok(clientes);
            return CreatedAtRoute("DefaultApi", new { id = nuevoCliente.Id }, nuevoCliente);
        }

        //PUT /api/clientes/5/Luis
        public HttpResponseMessage Put(Cliente clienteUpdate)
        {
            var cliente = clientes.SingleOrDefault(c => c.Id == clienteUpdate.Id);
            if (cliente != null)
            {
                cliente.Nombre = clienteUpdate.Nombre;
                cliente.Apellido = clienteUpdate.Apellido;
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
                throw new HttpResponseException(HttpStatusCode.NotFound);            
        }

        //DELETE /api/clientes/5
        [ResponseType(typeof(Cliente))]
        public HttpResponseMessage Delete(int id)
        {
            var cliente = clientes.SingleOrDefault(c => c.Id == id);
            if (cliente != null)
            {
                clientes.Remove(cliente);
                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            throw  new HttpResponseException(HttpStatusCode.NotFound);
        }
    }
}


Si no entiendes del todo el código no te preocupes que posteriormente lo explicaremos más en detalle cuando hagamos la implementación del servicio.

Si corremos en este momento el proyecto por defecto nos ejecutará la ruta por defecto al igual que cualquier otra aplicación MVC, es decir /home/index, tal como lo muestra la siguiente pantalla:


Si vemos esto y nuestro compilar no nos arroja ningún error es que hasta el momento hemos desarrollado todo lo que va de nuestro ejemplo corrrectamente. Y comprobamos el estado de uno de los métodos si digitamos "localhost:7439/api/clientes" (recuerda que el puerto seguramente será diferente en tu equipo) y  obtenemos el siguiente resultado:


Como se puede observar el resultado es un XML, esto es así porque el navegador negoció así con el servidor el resultado. Si hemos obtenido esta salida en el navegador entonces hemos realizado correctamente nuestro ejemplo. Por el momento dejaremos nuestro ejemplo hasta aquí en una entrega posterior explicaremos los métodos y su funcionamiento y su implementación.

Espero que esta introducción nos permite entender el funcionamiento básico de un servicio REST, aunque quedamos pendientes de continuar nuestro ejemplo.


Referencias:

No hay comentarios:

Publicar un comentario