Conceptos Avanzados de Internet - Web Services (III) - REST PDF
Document Details
Uploaded by WorthyFeministArt5863
Escola Antònia Simó Arnó
Tags
Summary
Este documento proporciona una introducción a los Web Services REST. Explica los principios detrás de la arquitectura REST, incluyendo las restricciones y principios arquitecturales. Se incluyen ejemplos de peticiones y respuestas, así como un análisis de las operaciones CRUD y la diferencia entre las operaciones REST y RPC.
Full Transcript
# Conceptos Avanzados de Internet ## Web Services (III): REST ### REST - REST define unas guías o restricciones para definir Servicios Web que recogen los principios que han hecho que la Web haya llegado a tener tanto éxito. ### Algunos objetivos de REST son: #### Escalabilidad #### Generalidad de...
# Conceptos Avanzados de Internet ## Web Services (III): REST ### REST - REST define unas guías o restricciones para definir Servicios Web que recogen los principios que han hecho que la Web haya llegado a tener tanto éxito. ### Algunos objetivos de REST son: #### Escalabilidad #### Generalidad de las interfaces - Interfaces cliente-servidor intuitivas y sencillas (GET + recurso, PUT + recurso, etc.) #### Independencia en el desarrollo de componentes - Se puede modificar el código sin que afecte al funcionamiento del servicio (si se mantiene el interfaz). - Se pueden añadir nuevos recursos (no afecta a los existentes). #### Mejorar latencia - Permite el uso de cachés y balanceo de carga. ### REST: Restricciones / Principios arquitecturales - Un Servicio Web REST debe cumplir estas restricciones: - **Cliente-Servidor** - **Caché** - **Sistema por capas** - **Comunicación sin estados** - **Interfaz uniforme** - **Identificación de recursos** - **Manipulación de recursos a través de representaciones** - **Mensajes autodescriptivos** - **HATEOAS (Hypermedia As The Engine Of Application State)** - **Code On Demand** (opcional) - **REST no es la solución ideal para todo tipo de aplicación, se deben estudiar otras alternativas.** - **REST no es una religión! A veces puede ser interesante saltarse una restricción si una aplicación en concreto lo requiere.** - **Aunque el WS no se considere REST se beneficiará de las ventajas asociadas a otras restricciones.** - Niveles de madurez, del 0 (mínimo) al 3 (máximo) según cumplimiento de REST - **Nota:** REST no obliga a usar HTTP, pero se suelen usar juntos. ### Restricción: Interfaz uniforme - **Principal restricción de REST** - **Identifica qué se puede hacer con los recursos** - Se va a justificar la necesidad de esta restricción siguiendo el modelo de madurez de Richardson (definido posteriormente a REST), define en que medida un API se puede considerar RESTful. Asumimos que se usa el protocolo HTTP para las comunicaciones. | Nivel | Descripción | |---|---| | **3** | Controles hipermedia (hiperenlaces) – Totalmente REST | | **2** | Verbos HTTP – Usado en la mayor parte de WS | | **1** | Uso de recursos | | **0** | RPC – Nada REST | ### Nivel O de Richardson (nada REST) - Todas las peticiones se dirigen al mismo endpoint (URI), contienen nombre de operación y argumentos de entrada. #### Ejemplo petición y respuesta del servidor: - Cliente: ```xml POST /endpoint Accept: application/xml <leeEdad empleado=99/> ``` - Servidor: ```xml HTTP/1.1 200 OK Content-Type: application/xml Content-Lenght: 36 <edadEmpleado> 25 </edadEmpleado> ``` - Lista de operaciones disponibles: leeEdad, cambiaEdad, leeEmail, cambiaEmail, despideEmpleado, etc. - Muchas operaciones, cada una con distintos argumentos de entrada y de salida - Complejo de manejar por un programador! - Consultar todas las operaciones en documentación - En nivel O se ignora completamente HTTP - Se podría haber utilizado GET en lugar de POST (se ignora el método HTTP). Un GET para escribir!!! ### Nivel 1 de Richardson - **Añade el uso de recursos:** Cada recurso tiene su propia URI a la que se envían las peticiones. #### Ejemplo petición y respuesta del servidor: - Cliente: ```xml POST /emp/99 Accept: application/xml <leeEdad/> ``` - Servidor: ```xml HTTP/1.1 200 OK Content-Type: application/xml Content-Lenght: 36 <edadEmpleado> 25 </edadEmpleado> ``` - APIs siguen sin considerarse RESTful. - Mejora muy pequeña respecto al nivel 0: se puede especificar sobre qué recurso ejecutar la operación. ### Nivel 2 de Richardson - Se puede considerar que es REST (muchas APIs RESTful son de nivel 2) - Se usan los métodos de HTTP (HTTP verbs) - En las peticiones y respuestas se mandan representaciones de los datos. - Estado actual de un recurso, en una notación en concreto (JSON, XML, etc.) #### Ejemplo petición y respuesta del servidor: - Cliente: ```xml GET /emp/99 Accept: application/xml ``` - Servidor: ```xml HTTP/1.1 200 OK Content-Type: application/xml Date: Wed, 12 Oct 2016, 16:30 Content-Lenght: 74 <empleado id="99"> <edad> 25 </edad> <email>[email protected]</email> </empleado> ``` - **Ventajas:** - API más sencillo - Se determinan los recursos y su estructura - Las operaciones sobre ellos son intuitivas: ¿Pregunta: ¿Cómo cambiar la edad? - Se usa HTTP: - Permite uso de cachés. Se almacenan representaciones por si un recurso vuelve a pedirse más adelante - Código de respuesta da información útil (HTTP ahora es protocolo de aplicación) - P.ej. 201 = recurso creado, 404 = recurso no encontrado, 200 = respuesta estándar para peticiones correctas - Representación correspondiente al recurso empleado 99, el 12 de octubre de 2016, en formato XML ### Pregunta. REST: Modificar un campo de una representación - Un servidor tiene un recurso /empleado/125. La representación del recurso es: ```xml <empleado id="125"> <edad> 25 </edad> <email>[email protected]</email> </empleado> ``` - ¿Con cual de las siguientes opciones cambiarías la edad a 26 años (manteniendo el resto de campos igual)? A) GET /empleado/125 - 2.Modificar edad en la representación obtenida- 3.PUT /empleado/125 B) PUT /empleado/125 mandando una representación con solo la edad - ¿Te imaginas cómo se cambia el email? REST es intuitivo para un desarrollador. ### Nivel 3 de Richardson - **Añade hiperenlaces mediante HATEOAS (Hypermedia As The Engine Of Application State)** - Se dan enlaces a operaciones permitidas, no se permiten otras. - Se estudiará más adelante. #### Ejemplo petición y respuesta del servidor: - Cliente: ```xml GET /producto/25 Accept: application/json ``` - Servidor: ```json HTTP/1.1 200 OK Content-Type: application/json Date: Wed, 12 Oct 2016, 16:35 Content-Lenght: 74 {"nombre" : "Galaxy Note 7", "precio”: 800, "descripción": "es la bomba!", enlace a la lista de productos, enlace para comprar el producto } ``` ### Restricción: Interfaz uniforme (cont.) - La Interfaz Uniforme se divide en 4 restricciones a la interfaz cliente-servidor (con conceptos que acabamos de ver). - **Identificación de recursos** - **URIS**: /emp/35 - **Manipulación de recursos a través de representaciones**: XML, JSON, etc. - ```json {"nombre":"Pedro", "edad":25 ...} ``` - **Mensajes auto-descriptivos** - Método HTTP + URI - **APIs son fáciles de manejar** - **HATEOAS (Hypermedia As The Engine Of Application State)** - **Hiperenlaces** ### Interfaz uniforme: Mensajes auto-descriptivos - Los mensajes deben contener información suficiente para determinar cómo se deben procesar (qué método invocar) e interpretar (qué efecto van a tener). - Para determinar qué método (código) se invoca se suele usar: - Método HTTP (GET, PUT, POST, DELETE...) - URI - Tipo de datos solicitado o enviado (imagen, XML, JSON...) #### Ejemplo petición y respuesta del servidor: - **PETICIÓN:** ``` GET/ejemplo.com/empleado/100 HTTP/1.1 Accept: application/json ``` - **SERVIDOR Python (Flask):** ```python @app.route('/empleado/<int:id>', methods =['GET']) def get_empleado(id): ``` - **SERVIDOR JAVA:** ```java @GET @Path("/empleado/{id}") @Produces ("application/json") public Empleado getEmpleado(@PathParam ("id") String id) { } ``` - Observad como se usan decoradores (@decorador) en el servidor para que sepa que método ejecutar ### Interfaz uniforme: Representaciones de recursos - **Representación = estado actual de un recurso** ```json {"empleado": { "nombre":"Pedro", "edad": 25, "telefono": 623456789 } ``` ```json {"empleado": { "nombre":"Pedro", "edad": 25, "telefono": 968012345 } ``` - **Un mismo recurso puede tener representaciones en distintos formatos/lenguajes** - P. ej. XML o JSON - Cabecera Accept (y Content-Type) - Para solicitar un formato (y enviar datos) ```xml <empleado> <nombre> Pedro </nombre> <edad> 25 </edad> <telefono> 968012345 </telefono> </empleado> ``` ### Operaciones CRUD en REST - CRUD = Create, Read, Update, Delete. - Normalmente los datos se ordenan en colecciones de datos y se suele trabajar con ellos de la siguiente forma: (ejemplo para una colección de empleados) | URI | GET | PUT | POST | DELETE | |---|---|---|---|---| |emp/ | Lee lista emp | Sobrescribe lista emp. Añade/Sobre escribe empeado id | Añade nuevo empleado | Borra empleado | - Obligatorio que cada método HTTP se comporte tal y como definen las RFCs (GET = leer, etc.) y devuelva código de estado y cabeceras indicadas por la RFC. - Opcionalmente podemos permitir o no ciertas operaciones, a decisión del programador. - Borrar o sobrescribir colecciones ? (ver si es peligroso) - Crear nuevos ítems usando PUT? ### POST vs PUT para crear/modificar recursos - Ambos mandan la representación del objeto a escribir. - POST se dirige a la colección, no indica el identificador (normalmente) y deja al servidor asigne un identificador y una URI al recurso. #### Ejemplo petición y respuesta del servidor: - Cliente: ```json POST /emp Accept: application/json Content-Type: Application/json {"nombre": "Pedro", "ciudad": "Cartagena", "edad": 25 } ``` - Servidor: ```json HTTP/1.1 201 Created Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Location: /emp/4f39a0 Content-Lenght: 83 {"id": 4f39a0, "nombre": "Pedro", "ciudad":"Cartagena", "edad": 25 } ``` - El servidor elige un id (podría generar otros campos nuevos si lo creyera conveniente, p.ej. calcular el coste de un pedido a partir de los productos que incluye) y crea una URI a partir del id. - El código 201 indica al cliente que ha creado un nuevo recurso. - Indica al cliente la nueva URI con una cabecera location donde se encuentra el recurso. - Cabecera Location siempre acompaña a 201. - En el cuerpo se puede devolver debe devolver un mensaje informativo (a), de acuerdo a la RFC. A veces se devuelve una representación del recurso (b). - **Ventaja POST para crear:** el servidor elige el id y evita conflictos de ids repetidos (aunque ids sean menos intuitivos). - Servidor: ```json HTTP/1.1 201 Created Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Location: /emp/4f39a0 Content-Lenght: 57 {"status":"ok", "message":"new resource created"} ``` - PUT se dirige a la URI del recurso, exista o no (si no existe lo crea, si el servidor permite esa opción). #### Ejemplo petición y respuesta del servidor: - Cliente: ```json PUT/emp/25 Accept: application/json Content-Type: Application/json {"id": "25", "nombre": "Pedro", "ciudad":"Cartagena", "edad": 25 } ``` - Servidor: ```json HTTP/1.1 201 Created Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Location: /emp/25 Content-Lenght: 19 {"status":"ok"} ``` - La representación que se manda se usa para escribir el recurso. - El código 201 indica al cliente que ha creado un nuevo recurso (a). - El código 200 indica al cliente que el recurso se ha modificado (ya existía) y devuelve una representación con el estado de la operación (b). - El código 204 indica que se ha modificado y que no se devuelve cuerpo en la respuesta (c). - Indica al cliente la nueva URI con una cabecera location donde se encuentra el recurso. - En el cuerpo se puede devolver (a) una representación del recurso o (b) un mensaje informativo o incluso devolver el cuerpo vacío: en cualquier caso el recurso se puede encontrar mediante la cabecera location. - Servidor: ```json HTTP/1.1 200 OK Content-Type: application/json (b) Date: Wed, 12 Oct 2016, 16:30 Location: /emp/25 Content-Lenght: 57 {"status":"ok", "message": "resource modified"} ``` - Servidor: ```json HTTP/1.1 204 No content Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Location: /emp/25 Content-Lenght: 57 ``` ### Operaciones RPC vs REST - Operaciones para un empleado: - API RPC, - leeDirección (int id_empleado) - cambia Dirección (int id_empleado, String dir) - leeEdad(int id_empleado) - darDeBaja(int id_empleado) - Etc., etc. - API REST (GET, PUT, POST, DELETE) + URI - ```json {"id":25, "dirección":"Carlos III, 35", "email":"....", "estado":"Alta"...} ``` - Para cambiar la dirección de un empleado (Suponiendo que se sabe el id del empleado) - RPC: Consulta la extensa documentación del API > Llama a cambia Dirección (id) con POST - REST: Lee representación del recurso (GET /emp/25) > Modifica campo dirección (cliente en local) > Manda nueva representación (PUT/emp/25) - Para dar de baja a un empleado - RPC: Consulta la extensa documentación del API > Llama a darDeBaja(id) - REST: Igual que antes pero modifica el campo estado - Idem para resto de métodos - **No hay que conocer las (muchísimas) operaciones, solo los recursos (URIs* y estructura de datos)** - *Con HATEOAS no es necesario conocer las URIs ### Borrar un recurso - Se utiliza DELETE para borrar un recurso (hacer que desaparezca totalmente de la base de datos) - En caso de éxito, se devuelve 200 o 204 según si las respuesta incluye un mensaje de esto en el cuerpo o no. - En caso de error 4xx - según si el cliente ha hecho mal la petición (400), no se ha autenticado, no tiene permiso, etc. o 5xx (si falla el servidor). Códigos de error también podrían darse con otros métodos HTTP #### Ejemplo petición y respuesta del servidor: - Cliente: ``` DELETE /emp/25 Accept: application/json ``` - Servidor: ```json HTTP/1.1 200 OK Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Content-Lenght: 56 {"status":"ok", "message":"resource deleted"} ``` - Servidor: ```json HTTP/1.1 204 No content Date: Wed, 12 Oct 2016, 16:30 ``` ### Operaciones no CRUD - Si la operación no corresponde a leer, escribir o borrar → se puede usar POST. #### Ejemplo: Arrancar máquinas virtuales (VM). - Problema: Se configura una máquina virtual en /vm/155 (RAM, núcleos, etc.). ¿Cómo se hace para que comience a ejecutarse? - Cliente: ``` POST/vm/155/run ``` - Servidor: ```json HTTP/1.1 303 Redirect Content-Type: application/json Location:/vm/155 Date: Wed, 12 Oct 2016, 16:30 Content-Lenght: 100 {"status":"ok", "message":"VM running, check given URI to get the current state of the VM"} ``` - Automáticamente se modifica el estado de la VM (arrancando) > servidor redirecciona a /vm/155 para consultar nuevo estado. - Se ha devuelto 303 Redirect ya que se ha redireccionado a otro recurso existente. Si otros recursos no cambiaran se podría devolver un 200 (o un 201 si se creara un recurso, 204 si no hubiera cuerpo, etc.). - Cliente: ``` GET/vm/155 Accept: application/json ``` - Servidor: ```json HTTP/1.1 200 OK Content-Type: application/json Date: Wed, 12 Oct 2016, 16:30 Content-Lenght: 100 {"id": 12345, "OS": "Linux", "state": "booting", ....} ``` - Si I segundo después se vuelve a leer el estado seguiría siendo booting, si se lee un minuto después sería booted, etc. ### Otras restricciones de REST - Un Servicio Web REST debe cumplir estas restricciones: - Cliente-Servidor - Sistema por capas - Caché - **Comunicación sin estados** *más importante* - **Interfaz uniforme** *(la más importante)* - Identificación de recursos - Manipulación de recursos a través de representaciones - Mensajes autodescriptivos - HATEOAS (Hypermedia As The Engine Of Application State) - Code On Demand (opcional) ### REST: Restricción Cliente-Servidor - Se usa un modelo Cliente-Servidor que permite separar al servicio de los consumidores: - Componentes del cliente - Componentes del servidor - Interfaz cliente-servidor - Objetivos perseguidos (al aplicarse junto a otras restricciones): - Reusabilidad (del servicio) - Capacidad de evolución - Cliente y servidor evolucionan de forma separada, sin afectar a su funcionamiento - Escalabilidad - Busca que la complejidadad pase del servidor I cliente - En REST se persigue simplificar los componentes del servidor a costa del cliente. Cuantos menos recursos consuma un servidor más fácil será atender a más clientes sin sobrecargarse (y por tanto necesitar más servidores). - Portabilidad - Independencia del sistema operativo, lenguaje de programación. ### REST: Sistema por capas - Un sistema REST puede componerse de varias capas (que no tienen porqué conocerse entre ellas) y debe funcionar correctamente haya una o más capas: - Capas: Cliente, Proxies, Gateways/proxies inversos, Servidor, etc. - Se desconocen entre ellas - Pueden actuar como cachés (cliente, proxies, gateways), repartidores de carga (Gateways), implementar mecanismos de seguridad... - Objetivos: Mejorar rendimiento, escalabilidad, seguridad... ### REST: Caché - Datos en respuestas deben ser marcados como cacheables o no cacheables. - Con caché mejora el rendimiento (latencia) pero se podrían mandar datos obsoletos. #### Ejemplo: - Dato crítico de un solo cliente -> No cacheable - Dato compartido de acceso frecuente -> Cacheable (público, también en proxys y gateways) ### REST: Caché (II) - Cache-Control - Configuración de caché (dónde y cómo almacenar) - Cache-Control: public, max-age=3600 - Cache-Control: no-store - Etag (servidor) + If-None-Match (cliente) - Servidor envía una firma (hash) del recurso - Si cambia recurso cambia la firma - Cliente solicita recurso sólo si ha cambiado - Last-Modified (servidor) + If-Modified-Since (cliente) - Según fecha de modificación ### REST: Restricción “Comunicaciones sin estados / Stateless" (I) - No se debe almacenar información sobre el estado de una sesión entre un cliente y servidor. - El resultado de una petición no debe verse afectado por las peticiones anteriores realizadas o por el cliente o sobre el recurso (salvo que se haya modificado el recurso!) - GET /empleados?edad_minima=30 - GET /empleados?localidad=Cartagena - Por lo tanto, cada petición debe llevar toda la información necesaria para que el servidor la pueda entender correctamente. - GET /empleados?edad_minima=30&localidad=Cartagena - Es el cliente el que debe almacenar el estado, no el servidor. ### REST: Restricción “Comunicaciones sin estados / Stateless" (II) - Objetivos: - Visibilidad por parte de intermediarios (cacheado, balanceo de carga, seguridad, etc.) - Los dispositivos intermedios entienden las comunicaciones cliente-servidor y pueden realizar su tarea sin preocuparse por estos almacenado en otros dispositivos - Fiabilidad - Facilidad para recuperarse ante errores (si cae un servidor no importa ya que no almacena estado de las sesiones de los clientes) - Escalabilidad - Al no tener que almacenar el estado para cada cliente se facilita la escalabilidad. Se pueden lanzar peticiones a granjas de servidores y que cualquiera de ellos las procese - Desventajas - Pequeña degradación de la eficiencia al tener que mandarse más datos en cada petición. - Query params, tokens para seguridad (en cabeceras), datos JSON/XML, etc. - Pérdida de control por parte del servidor. El funcionamiento del servicio depende de que los clientes estén implementados correctamente. - Prueba para comprobar esta restricción: - Reiniciar el servidor y comprobar, tras arrancar, si el servicio sigue funcionando. - No se ha debido perder ningún dato del cliente (porque no los hay en el servidor) ### REST: Estado de los recursos vs estado de la aplicación - Que no haya estado en las comunicaciones (sesión) no implica que no haya ningún tipo de estado: - Estado de los recursos: - Valor de los recursos (imagen, empleados, etc.) - Almacenado en el servidor (almacenamiento permanente, en base de datos) - Estado de la aplicación: - Estado del cliente, almacenado en el cliente. - Ejemplo en la Web: hacer una búsqueda en Google - https://www.google.es/search?q=upct&start=40 - En navegador solo podemos estar en un página a la vez > Vamos a considerar que la página en la que estamos es el estado del cliente. - Si hacemos una búsqueda tendremos páginas con 10 resultados (0..10 > P1, ..., 40..50 > P5). - Pedir desde el resultado 40 (página 5): - https://www.google.es/search?q=upct&start=40 - Es en la propio navegador (o un cliente de un servicio web) donde está este tipo de estado. - Al servidor le da igual si hemos visto las páginas anteriores, solo da la página que le pidamos. ### REST: HATEOAS - HATEOAS (Hypermedia As The Engine Of Application State) - Es la restricción más ignorada (compleja) pero también la que mayores posibilidades ofrece. - Hipermedia: - Hipertexto: Texto con (hiper)enlaces a otros textos. - Hipermedia: Término más genérico en el que además de texto puede haber imágenes, audio o video. - Propósito: - Al igual que en la Web busca que el servidor ofrezca una serie de enlaces y el cliente "navegue" a través de ellos. - El servidor dice al cliente qué puede hacer en cada momento a través de enlaces (links) → El servidor controla el estado de la aplicación (estado del cliente). - En cada mensaje de respuesta del servidor las representaciones de los recursos incluyen enlaces para la próxima petición. - Las representaciones devueltas contienen el nuevo estado de la aplicación. ### REST: Ejemplo HATEOAS (I) - Ejemplo: Una aplicación móvil para manejar la cuenta del banco. - Petición con saldo positivo: ```xml GET/cuentas/12345 HTTP/1.1 HTTP/1.1 200 OK <?xml version="1.0"> <cuenta> <numero> 12345 </12345> <saldo> 1000 </saldo> <link rel="self" href="/cuentas/12345" method="GET"> <link rel="ingreso" href="/cuentas/12345/ingresos" method="POST"> <link rel="transferencia" href="/cuentas/12345/transferencias" method="POST"> <link rel="cierre" href="/cuentas/12345/cerrar" method="POST"> </cuenta> ``` - Permite operaciones que impliquen ingresar o sacar dinero, incluso cerrar la cuenta. ### Pregunta: Ejemplo banco con HATEOAS, ¿Qué ocurre con una cuenta en negativo? - Si tenemos la cuenta en números rojos y el banco no nos permite deberle más dinero: - 1. ¿Qué operaciones nos dejará hacer? ¿Ingresos? ¿Transferencias? ¿Dar de baja? - 2. ¿Qué ocurre si intentamos hacer una operación que no está en los enlaces que devuelve el servidor? ¿Es correcto hacerla? ¿No deberíamos? ### REST: Ejemplo HATEOAS (II) - Ejemplo: Una aplicación móvil para manejar la cuenta del banco. - Petición con saldo negativo: ```xml GET/cuenta/12345 HTTP/1.1 HTTP/1.1 200 OK <?xml version="1.0"> <cuenta> <numero> 12345 </12345> <saldo>-100 </saldo> <link rel="self" href="/cuentas/12345" method="GET"> <link rel="ingreso" href="/cuentas/12345/ingresos" method="POST"> </cuenta> ``` - Ahora sólo permite ingresar dinero. - El servidor controla el estado de la aplicación (en el cliente). ### REST: Links en HATEOAS - Ejemplo links: ```xml <link rel="self" href="/cuentas/12345" > <link rel="ingreso" href="/cuentas/12345/ingresos"> ``` - Ejemplo links en JSON: ```json {"links":[ {"rel": "ingreso", "href" : "/cuentas/12345/ingresos"}, {"rel": "transferencia", "href" : "/cuentas/12345/transferencias"} ]} ``` - Ejemplo links en JSON (más común): ```json {"links": [ {"ingreso":"http://example.com/customers/771/ingresos"}, {"transferencia": "http://example.com/customers/771/ transferencia"}, ] ``` - Tipos de enlaces entre recursos predefinidos (y creciendo): http://www.iana.org/assignments/link-relations/link-relations.xml - Se pueden crear nuevas relaciones para cubrir las necesidades de una aplicación en particular (p.ej. ingreso, retirada, transferencia, cierre) - El cliente debe entender su significado y procesarlas correctamente. - En caso de no conocer alguna relación la ignora (pero sigue funcionando). - Los enlaces deben incluir la URI y opcionalmente: método tipo de datos (ejemplo: application indapet formulario-para-transferencia a json ### REST: HATEOAS, ejemplo relación next - Se hace una petición al servidor sobre un conjunto de datos pero éste no devuelve todo el conjunto. - Tipo de relación predefinido "next": ```xml <products> <link rel="next" href="http://example.com/webstore/products?startIndex=5" > <product id="123"> <name>headphones</name> <price>$16.99</price> <link rel="self" href="http://example.com/webstore/products/123/> </product> <product id="156"> <name>microphone</name> <price>$9.99</price> </product> </products> ``` - Indica que para obtener la siguiente parte de la lista de productos se debe acceder a la URI http://example.com/webstore/products?startIndex=5. ### REST: HATEOAS conclusiones - Un Servicio Web bien implementado permitiría que un cliente le bastara con conocer la URI de entrada al servicio web. - A partir de la representación recibida podría ir determinando sobre qué otros recursos puede hacer peticiones. #### Principal ventaja HATEOAS - El servidor puede evolucionar sin apenas afectar al cliente. - P. ej. se pueden cambiar las URIs. - El servidor controla qué puede hacer el cliente. #### Inconveniente: Programación más compleja. - Se puede recurrir a usar enlaces como self y next, (y otros) sin hacer el servicio HATEOAS. - En HATEOAS cualquier operación del cliente estaría controlada por enlaces, no solo unas pocas. - Según el creador de REST, sin HATEOAS un WS no es REST. Otros distinguen entre niveles de madurez de REST (se puede ser REST sin HATEOAS). Los servicios reales no suelen ser HATEOAS ### REST: Code On Demand - Restricción opcional, poco explorada. - Permite ampliar la funcionalidad de un cliente en tiempo de ejecución, sin parar el cliente. - Si un cliente no sabe como procesar un tipo de datos o un enlace (HATEOAS) puede descargar un script (p.ej. javascript) con la nueva funcionalidad. ### Seguridad (I) - **Confidencialidad:** Asegurar que sólo el interesado pueda ver la información. - Se suele usar HTTPS (HTTP + TLS/SSL). - **Autenticación (Autorización):** Demostrar que el cliente tiene permiso para acceder a los recursos. - Métodos: - **Seguridad Básica de HTTP:** Se envía usuario y contraseña en cada petición, sin cifrar. - Muy muy recomendable combinar con HTTPS! - Las contraseñas se almacenan en el cliente (vulnerabilidad) - Método menos seguro - **HTTP digest** - Se aplica una función de cifrado(MD5) sobre el usuario y la contraseña y un valor pseudo-aleatorio. - Las contraseñas se almacenan en el cliente (inconveniente) - Algo más seguro ### Pregunta: Cifrado vs codificación - Respecto a la petición y a la cabecera Authorization indique para cada una si van cifradas o codificas. - Nota: Codificar solo implica cambiar los caracteres que se muestran, no se necesita una clave para descodificar. Cifrar sí requiere clave y añade algo más de seguridad. - Observe: Protocolo empleado (ver URL), tipo de autenticación (ver diapositiva anterior). ### Seguridad (II): Tokens - Existen muchos métodos de autorización de acceso a recursos basados en enviar tokens. - Inicialmente un usuario manda usuario y contraseña (una vez) > Un servidor le devuelve un token de que le dará acceso a los recursos - Si un atacante obtiene el token no podrá obtener la contraseña del usuario - Pero sí podrá acceder a sus recursos mientras el token siga siendo válido - Sigue siendo recomendable usar HTTPS para proteger los tokens (y el resto del mensaje) ### Seguridad (III) - JSON Web Token (JWT) - Además de lo visto, con JWT los tokens pueden contener información del usuario: - Cabecera: Tipo de token y algoritmo. - Payload: Claims o derechos de un usuario. - Firma: Verifica que el token no ha sido alterado. Cifra cabecera, payload y secret (clave). - **Ventajas:** - Para autorización: Un mismo token puede usarse fácilmente en distintos dominios (p.ej. Google y Youtube). - Intercambio de información del usuario. - Autenticación: Si se usan pares clave pública/privada se puede verificar que el emisor es quien dice ser. ### Seguridad (IV) - OAuth (versiones I y 2): Autorización - Basado en tokens. El usuario (propietario de los recursos) delega en la aplicación (cliente) la capacidad de realizar ciertas acciones en su nombre. - Participantes: - Propietario de los recuros (usuario) - Servidor de recursos (servicio). Ej. Servidor con datos de empleados, productos, etc. - Cliente. Aplicación que accede a los datos en nombre del propietario/usuario. - Servidor de autorización (Ej. Facebook, Google). Da los tokens al cliente. Tras un proceso en el que el propietario introduce su usuario y contraseña. - Ejemplo: https://developers.google.com/oauthplayground/ - Para ver las etiquetas en Gmail: - En scope (Authoriza APIs) marcar Gmail API > ... Gmail.labels - Pulsar Authorize API. Aceptar compatir la información - A partir del código de autorización, obtener un token de acceso. - Hacer petición con el token de acceso (en id de usuario usar el email o "me"). - Nota: Hay diversas variantes de OAuth, según si el usuario manda contraseña al servidor de autorización, a la aplicación, etc. ### Seguridad (V) - OpenID Connect : Capa de identidad sobre OAuth para poder identificar a los usuarios. - Se puede hacer un GET a /userpoint (en el servidor de autorización) y devuelve un JSON con información del usuario. - Además del access token, se crea un id token con información del usuario en formato JWT. - Ejemplo con Google OAuth Playground: - Solicitar scope "openid profile" en OAuth 2.0 Playground de Google (o bien openid email). - Obtener un token de acceso (refrescar si ya había uno antiguo). - Hacer un GET a https://openidconnect.googleapis.com/v1/userinfo - La identificación puede valer para varios dominios: - Ej. Tras hacer login con la cuenta de Google también se puede acceder a la cuenta