Este documento presenta una breve introducción al estilo arquitectónico REST (Representational State Transfer) para servicios web. Explica conceptos clave como recursos, verbos HTTP, códigos de respuesta, APIs CRUD y operaciones asíncronas. También incluye ejemplos prácticos de transferencias de estado que ilustran el uso de métodos como GET, POST, PUT, PATCH y DELETE.
2. Contenido de la charla
• Qué es REST?
o
o
o
o
o
Definición
Conceptos
Verbos HTTP
Códigos de respuesta
Ejemplos
• APIs CRUD
o Operaciones sobre recursos
o Problemas de concurrencia
o Operaciones asíncronas
• Seguridad en REST
• Testing y pruebas
3. Sobre mi
• Programador web PHP
desde hace 4 años
(aprox. 1 con
Symfony2).
• Muy fan de
NodeJS, Angular y
Javascript en general
• Aficionado a la
seguridad informática y
redes.
6. Qué es REST?
Es una tecnología? ✗
Es una arquitectura?
7. Qué es REST?
Es una tecnología? ✗
Es una arquitectura? ✗
Es un “estilo arquitectónico”?
8. Qué es REST?
Es una tecnología? ✗
Es una arquitectura? ✗
Es un “estilo arquitectónico”? ✓
Cuando hablamos de REST nos referimos a una forma
de implementar una arquitectura en concreto
(arquitectura WebService) por eso solemos decir que
REST es sólo un estilo de elaborar servicios web.
10. ¿Qué es REST?
• La primera vez que se habló de REST fue en el año
2000 en la tesis doctoral de Roy Fielding, uno de los
principales autores del protocolo HTTP
• Está orientado a transferencias de recursos, no a
llamadas de procedimientos remotos (RPC)
• Hace un uso muy eficiente del protocolo
HTTP, rompe con el esquema de la web que
funciona solo con GET y POST
11. REST en la actualidad
• A día de hoy se conoce por REST a casi cualquier
servicio Web que trabaje con XML y HTTP
• La mayor parte de las APIs existentes son simples
interfaces para interactuar con la base de datos
(CRUD básico)
• REST nos permite modelar totalmente nuestro
negocio sin importar el lenguaje en que este
implementado el servicio o el cliente
12. Conceptos y reglas
• El servicio representará recursos, no acciones
o No se publican verbos como “comprar”
o Se usan recursos como “pedido” o “compra”
• Todos los recursos deben de poseer un UUID
o Universal Unique Identifier
o Todo recurso en REST necesita un UUID para ser identificado dentro del
sistema
• La forma en que se represente internamente un
recurso debe ser privada
• Todos los recursos deben de poseer un interfaz de
operaciones, y todos deben de implementarlas.
13. Cómo funciona?
• Las operaciones se realizan por transferencia de
estado
o El cliente pide una copia del recurso al servicio
o El cliente modifica el recurso
o El cliente transfiere el recurso actualizado al servicio
• Los recursos deben ser multimedia
o Los recursos deben de poder expresarse en más de un formato
• JSON, XML, CSV…
o En las peticiones podemos y debemos indicar el tipo de formato que
admitimos, o una lista con varios, ordenada por prioridades.
• Según la implementación que se consiga, un API se
cataloga en uno de los niveles REST
14.
15. Verbos HTTP
• El protocolo HTTP define un conjunto de verbos que nos
permiten realizar todo tipo de operaciones:
o
o
o
o
o
o
GET (LEER)
PUT (CREAR O ACTUALIZAR RECURSO COMPLETO)
POST (CREAR, ACTUALIZAR PARCIALMENTE UN RECURSO)
PATCH (ACTUALIZAR PARCIALMENTE UN RECURSO)
DELETE (BORRAR)
OPTIONS (CONSULTAR OPERACIONES)
• http://www.restapitutorial.com/lessons/httpmethods.html
• Usarlos incorrectamente lleva a desastres como el de
Basecamp.
o
http://www.mail-archive.com/isn@attrition.org/msg04213.html
16.
17. POST e idempotencia
• POST es él verbo “maldito” por REST, al no ser
idempotente.
• La idempotencia asegura que ejecutar n veces
una transferencia obtendrá el mismo resultado.
• Se usa para modelar operaciones como:
o Crear recursos
o Modificar parcialmente recursos…
18. Códigos de Respuesta
•
El resultado de una transferencia REST viene dado por el código de
estado de la respuesta HTTP, en REST, los más habituales son:
o
o
o
o
o
o
o
o
o
o
o
o
•
200 (OK)
201 (Creado)
202 (Aceptado)
204 (Sin contenido)
304 (No modificado)
400 (Petición mal formada)
401 (No autorizado)
403 (Acceso no permitido)
404 (No encontrado)
409 (Conflicto)
412 (Fallo de pre-condición)
500 (Problema de Servidor)
http://www.restapitutorial.com/httpstatuscodes.html
20. Ejemplos
En nuestra API de pruebas usaremos:
•
GET
o
o
•
Eliminar recursos
o
•
Actualizaciones totales de recursos
o
•
Actualizaciones parciales
o
•
Creación de recursos
o
•
Obtener recursos o colecciones de recursos
Consultar acciones disponibles
POST
PATCH
PUT
DELETE
OPTIONS
La URL sobre la que trabajaremos será:
http://symfonyvalencia.es/api/usuarios
El servidor puede devolver datos en XML o en JSON
32. APIs CRUD
• Son las APIs más habituales
• CRUD
o
o
o
o
Create (crear)
Read (leer)
Update (actualizar)
Delete (borrar)
• Cubren las operaciones básicas que realizamos
habitualmente sobre entidades
• Implementan todos los verbos HTTP
• Son lo contrario a APIs read-only
• Son bastante sencillas de implementar
• En Symfony2 existen bundles que facilitan su
implementación, como FOSRESTBundle
33. APIs CRUD
• Si pretendemos ceñirnos absolutamente al
concepto de API REST, no debemos de diseñar
nuestra API como un reflejo de las entidades, ya
que expone nuestro esquema de base de datos.
• Un cambio en una entidad no debería de afectar
al uso del API.
• Se trata de modelar nuestro negocio con
operaciones sobre recursos no de crear un interfaz
para gestionar nuestra base de datos.
34. Acceso concurrente
• Si a nuestro Web Service se conectan
simultáneamente varias personas y modifican el
mismo registro… ¿Puede haber problemas de
inconsistencia?
• El problema de la inconsistencia en REST se
soluciona habitualmente con la inclusión de
cabeceras Etag y If-Match.
• Se utilizan Etags débiles, ya que las fuertes son
demasiado estrictas para nuestro propósito
38. Actualizaciones parciales
• Otro problema básico en REST es la actualización
parcial del contenido.
• Si usamos PUT, sobrescribimos todo el recurso, ¿y si solo
queremos cambiar un atributo del recurso?
• El método habitual se basa en crear nuevos tipos MIME
de cambio de estado o diff y usar POST.
• La solución moderna pasa por usar el verbo
PATCH, funciona igual que con POST, pero es más
semántico y solo admite tipos MIME que representen
diffs
39. Actualizaciones parciales
• Cuando hablamos de diffs hablamos de crear un
formato o tipo MIME que represente una operación
de actualización parcial sobre un registro.
• Suelen nombrarse como:
o
application/recurso-diff+formato
• Recurso es el tipo de entidad (usuario, factura…)
• Formato puede ser cualquier formato (json, xml…)
• Ejemplos:
o application/usuario-diff+json
o application/usuario-diff+xml
42. Operaciones de larga
duración o asíncronas
Cuando las operaciones no son inmediatas, o deben
ser encoladas porque se procesan en bloque a cierta
hora mediante un cron, o necesitan validación de un
servicio externo (pasarelas de pago, Paypal…), el
usuario debe de poder seguir el estado del recurso.
Con REST es posible modelar operaciones asíncronas
o encolables creando un recurso intermedio que
represente el estado del recurso antes de finalizar su
creación.
43. Ejemplo
• Vamos a realizar un pago a una tienda online vía
REST
• El pago debe de ser validado por la entidad
bancaria que implementa la pasarela de pago.
• El proceso puede tardar entre 3 y 5min
• El cliente desea saber cuando ha sido validado el
pago
50. Seguridad en REST
• En el contexto de un servicio REST no existe el concepto
de Sesión, ya que HTTP es un protocolo Stateless no
orientado a conexión.
• Si nuestra API necesita autenticar a sus usuarios, estos
deben de hacerlo en cada petición
• Esto simplifica un ataque por parte de intrusos
• Veamos algunas normas básicas de seguridad en REST
52. 1. No uses IDs predecibles
• Cualquier intruso que sniffe nuestro tráfico y
detecte una petición del tipo:
GET /api/usuario/1/datos-bancarios
• Se verá tentado de probar con:
GET /api/usuario/2/datos-bancarios
GET /api/usuario/3/datos-bancarios
GET /api/usuario/n/datos-bancarios
• Tampoco debemos usar las claves primarias de
nuestra base de datos, nos exponemos a ataques
SQLi
54. 2. Usa HTTPS
• Con el protocolo HTTPS ya tenemos ganado la
mitad
• Es un protocolo seguro y el contenido va
cifrado, tanto para peticiones como para
respuestas.
• Si transmitimos información sensible no será
fácilmente reproducible por un atacante que haya
usado un sniffer
• Nos da seguridad a la hora de transmitir
contraseñas
56. 3. Genera Tokens de
seguridad
• Si creamos nuestro propio esquema de
seguridad, generando Tokens que caduquen cada
cierto tiempo, evitaremos transmitir la contraseña
demasiadas veces.
• Después de la primera autenticación, el servidor
nos transmite nuestro Token
• En las próximas peticiones lo incorporaremos en
una cabecera, o una cookie
58. 4. Algoritmo HMAC
• Nos puede ayudar a construir buenos Tokens
PARTE_PUBLICA = UUID + “:” + NIVEL_SEGURIDAD + ”:”
+ TIMESTAMP
FIRMA = HMAC(CLAVE_SECRETA, PARTE_PUBLICA)
TOKEN = FIRMA + ”_” + PARTE_PUBLICA
• Desde el servidor basta con descomponer el Token
en las componentes FIRMA y PARTE_PUBLICA, volver
a calcular la firma con la PARTE_PUBLICA recibida y
comparar la firma generada con la recibida
59. 4. Algoritmos ajustables
• Algoritmos como BCRYPT o PBKDF aceptan un
parámetro de “complejidad”, que permiten indicar
cuanto tardará en calcularse la contraseña.
• Esto limita los ataques de fuerza bruta, por
ejemplo, con una complejidad de 500ms solo
podrían probarse 2 passwords por segundo.
61. 5. Usa OAuth
• Una opción alternativa a generar nuestros tokens es
implementar un servidor OAuth que nos permita
acceder a nuestra API
• Existen librerías en casi todos los lenguajes que
implementan OAuth
• Podemos incluso usar nuestros credenciales en
redes sociales para acceder a nuestra API.
64. Testing y pruebas
• Como cualquier otro programa, aplicación web… que
desarrollemos, las APIs REST se pueden implementar
usando TDD.
• Es importante testear siempre que todos los códigos de
respuesta devueltos son adecuados, tanto para casos
de éxito como para casos de error.
• IMPORTANTE: Muchos frameworks implementan listeners
de excepciones y evitan, por ejemplo que una página
devuelva un 404, enmascarando el resultado con una
respuesta 200.
65. Testing con xUnit
• Podemos usar tranquilamente nuestro framework
de pruebas xUnit para testear, no solo los códigos
de respuesta, sino toda la lógica de negocio.
• Las prácticas habituales de testing con este tipo de
herramientas son totalmente válidas para el testeo.
67. Testing con cURL
• Es una alternativa para realizar nuestros tests (cURL
+ Shell Script)
• Con cURL podemos crear exactamente la
transferencia que buscamos.
• Si se tienen suficientes conocimientos sobre cURL se
pueden crear buenos tests con un tiempo de
ejecución bastante bajo.
69. Testing con Guzzle (PHP)
• Guzzle es una librería en PHP que actúa como un
wrapper de cURL, exprimiendo al máximo su
potencia.
• Permite crear clientes REST muy potentes y
escalables
• Es realmente sencillo de utilizar y es orientado a
objetos
• Se integra bien con PHPUnit.
71. Testing con POSTMAN
• POSTMAN es un plugin para Chrome que actúa
como cliente REST
• Nos permite guardar las transferencias
preconfiguradas
• Permite autenticación mediante OAuth de forma
bastante sencilla
• No es una herramienta automática (hay que
ejecutar manualmente cada test y comprobar su
resultado), por lo que no es recomendable testear
sólo con POSTMAN
73. Documentación con
Swagger
• Swagger es un estándar para definición de APIs
REST y un framework que nos permite visualizar su
representación y también consumir el API.
• Es una herramienta muy útil para publicar nuestra
API y que todo el mundo aprenda a usarla
rápidamente.
• Existe un bundle para Symfony2 que implementa
Swagger: NelmioApiDocBundle