Polaroid

Servicios Web de RESTful

REST define un conjunto de principios arquitectónicos por los que se pueden diseñar servicios Web que se centran en los recursos de un sistema, lo que incluye la forma en que los estados de los recursos se dirigen y trasfieren a través de HTTP por un amplio rango de clientes que están escritos en diferentes lenguajes. Si lo medimos por el número de servicios Web que lo utilizan, en los últimos años REST ha emergido como un modelo de diseño predominante para los servicios Web. En verdad, REST ha tenido tanto impacto en la Web que ha apartado enormemente al diseño de interfaces basado en SOAP y WSDL, porque es un estilo sensiblemente más fácil de usar.


REST no obtuvo mucha atención la primera vez que fue presentado en el por Roy Fielding en la Universidad de California, Irvine, en su disertación académica, "Architectural Styles and the Design of Network-based Software Architectures", que analiza un conjunto de principios arquitectónicos de software que emplean la Web como una plataforma para la computación distribuida. Ahora, años después de su presentación, han empezado aparecer las primordiales infraestructuras para REST, y se están desarrollando otras por el hecho de que, por servirnos de un ejemplo, se ha anunciado que se marcha a convertir en una parte integral de Java™ 6 en JSR-311.


Este artículo sugiere que, en su forma actual más pura, cuando atrae toda esta atención, las implementaciones específicas prosiguen cuatro principios básicos de diseño de servicios Web de REST:



  • Utilice métodos HTTP de forma explícita.

  • Sea sin estados.

  • Exponga los URIS como estructuras de directorios.

  • Transfiera XML, JavaScript Object Notation (JSON), o bien los dos.


Las próximas secciones amplían esos cuatro principios y plantean una razón técnica de por qué deberían ser importantes para los diseñadores de servicios Web de REST.


Utilice métodos HTTP de forma explícita


Una de las principales características de un servicio Web de RESTful es el empleo explícito de métodos HTTP de una manera que prosiga el protocolo tal y como está definido por RFC dos mil seiscientos dieciseis. HTTP GET, por servirnos de un ejemplo, se define como un método para producir datos, que está destinado a ser usado por una aplicación del cliente del servicio para recuperar un recurso, para traer datos desde un servidor Web o para ejecutar una consulta con la expectativa de que el servidor Web la busque y responda con un conjunto de recursos que coincidan.


REST solicita a los desarrolladores que usen HTTP de forma explícita y de una manera marketing digital en toledo con la definición del protocolo. Este principio básico del diseño de REST establece una correlación individual entre las operaciones de crear, leer, actualizar y borrar (CRUD) y los métodos HTTP. Según esta correlación:



  • Para crear un recurso en el servidor hay que emplear un POST.

  • Para recobrar un recurso hay que emplear un GET.

  • Para mudar el estado de un recurso, o bien para actualizarlo, hay que emplear un PUT.

  • Para quitar o bien borrar un recurso hay que emplear un DELETE.


Una poco afortunada falla de diseño inherente de muchas APIs Web es la utilización de métodos HTTP para fines no deseados. Por poner un ejemplo, el URI de la petición en una petición HTTP GET, en general identifica un recurso específico. O bien la cadena de caracteres de una consulta de un URI de la solicitud incluye un conjunto de parámetros que define los criterios de búsqueda que el servidor usa para encontrar un conjunto de recursos que coinciden. Por lo menos, así es cómo HTTP/1.1 RFC describe el GET. Pero, hay muchos casos de APIs Web no atractivas que utilizan HTTP GET para desencadenar algo transaccional en el servidor—por ejemplo, para añadir registros a una base de datos. En esos casos, GET para pedir el URI no se emplea adecuadamente, cuando menos, no se emplea de la manera RESTful. Si la API Web usa GET para invocar procedimientos remotos, se parecerá a esto:


GET /adduser?name=Robert HTTP/1.1


No es un diseño muy atractivo, por el hecho de que el método Web precedente aguanta una operación de cambio de estado sobre HTTP GET. Por ponerlo de otra forma, la solicitud HTTP GET precedente tiene efectos colaterales. Si se procesa adecuadamente, el resultado de la solicitud será añadir un usuario nuevo—en este ejemplo, Robert—para el almacén de datos subyacente. El problema aquí es eminentemente semántico. Los servidores Web están diseñados para responder a las peticiones HTTP GET recuperando los recursos que coinciden con la senda (o bien los criterios de la consulta) del URI de la solicitud, y devuelven los mismos, o bien una representación de ellos, en una respuesta; no para añadir un registro a una base de datos. Utilizar GET de esta forma es inconsistente desde el punto de vista del uso previsto del método del protocolo, y desde la perspectiva de los servidores Web conformes con HTTP/1.1.


Más allá de la semántica, el otro inconveniente con GET es que, para provocar el borrado, modificación o bien incorporación de un registro en una base de datos, o para cambiar el estado por el lado del servidor de alguna forma, invita a herramientas para capturar las memorias caché de la Web (crawlers) y a motores de búsqueda para hacer cambios por el lado del servidor sin ninguna intención, solo rastreando un enlace. Una forma fácil de superar este problema frecuente es mover a etiquetas XML los nombres y los valores de los parámetros del URI de la petición. Las etiquetas resultantes, una representación XML de la entidad a crear, se pueden mandar en el cuerpo de una HTTP POST cuyo URI de la solicitud es el objeto primario de la entidad (vea los Listados 1 y dos).


El método precedente es un caso de una solicitud RESTful: empleo adecuado de HTTP POST e inclusión de la carga útil en el cuerpo de la solicitud. En la parte receptora, la petición se puede procesar añadiendo el recurso que está contenido en el cuerpo como un subordinado del recurso que está identificado en el URI de la solicitud; en este caso, el recurso nuevo se debería añadir como objeto secundario de /users. Esta relación de contención entre la entidad nueva y su objeto primario, como se detalla en la petición POST, es análoga a la forma en la que un fichero es subordinado a su directorio primario. El usuario establece la relación entre la entidad y su objeto primario, y define el URI de la nueva entidad en la petición POST.


Posteriormente, una aplicación del usuario podrá obtener una representación del recurso usando el nuevo URI, observando que el recurso está situado, cuando menos lógicamente, bajo /users, como se muestra en el Listado tres.


La utilización de GET de esta forma es explícita, porque GET sólo se emplea para la recuperación de datos. GET es una operación que no debería tener efectos colaterales, una propiedad también famosa como idempotence.


En los casos en los que una operación de actualización sea soportada a través de HTTP GET, también se deberá aplicar una refactorización afín de un método web, tal como se muestra en el Listado cuatro.


Esto cambia el atributo (o bien propiedad) name del recurso. Si bien, para dicha operación se puede usar una cadena de consulta, y el Listado cuatro es una operación operación simple, este patrón cadena-de-consulta-como-método-de-firma tiende a estropearse cuando se usa para operaciones más complejas. Ya que su meta es emplear los métodos HTTP de forma explícita, un enfoque más RESTful es mandar una petición HTTP PUT para actualizar el recurso, en lugar de HTTP GET, por exactamente las mismas razones anteriores (vea el Listado cinco).


Utilizar PUT para sustituir el recurso original proporciona una interfaz más limpia, que es coherente con los principios de REST y con la definición de los métodos HTTP. La petición PUT del Listado 5 es explícita en el sentido de que apunta al recurso que debe ser actualizado identificándolo en la petición de URI, y en el sentido de que transfiere una nueva representación del recurso desde el usuario cara el servidor en el cuerpo de una solicitud PUT, en vez de transferir los atributos del recurso como un conjunto suelto de nombres y valores de parámetros sobre el URI de la solicitud. El Listado cinco también renombra el recurso de Robert a Bob, y, al hacerlo, cambia su URI a /users/Bob. En un servicio Web de REST, las solicitudes posteriores para el recurso que utiliza el URI antiguo generarían un error estándar 404 No Encontrado.


Como principio general del diseño, ayuda a seguir las directrices de REST para utilizar métodos HTTP de forma explícita usando nombres en los URIs, en vez de verbos. En un servicio Web de RESTful, los verbos—POST, GET, PUT y DELETE—ya están definidos por el protocolo. También, idealmente, el servicio Web no debería acotar más verbos o bien procedimientos recónditos, como /adduser o /updateuser, para mantener la interfaz extendida y para dejar que los clientes sean explícitos acerca de las operaciones que invocan. Este principio general del diseño también se aplica al cuerpo de una petición HTTP, que está destinado a ser usado para transferir el estado del recurso, no para llevar el nombre de un método recóndito o bien de un procedimiento remoto a invocar.


Sea sin estado


Los servicios Web de REST tienen que escalar para satisfacer las cada vez mayores demandas de alto desempeño. Los clústeres de los servidores que tienen capacidades de balanceo de carga y de recuperación por fallo, los proxys y las puertas de link, generalmente, se disponen de una forma que forma la topología de un servicio, lo que permite reenviar las solicitudes de un servidor a otro según se necesite, para reducir el tiempo de respuesta general de una llamada a un servicio web. Para utilizar servidores intercesores para prosperar la escala, los clientes del servicio de servicios Web de REST deben enviar solicitudes completas y también independientes; es decir, enviar solicitudes que incluyan todos y cada uno de los datos que se tienen que completar, a fin de que los componentes de los servidores intermediarios puedan reenviar, redirigir y balancear la carga para no tener que mantener localmente ningún estado entre las solicitudes.


Una solicitud completa y también independiente no requiere que el servidor recupere ningún tipo de contexto o estado de la aplicación, mientras procesa la solicitud. Las aplicaciones (o bien clientes) de los servicios web de REST incluyen, dentro de las cabeceras y cuerpos HTTP de una solicitud, todos y cada uno de los parámetros, contexto y datos que el componente por el lado del servidor necesita para producir una respuesta. El no tener estado en este sentido mejora el rendimiento del servicio Web y facilita el diseño y la implementación de los componentes por el lado del servidor, dado a que la ausencia de estado en el servidor elimina la necesidad de sincronizar los datos de la sesión con una aplicación externa.


La imagen 1 ilustra un servicio sin estado desde el que una aplicación puede solicitar la siguiente página de un conjunto de resultados de múltiples páginas, asumiendo que el servicio realice el seguimiento de dónde lo deja la aplicación mientras navega por el conjunto. En este diseño sin estado, el servicio incrementa y guarda, en algún lugar, una variable previousPage para ser capaz de responder a las solicitudes de la siguiente.



Los servicios con estado como este se vuelven complicados. En una Plataforma de Java, los servicios con estado de los entornos Enterprise Edition (Java EE) precisan de muchas consideraciones previas para guardar eficazmente y para permitir la sincronización de los datos de la sesión a lo largo de un clúster de contenedores de Java. En este género de ambientes, desarrollo portfolio web madrid los desarrolladores de servlet/JavaServer Pages (JSP) y Enterprise JavaBeans (EJB) están familiarizados, de forma frecuente tienen problemas para hallar la raíz de la causa de una excepciónjava.io.NotSerializableException durante la replicación de la sesión. Este inconveniente, tanto si es lanzado por el contenedor del servlet a lo largo de una replicación HttpSession como si es lanzado por el contenedor de EJB a lo largo de una replicación de EJB sin estado, es un inconveniente que puede valer a los desarrolladores días de trabajo intentando identificar un objeto que no incorpora Serializable en un, en ocasiones, complejo gráfico de objetos que constituyen el estado del servidor. Además, la sincronización de la sesión añade una sobrecarga, que afecta al rendimiento del servidor.


Los componentes sin estado por el lado del servidor, por otra parte, son más fáciles de diseñar, redactar y repartir a lo largo de los servidores que tienen la carga equilibrada. Un servicio sin estado no sólo tiene mejor rendimiento, traspasa la mayor parte de la responsabilidad de mantener el estado a la aplicación del cliente. En un servicio web de RESTful, el servidor es responsable de producir respuestas y de proporcionar una interfaz que deje que el cliente sostenga por sí sólo el estado de la aplicación. Por poner un ejemplo, en la solicitud de un conjunto de resultados de múltiples páginas, el cliente debería incluir el número actual de la página a recobrar en vez de simplemente pedir la siguiente (vea la Imagen dos).



Un servicio web sin estado produce una respuesta que enlaza al número de la próxima página del conjunto y deja que el usuario haga lo que deba hacer para conservar ese valor. Este aspecto del diseño de servicios web de RESTful Web se puede desglosar en dos puntos de responsabilidades, como una separación de alto nivel que aclara cómo se puede sostener un servicio sin estado:


Servidor



  • Genera respuestas que incluyen enlaces a otros recursos, para dejar que otras aplicaciones naveguen entre los recursos relacionados. Esta clase de contestación incorpora links. De forma similar, si la petición se efectúa para un objeto secundario o un recurso contenedor, la contestación típica de RESTful también podría incluir links a los objetos secundarios del primario o bien a recursos subordinados, para que éstos continúen conectados.

  • Genera respuestas que indican si se pueden guardar en la memoria caché, para prosperar el rendimiento al reducir el número de peticiones de recursos duplicados y al eliminar completamente ciertas peticiones. El servidor lo hace incluyendo una cabecera de respuesta HTTP Cache-Control y Last-Modified (una data).


Aplicación del cliente



  • Utiliza la cabecera de la respuesta Cache-Control para determinar si guarda el recurso en la memoria caché (hacer una copia local del mismo). El cliente del servicio también lee la cabecera de la respuesta Last-Modified y envía de vuelta el valor de la fecha en una cabecera If-Modified-Since para consultar al servidor si el recurso ha cambiado. Esto se llama GET Condicional, y las dos cabeceras van mano a mano en que la respuesta del servidor es un código trescientos cuatro estándar (No Cambiado), y omite el recurso actual solicitado si no ha cambiado desde ese momento. Un código de respuesta HTTP trescientos cuatro quiere decir que el usuario puede emplear con seguridad una copia local, guardada en la caché, de la representación del recurso como la más actualizada; de hecho, elude las posteriores solicitudes GET hasta que el recurso cambie.

  • Envía solicitudes completas que se pueden atender de forma independiente respecto a las otras solicitudes. Esto requiere que el cliente utilice absolutamente las cabeceras HTTP tal y como lo especifica la interfaz del servicio Web, y que envíe representaciones completas de los recursos en el cuerpo de la petición. El cliente del servicio envía peticiones que hacen poquísimas suposiciones acerca de las anteriores peticiones, la existencia de una sesión en el servidor, la capacidad del servidor de añadir contexto a una petición, o sobre el estado de una aplicación que se mantiene entre las solicitudes.


Esta colaboración entre la aplicación y el servicio del usuario es esencial a fin de que un servicio web de RESTful sea sin estado. Mejora el desempeño al ahorrar ancho de banda y al disminuir al mínimo el estado de la aplicación por el lado del servidor.


Exponga los URIs como estructuras de directorio.


Desde el punto de vista de las aplicaciones que se encargan de recursos, los URIs determinan lo intuitivo que será un servicio web de REST y si el servicio se va a utilizar de formas que los diseñadores puedan adelantar. La tercera característica web de RESTful va sobre los URIs.


Los URIs de los servicios web de REST deberían ser intuitivos hasta el punto en que sean fáciles de adivinar. Piense en un URI que tenga un tipo de interfaz autodocumentada que requiera poca, o ninguna, explicación o referencia a fin de que un desarrollador comprenda a que apunta y para derivar los recursos relacionados. Con este fin, la estructura de un URI debería ser bastante clara, predecible y fácil de comprender.


Una forma de conseguir este nivel de usabilidad es delimitar URIs de tipo estructura de directorio. Esta clase de URI es jerárquico, enraizado como una única ruta y sus ramificaciones son subrutas que exponen las principales áreas del servicio. Según esta definición, un URI no es meramente una cadena de caracteres delimitada por barras oblicuas, sino un árbol con ramas subordinadas y superiores que se conectan en los nodos. Por poner un ejemplo, en un servicio de hebras de discusiones que reúne temas que varían desde Java hasta el papel, usted puede acotar un conjunto estructurado de URIs de esta manera:


/discussion/topics/topic


La raíz, /discussion, tiene un nodo /topics bajo ella. Por debajo de eso hay una serie de nombres de temas, como cotilleos, tecnología, etc., y cada uno de ellos apunta a una hebra de una discusión. Dentro de esta estructura es fácil extraer hebras de discusiones simplemente escribiendo algo después de /topics/.


En ciertos casos, la senda hacia un recurso se presta en especial bien para una estructura tipo directorio. Por servirnos de un ejemplo, tome los recursos organizados por la data, lo que es buena combinación para usar la sintaxis jerárquica.


Este ejemplo es intuitivo por el hecho de que se fundamenta en reglas:


/discussion/2008/12/10/topic


El primer fragmento de la ruta es un año de cuatro dígitos, el segundo fragmento de la ruta es un día de 2 dígitos y el tercer fragmento es un mes de 2 dígitos. Puede parecer un poco absurdo tener que explicarlo de esta manera, pero es el nivel de simplicidad que estamos buscando. Los humanos y las máquinas pueden generar fácilmente URIs estructurados como estos, porque se basan en reglas. Rellenar las unas partes de la ruta en las ranuras de la sintaxis hace que sean buenos porque hay un patrón terminante desde el que componerlos:


/discussion/year/day/month/topic


Algunas indicaciones adicionales interesantes mientras que se piensa acerca de la estructura del URI para un servicio web de RESTful son:



  • Esconder las extensiones del archivo de la tecnología de los scripts por el lado del servidor (.jsp, .php, .asp), si las tuviese, para poder transportarlo a otro sitio sin mudar los URIs.

  • Mantenga todo en letra minúscula.

  • Sustituya los espacios con guiones o bien con subrayados (escoger un tipo).

  • Evite consultar las cadenas de caracteres tanto como pueda.

  • Si el URI pedido es para una ruta parcial, dé siempre como contestación una página o bien recurso predeterminado, en lugar de utilizar el código 404 No Encontrado.


Los URIs también deberían ser estáticos, para que cuando el recurso o bien la implementación del servicio cambien, el enlace prosiga siendo exactamente el mismo. Esto deja utilizar marcadores. También es importante que la relación entre los recursos que está codificada en los URIs siga siendo independiente de la forma en la que se representan las relaciones dónde estás están almacenadas.


Transfiera XML, JSON, o ambos


Una representación de recursos en general refleja el estado actual de un recurso y de sus atributos en el instante en el que una aplicación cliente del servicio la solicita. En este sentido, las presentaciones de recursos son meras instantáneas en el tiempo. Esto podría ser una cosa tan sencilla como la representación de un registro en una base de datos que está formada por una correlación entre nombres de columnas y etiquetas XML, dónde los valores de los elementos del XML poseen los valores de las filas. O bien, si el sistema tiene un modelo de datos, entonces, según esta definición, una representación de un recurso es una instantánea de los atributos de una de las cosas del modelo de datos de su sistema. Estas son las cosas que usted quiere que su servicio web de REST presente.


El último conjunto de limitaciones que va en el diseño de un servicio web de RESTful tiene que ver con el formato de los datos que la aplicación y el servicio intercambian en la carga útil de la solicitud/respuesta o en el cuerpo HTTP. Aquí es donde realmente compensa mantener las cosas sencillas, inteligibles por los humanos y conectadas.


Los objetos de su modelo de datos generalmente están relacionados de alguna manera, y las relaciones entre los objetos del modelo de datos (recursos) deberían estar reflejadas de forma que estén representadas para trasferirlas a una aplicación usuario. En el servicio de hebras de discusiones, un caso de representaciones de recursos conectados podría incluir un tema de la discusión raíz, sus atributos y los links incorporados a las contestaciones que se han proporcionado para ese tema.


Y, finalmente, para otorgar a las aplicaciones del usuario la capacidad de pedir un género de contenido específico que le venga mejor, edifique su servicio de manera que utilice la cabecera HTTP Accept incorporada, donde el valor de la cabecera es un tipo MIME. En la Tabla 1 se muestran ciertos tipos MIME habituales que emplean los servicios de RESTful.


Esto deja que el servicio sea utilizado por diferentes clientes que están escritos en diferentes lenguajes y que se ejecutan en diferentes plataformas y dispositivos. La utilización de los tipos MIME y de la cabecera HTTP Accept es un mecanismo que se conoce como negociación de contenido, que deja de los clientes elijan cuál es el formato de datos que es conveniente para ellos y minimiza el acoplamiento de datos entre el servicio y las aplicaciones que lo utilizan.


Conclusión


REST no siempre es la elección conveniente. Fue impuesto como una forma de diseñar servicios Web con menos dependencia del middleware patentado (por servirnos de un ejemplo, un servidor de aplicaciones) que la que tienen los del tipo SOAP y los basados en WSDL. Y, de alguna manera, REST es regresar a la Web de la manera en la que era ya antes de la era de los grandes servidores de aplicaciones, a través de su énfasis en los primeros estándares, URI y HTTP de Internet. Como hemos vistos en los autodenominados principios del diseño de la interfaz de RESTful, XML sobre HTTP es una potente interfaz que deja que aplicaciones internas, como el JavaScript Asincrónico + interfaces de usuario adaptadas basadas en XML (Ajax), se conecten, manejen y consuman recursos fácilmente. En verdad, el perfecto ajuste entre Ajax y REST ha incrementado la cantidad de atención que REST está obteniendo estos días.


Exponer los recursos de un sistema a lo largo de una API de RESTful es una forma flexible de proporcionar diferentes géneros de aplicaciones en las que los datos tengan un formato estándar. Ayuda a satisfacer los requisitos de la integración que son críticos para construir sistemas en los que los datos se puedan conjuntar fácilmente (mashups), y para extender o construir un conjunto de servicios de RESTful básicos y crear algo mucho mayor. Este artículo tan sólo toca los aspectos básicos, pero, espero que le haya incitado a seguir explotando el tema.

Back to posts
This post has no comments - be the first one!

UNDER MAINTENANCE