Skip to content

6 Arquitectura REST

Arquitectura REST

Una API es una forma de describir la forma en que los programas o los sitios webs intercambian datos. El formato de intercambio de datos normalmente es JSON o XML.

Las APIs se usan para ofrecer datos a aplicaciones cliente, ya sean web, de escritorio o móviles, incluso desarrolladas por la misma empresa propietaria de la API.

REST cambió por completo la ingeniería de software a partir del 2000. Este nuevo enfoque de desarrollo de proyectos y servicios web fue definido por Roy Fielding, el padre de la especificación HTTP y uno los referentes internacionales en todo lo relacionado con la Arquitectura de Redes, en su disertación Architectural Styles and the Design of Network-based Software Architectures’.

En el campo de las APIs, REST (Representational State Transfer- Transferencia de Estado Representacional) es, a día de hoy, el alfa y omega del desarrollo de servicios de aplicaciones.

REST

Interfaz uniforme entre sistemas que automatiza el uso de HTTP para las operaciones sobre los datos

En la actualidad no existe proyecto o aplicación que no disponga de una API REST para la creación de servicios profesionales a partir de ese software. Twitter, YouTube, los sistemas de identificación con Facebook… hay cientos de empresas que generan negocio gracias a REST y las APIs REST. Sin ellas, todo el crecimiento en horizontal sería prácticamente imposible. Esto es así porque REST es el estándar más lógico, eficiente y habitual en la creación de APIs para servicios de Internet.

Buscando una definición sencilla, REST es cualquier interfaz entre sistemas que use HTTP para obtener datos o generar operaciones sobre esos datos en todos los formatos posibles, como XML y JSON. Es una alternativa en auge a otros protocolos estándar de intercambio de datos como SOAP (Simple Object Access Protocol), que disponen de una gran capacidad pero también mucha complejidad. A veces es preferible una solución más sencilla de manipulación de datos como REST.

REST API

Figura 6 - REST API

Como ya sabemos, el protocolo HTTP es un protocolo cliente/servidor sin estado, de manera que cada petición HTTP contiene toda la información necesaria para ejecutarla, lo que permite que ni cliente ni servidor necesiten recordar ningún estado previo para satisfacerla. Aunque esto es así, algunas aplicaciones HTTP incorporan memoria caché. Para ello se configura lo que se conoce como protocolo cliente-caché-servidor sin estado, haciendo que exista la posibilidad de definir algunas respuestas a peticiones HTTP concretas como cacheables, con el objetivo de que el cliente pueda ejecutar en un futuro la misma respuesta para peticiones idénticas. De todas formas, que exista la posibilidad no significa que sea lo más recomendable.

URIs

Los recursos en REST siempre se manipulan a partir de la URI. Es la URI y ningún otro elemento el identificador único de cada recurso de ese sistema REST. La URI nos facilita acceder a la información para su modificación o borrado, o, por ejemplo, para compartir su ubicación exacta con terceros.

La API REST debe ser jerárquica, usando nombres en plural para los recursos, y un identificador para el recurso concreto. Por ejemplo, para la lista de recurso "post", usaremos http://jsonplaceholder.typicode.com/posts/, y para el recurso "post" individual con el id 1 usaremos http://jsonplaceholder.typicode.com/posts/1.

La arquitectura REST define una jerarquía de recursos. Por ejemplo la URI https://jsonplaceholder.typicode.com/users/1/todos representa las tareas pendientes (todo) del usuario (user) cuyo identificador es 1.

Operaciones

Para la transferencia de datos en un sistema REST, este aplica acciones concretas (POST, GET, PUT y DELETE) sobre los recursos, siempre y cuando estén identificados con una URI. Esto facilita la existencia de una interfaz uniforme que sistematiza el proceso con la información.

Las operaciones más importantes relacionadas con los datos en cualquier sistema REST y la especificación HTTP son cuatro: GET (leer y consultar), POST (crear), PUT (editar) y DELETE (eliminar). Algunos servidores proporcionan también la operación de PATCH (actualización parcial de un recurso).

Para obtener una lista de recursos se usará el método GET y una URI que represente la lista de recursos:

GET /posts/ HTTP/1.1
Host: jsonplaceholder.typicode.com

La respuesta usará el código de estado HTTP para representar el resultado:

Respuesta de lista de recursos

HTTP/1.1 200 OK
Date: Tue, 21 Jan 2020 11:47:49 GMT
Content-Type: application/json; charset=utf-8

[ { "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" }, { "userId": 1, "id": 2, "title": "qui est esse", "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" }, { "userId": 1, "id": 3, "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" } ]

Para obtener un recurso concreto se usará el método GET y una URI que represente un recurso individual:

GET /posts/1 HTTP/1.1
Host: jsonplaceholder.typicode.com

La respuesta usará el código de estado HTTP 200 para indicar que se ha encontrado:

Respuesta de recurso individual correcta

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" }

o el código de estado 400 para indicar que no se ha encontrado:

HTTP/1.1 404 NOT FOUND
Content-Type: application/json; charset=utf-8

{}

Para la creación de recursos se usará una URI que represente una lista de recursos (el recurso todavía no existe y por tanto no tiene id), el método HTTP debe ser POST, y se mandará en el cuerpo de la petición los datos del recurso a crear:

POST /posts HTTP/1.1
Host: jsonplaceholder.typicode.com
Content-type: application/json; charset=UTF-8

{ "title": "foo", "body": "bar", "userId": 1 }

Como respuesta a la creación de un recurso obtendremos alguno de los siguientes códigos de respuesta: 403 (Acceso prohibido), 400 (petición incorrecta, p.ej. falta un campo o su valor no es válido), 500 (Error del lado del servidor al intentar crear el recurso, p.ej. se ha caído la BD, 201 (Recurso creado correctamente). Además, la convención en REST es devolver en la respuesta la URL del recurso recién creado como valor de la cabecera HTTP Location.

HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: http://jsonplaceholder.typicode.com/posts/101

{ "title": "foo", "body": "bar", "userId": 1, "id": 101 }

Respecto a la actualización de recursos, se usará una URI que apunte a un recurso individual. Usaremos el método PUT si vamos a enviar todos los datos recurso, o el método PATCH para cambiar solo ciertos datos (no soportado por todos los servicios):

PUT /posts/1 HTTP/1.1
Host: jsonplaceholder.typicode.com
Content-type: application/json; charset=UTF-8

{ "title": "Baldomero", "body": "Llegate Ligero", "userId": 1 

y la respuesta incluirá alguno de los códigos respuestas que ya hemos visto:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{ "title": "Baldomero", "body": "Llegate Ligero", "userId": 1, "id": 1 }

Si queremos eliminar un recurso, deberemos usar una URI que apunte a un recurso individual, e indicar el método DELETE:

DELETE /posts/1 HTTP/1.1
Host: jsonplaceholder.typicode.com
Content-type: application/json; charset=UTF-8

y la respuesta será:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{}

HATEOAS

Para cualquier API REST es obligatorio disponer del principio HATEOAS (Hypermedia As The Engine Of Application State - Hipermedia Como Motor del Estado de la Aplicación) para ser una verdadera API REST. Este principio es el que define que cada vez que se hace una petición al servidor y éste devuelve una respuesta, parte de la información que contendrá corresponderá a los hipervínculos de navegación asociada a otros recursos del cliente.

Por ejemplo, en la siguiente API con datos sobre las películas de Star Wars, cuando solicitamos el recurso correspondiente al personaje cuyo id es 1

GET /api/people/1 HTTP/1.1
referer: https://swapi.co/api/people/1

en la respuesta se incluyen las URI con las que podemos acceder en la misma API a cada una de las películas en las que aparece dicho personaje:

Respuesta de personaje con id 1

HTTP/1.1 200 OK
Content-Type: application/json

{
    "name": "Luke Skywalker",
    "height": "172",
    "mass": "77",
    "hair_color": "blond",
    "skin_color": "fair",
    "eye_color": "blue",
    "birth_year": "19BBY",
    "gender": "male",
    "homeworld": "https://swapi.co/api/planets/1/",
    "films": [
        "https://swapi.co/api/films/2/",
        "https://swapi.co/api/films/6/",
        "https://swapi.co/api/films/3/",
        "https://swapi.co/api/films/1/",
        "https://swapi.co/api/films/7/"
    ],
    "species": [
        "https://swapi.co/api/species/1/"
    ],
    "vehicles": [
        "https://swapi.co/api/vehicles/14/",
        "https://swapi.co/api/vehicles/30/"
    ],
    "starships": [
        "https://swapi.co/api/starships/12/",
        "https://swapi.co/api/starships/22/"
    ],
    "created": "2014-12-09T13:50:51.644000Z",
    "edited": "2014-12-20T21:17:56.891000Z",
    "url": "https://swapi.co/api/people/1/"
}

Ventajas

El servidor debe marcar de forma implícita o explícita las respuestas para indicar si el cliente puede o no cachearlas. Así, en futuras peticiones, el cliente sabrá si puede reutilizar o no los datos que ya había obtenido. Al ahorrar peticiones, mejoraremos la escabilidad de la aplicación y el rendimiento en cliente (evitamos principalmente la latencia de red).

REST ofrece una serie de ventajas para el desarrollo:

  • Separación entre el cliente y el servidor: el protocolo REST separa totalmente la interfaz de usuario del servidor y el almacenamiento de datos. De esta manera el cliente acceder a los recursos a través de su identificador, pero no tiene conocimiento real de cómo estar almacenados realmente dichos recursos en el servidor. Esto tiene algunas ventajas cuando se hacen desarrollos. Por ejemplo, mejora la portabilidad de la interfaz a otro tipo de plataformas, aumenta la escalabilidad de los proyectos y permite que los distintos componentes de los desarrollos se puedan evolucionar de forma independiente.
  • Visibilidad, fiabilidad y escalabilidad. La separación entre cliente y servidor tiene una ventaja evidente y es que cualquier equipo de desarrollo puede escalar el producto sin excesivos problemas. Se puede migrar a otros servidores o realizar todo tipo de cambios en la base de datos, siempre y cuando los datos de cada una de las peticiones se envíen de forma correcta. Esta separación facilita tener en servidores distintos el front-end y el back-end , permitiendo que éstos sean desarrollados por separado, convirtiéndolos en productos más flexibles a la hora de trabajar. Mientras la interfaz no cambie, podremos cambiar el cliente o el servidor sin problemas.
  • La API REST siempre es independiente del tipo de plataformas o lenguajes: la API REST siempre se adapta al tipo de sintaxis o plataformas con las que se estén trabajando, lo que ofrece una gran libertad a la hora de cambiar o probar nuevos entornos dentro del desarrollo. Con una API REST se pueden tener servidores PHP, Java, Python o Node.js. Lo único que es indispensable es que las respuestas a las peticiones se hagan siempre en el lenguaje de intercambio de información usado, normalmente XML o JSON.
  • Permite el uso de un sistema de capas o servidores intermedios, para aumentar la escalabilidad (sistemas de balanceo de carga, cachés) o para implementar políticas de seguridad. Por su parte, el cliente puede estar conectado mediante la interfaz al servidor principal o a un intermediario, ya que esto será transparente para él.