¿Qué es un web service Rest?

Transferencia de Estado Representacional

La Transferencia de Estado Representacional (en inglés Representational State Transfer) o REST es un estilo 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.


Protocolo cliente/servidor sin estado con operaciones bien definidas

El protocolo de comunicación utilizado en los servicios REST es el protocolo HTTP. Este protocolo es la base de las comunicaciones en internet y se basa en una serie de peticiones enviadas por el cliente que son recibidas y procesadas en el servidor. El resultado de estas peticiones es devuelto en forma de respuesta al cliente. Este protocolo no mantiene el estado de las peticiones, es decir, no existe una sesión en la que se almacene el resultado de una petición de manera que peticiones siguientes tengan un comportamiento determinado por la petición anterior. Cada petición es totalmente independiente, incluso en aspectos como la autenticación. Esto significa que cada petición debe llevar todo el contenido necesario (incluyendo toda la información relacionada con la autenticación) para ser realizadas, y que es el usuario el encargado de mantener el estado en su propia aplicación si es que lo desea. El funcionar bajo un protocolo sin estado permite a los servidores ahorrar recursos al no ser necesario almacenar información de la sesión de usuario y facilita las labores de desarrollo. Utilizar el protocolo HTTP como protocolo de comunicaciones es el principio básico que todas las APIs que se consideran REST siguen y cumplen, hasta el punto de que muchas interfaces de comunicación que simplemente usan HTTP se consideran a si mismas como REST. La realidad es diferente, ya que para considerarse REST además de utilizar este protocolo deberían hacer un uso correcto de los métodos y los códigos de estado o error.

Métodos (verbos)

Para realizar las peticiones, el protocolo Http proporciona una serie de métodos (también conocidos como “verbos”) que indican acciones que se van a realizar sobre un recurso, que no es más que un elemento de información. Cuando accedemos a una página web desde nuestro navegador, estamos realizando una petición a un servidor con el método GET. Si enviamos un formulario desde una web, estaremos realizando una petición con el método POST. Los sistemas REST utilizan estos métodos para identificar operaciones sobre los distintos recursos. Los métodos más utilizados por las APIS REST son los siguientes:

  • GET: Se utiliza para consultar, leer y en definitiva acceder a un recurso
  • POST: Envía datos para crear un recurso. Como en cualquier petición POST, los datos no se envían en la URI, sino que deben ir incluidos en el cuerpo de la petición.
  • PUT: Utilizado para editar un recurso. Al igual que el POST, los datos deben ir en el cuerpo de la petición.
  • DELETE: Es la opción para eliminar un recurso
  • PATCH: Se utiliza para modificar parcialmente un recurso, aunque se utiliza en muy pocas ocasiones. Normalmente se utiliza simplemente PUT.

El uso correcto de estos métodos es básico para considerar una API como REST. No se debería diseñar una API que realice modificaciones sobre un recurso mediante métodos GET, o que elimine elementos mediante un POST, sin embargo, existen numerosos casos de este tipo.

Códigos de error

En cualquier tipo de API es necesario que la aplicación cliente detecte si las peticiones u operaciones que ha realizado han finalizado de forma correcta o por el contrario se ha producido algún tipo de error. Es muy común que las APIs Restful definan unos códigos de error personalizados y no utilicen los códigos de error y estado propios del protocolo HTTP. Este comportamiento provoca que desde el punto de vista del cliente, sea necesario desarrollar un tratamiento de errores totalmente personalizado para cada API.
El protocolo HTTP define entre otros muchos, los siguientes códigos:

  • 200 → OK : Petición recibida y procesada de forma correcta
  • 201 → Created : Petición completada. El resultado ha sido la creación de un nuevo recurso
  • 204 → No Content: La petición es correcta, pero la respuesta no tiene ningún contenido
  • 401 → Unauthorized: La información de autenticación no es válida
  • 404 → Not found: El recurso no ha sido encontrado

Es importante aprovechar los códigos de error de HTTP y utilizarlos de una forma correcta, facilitando el desarrollo y consumo de nuestra API por los clientes. En muchas ocasiones, las APIs supuestamente Restful devuelven siempre el código 200 (sea cual sea el resultado de la petición), mientras que el resultado real va en el cuerpo del mensaje. Esto obliga a las aplicaciones clientes a procesar siempre el cuerpo de los mensajes recibidos y a conocer los errores y notaciones específicas que cada API ha definido.

Cacheable

Una interfaz de comunicación que siga los principios REST debe ser cacheable para poder mejorar los accesos por parte de los usuarios y el rendimiento general de la misma. Es posible que clientes realicen una misma petición de forma muy continuada. Si no hay modificaciones en los datos, es interesante disponer de caché para evitar un bajón en el rendimiento general del resto de usuarios. Cada petición debe indicar si el resultado de la misma puede ser o no cacheado. Un sistema de caché correcto afecta de forma positiva al rendimiento de y a la escalabilidad de la API.

Escalable

El sistema servidor encargado de recibir y procesar las peticiones debe ser susceptible de ser dividido en capas (por ejemplo, un nivel encargado de las peticiones del recurso A y otro encargado del recurso B). Esta capacidad, junto con el cacheo de las respuestas permite aumentar el rendimiento de estos sistemas. Además la división en capas permite además disponer de diferentes políticas de seguridad.

Identificación de recursos mediante URIs

A continuación nos centraremos en la información que proporciona una API y en cómo se identifica y organiza esta información. Este aspecto es fundamental si queremos diseñar una API REST que cumpla con los requisitos de dicha arquitectura. A los diferentes elementos de información los denominaremos “recursos”. Un recurso puede ser información sobre libros, clientes, coches, etc. pero un recurso nunca será una acción como por ejemplo “comprar_libro” o “crear_coche”. Previamente hemos indicado en la definición que un recurso debe estar identificado de forma única por una URI. Una URI no es más que una cadena de texto con una estructura determinada que nos permite identificar un elemento.

Una URI se estructura de la siguiente forma:

{protocolo}://{dominio o hostname}{:puerto(opcional)}/{ruta del recurso}?{parámetros}

Estamos utilizando URIs de forma continua cuando navegamos por internet (en concreto URLs, que son un tipo especial de URIs). Si por ejemplo, estamos navegando en un blog y accedemos a un artículo mediante esta dirección:

http://www.mibloginventado.com/articulos/2014/7/integracion-de-aplicaciones

A simple vista podemos identificar de forma sencilla que estamos accediendo a un blog llamado “mibloginventado” (el dominio o hostname), y una vez dentro de ese blog estamos accediendo a la sección de artículos del año 2014 y del mes 7 (julio). Finalmente dentro de este mes accedemos al artículo llamado “integración de aplicaciones”. Simplemente con el acceso a un artículo y fijándonos en la estructura de su URI podríamos detectar que el blog organiza los artículos agrupándolos en años, y que cada año a su vez agrupa los artículos en meses. Esta misma idea es la que se utiliza en las apis REST.
Para asignar una URI a un recurso existen varias reglas básicas:
  • Deben ser únicas, no pudiendo existir más de una URI para identificar un mismo recurso.
  • Deben ser independientes del formato en el que queramos consultar el recurso
  • Deben mantener una jerarquía en la ruta del recurso
  • No deben indicar acciones, por lo que no debemos usar verbos a la hora de definir una URI

Veamos una serie de ejemplos para aclarar estos conceptos.
Si tenemos una api situada en http://miapideejemplo.com, y un recurso llamado “productos”, la URI de acceso al producto cuyo identificador es 57 sería http://miapideejemplo.com/productos/57. Si quisieramos acceder a un recurso llamado “productos”, el cual nos devolvería el listado de los productos disponibles, la URI identificativa sería http://miapideejemplo.com/productos.
Existe un debate entre la utilización de plurales y singulares a la hora de definir una URI en referencia al acceso a un recurso, o al listado completo de recursos. La opción más sencilla es utilizar el plural (siempre que el recurso se refiera a una colección de elementos y no a un recurso único e inamovible como por ejemplo “configuration”), ya que minimizamos el uso de URLs y evitamos confusiones a la hora de acceder a un mismo recurso, que es lo que realmente estamos haciendo. Por ejemplo, para cubrir todas las necesidades de acceso sobre un recurso que representa a los clientes tendríamos las siguientes combinaciones de URI y comandos HTTP
En este caso, el recurso está definido de forma única por la misma URI (http://miapideejemplo.com/clientes) y todas las operaciones van dirigidas a dicha URI, sin necesidad de hacer modificaciones en la misma dependiendo de la operación que queramos realizar. Si queremos añadir funcionalidad de filtrado a la hora de obtener un listado de recursos, no debemos definir otra URI especial ni añadir nuevos elementos en la ruta de la URI, sino que podemos usar los parámetros de consulta de la query, que son una serie de pares (clave, valor) separados por el carácter “&” y que se sitúan en la URI tras el símbolo “?”.
Un ejemplo incorrecto a la hora de filtrar clientes sería:
El ejemplo correcto sería

Debemos ser cuidadosos a la hora de definir la jerarquía de los diferentes recursos. Si por ejemplo tenemos el recurso “tienda” y el recurso “dependiente”, la jerarquía lógica para acceder a un dependiente de una tienda debería ser http://miapideejemplo.com/tiendas/5/dependientes/3, mientras que una estructura menos lógica y que deberíamos evitar sería la que accede en primer lugar al dependiente y luego a la tienda en la que trabaja: http://miapideejemplo.com/dependientes/3/tiendas/5.

Recordemos que las URIs no deben indicar acciones, por lo que ejemplos como http://miapideejemplo.com/usuarios/update o http://miapideejemplo.com/update_usuarios deben ser evitados a toda costa.

Otros aspectos interesantes a tener en cuenta a la hora de definir las URIs de nuestro servicio son los siguientes:
  • Utilizar minúsculas y guiones o guiones bajos (snake-case) en lugar de mayúsculas y minúsculas (CamelCase)
  • No utilizar caracteres que necesiten codificación URL como por ejemplo espacios en blanco, comillas, etc.
  • No utilizar parámetros de consulta (?tipo=1) en peticiones que no sean de consulta.

Comentarios

Entradas populares