Introducción a REST - SymfonyVLC

74
Servicios Web REST Breve introducción a REST

description

Transparencias de la charla sobre introducción a REST en SymfonyVLC el 8/10/2013

Transcript of Introducción a REST - SymfonyVLC

Page 1: Introducción a REST - SymfonyVLC

Servicios Web REST

Breve introducción a REST

Page 2: Introducción a REST - SymfonyVLC

Contenido de la charla• Qué es REST?

o Definición

o Conceptos

o Verbos HTTP

o Códigos de respuesta

o Ejemplos

• APIs CRUDo Operaciones sobre recursos

o Problemas de concurrencia

o Operaciones asíncronas

• Seguridad en REST

• Testing y pruebas

Page 3: Introducción a REST - SymfonyVLC

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.

Page 4: Introducción a REST - SymfonyVLC

Qué es REST?Definición y conceptos

Page 5: Introducción a REST - SymfonyVLC

Qué es REST? Es una tecnología?

Page 6: Introducción a REST - SymfonyVLC

Qué es REST? Es una tecnología? ✗

Es una arquitectura?

Page 7: Introducción a REST - SymfonyVLC

Qué es REST? Es una tecnología? ✗

Es una arquitectura? ✗

Es un “estilo arquitectónico”?

Page 8: Introducción a REST - SymfonyVLC

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.

Page 9: Introducción a REST - SymfonyVLC

Qué significa REST?

REpresentational

State

Transfer

Page 10: Introducción a REST - SymfonyVLC

¿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

Page 11: Introducción a REST - SymfonyVLC

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

Page 12: Introducción a REST - SymfonyVLC

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 UUIDo 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.

Page 13: Introducción a REST - SymfonyVLC

Cómo funciona?• Las operaciones se realizan por transferencia de

estadoo 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 multimediao 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

Page 14: Introducción a REST - SymfonyVLC
Page 15: Introducción a REST - SymfonyVLC

Verbos HTTP• El protocolo HTTP define un conjunto de verbos que nos

permiten realizar todo tipo de operaciones:

o GET (LEER)

o PUT (CREAR O ACTUALIZAR RECURSO COMPLETO)

o POST (CREAR, ACTUALIZAR PARCIALMENTE UN RECURSO)

o PATCH (ACTUALIZAR PARCIALMENTE UN RECURSO)

o DELETE (BORRAR)

o 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/[email protected]/msg04213.html

Page 16: Introducción a REST - SymfonyVLC
Page 17: Introducción a REST - SymfonyVLC

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…

Page 18: Introducción a REST - SymfonyVLC

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 200 (OK)

o 201 (Creado)

o 202 (Aceptado)

o 204 (Sin contenido)

o 304 (No modificado)

o 400 (Petición mal formada)

o 401 (No autorizado)

o 403 (Acceso no permitido)

o 404 (No encontrado)

o 409 (Conflicto)

o 412 (Fallo de pre-condición)

o 500 (Problema de Servidor)

• http://www.restapitutorial.com/httpstatuscodes.html

Page 19: Introducción a REST - SymfonyVLC

VEAMOS EJEMPLOS!

Page 20: Introducción a REST - SymfonyVLC

EjemplosEn nuestra API de pruebas usaremos:

• GETo Obtener recursos o colecciones de recursos

• POSTo Creación de recursos

• PATCHo Actualizaciones parciales

• PUTo Actualizaciones totales de recursos

• DELETEo Eliminar recursos

• OPTIONSo Consultar acciones disponibles

La URL sobre la que trabajaremos será:

http://symfonyvalencia.es/api/usuarios

El servidor puede devolver datos en XML o en JSON

Page 21: Introducción a REST - SymfonyVLC

Transferencia OPTIONSConsultar acciones

Cliente ServidorOPTIONS /api/usuarios/B2K1E3

Host: www.symfonyvalencia.es

HTTP/1.1 200 OK

Allow: GET, PUT, POST, OPTIONS, DELETE, PATC

H

Page 22: Introducción a REST - SymfonyVLC

Transferencia GET Obtener una Colección

Cliente ServidorGET /api/usuarios HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

Page 23: Introducción a REST - SymfonyVLC

Transferencia GET Obtener una Colección

Cliente ServidorGET /api/usuarios HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

[{

“id”: “X1B4Z3”,

“nombre”: “Miguel Ángel”,

“edad”: 27,

“lenguajes”: [“PHP”, “Javascript”]

},

{

“id”: “AB325J”,

“nombre”: “Ángel Miguel”,

“edad”: 26,

“lenguajes”: [“Ruby”, “Java”]

}]

Page 24: Introducción a REST - SymfonyVLC

Transferencia GETObtener un registro

Cliente ServidorGET /api/usuarios/X1B4Z3 HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

Page 25: Introducción a REST - SymfonyVLC

Transferencia GETObtener un registro

Cliente ServidorGET /api/usuarios/X1B4Z3 HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

Etag: W/2cc7-3f3ba34cc25d

{

“id”: “X1B4Z3”,

“nombre”: “Miguel Ángel”,

“edad”: 27,

“lenguajes”: [“PHP”, “Javascript”]

}

Page 26: Introducción a REST - SymfonyVLC

Transferencia POSTCrear un recurso

Cliente ServidorPOST /api/usuarios HTTP/1.1

Host: www.symfonyvalencia.es

Content-Type: application/x-www-

form-urlencoded

Accept: application/json

nombre=Manolo&edad=26&localidad

=Valencia

Page 27: Introducción a REST - SymfonyVLC

Transferencia POSTCrear un recurso

Cliente ServidorPOST /api/usuarios HTTP/1.1

Host: www.symfonyvalencia.es

Content-Type: application/x-www-

form-urlencoded

Accept: application/json

nombre=Manolo&edad=26&localidad

=Valencia

HTTP/1.1 201 Created

Content-Type: application/json

Location: http://symfonyvalencia.es/usuarios/B2

K1E3

Etag: W/2cc7-3f3ba34cc25d

{

”id”: “B2K1E3”

}

Page 28: Introducción a REST - SymfonyVLC

Transferencia PUTActualizar un recurso

Cliente ServidorPUT /api/usuarios/X1B4Z3

Host: www.symfonyvalencia.es

Content-Type: application/json

Accept: application/json

{

“nombre”: “Miguel Ángel”,

“edad”: 27,

“lenguajes”: [„PHP‟, „Javascript‟],

“localidad”: “Valencia”

}

Page 29: Introducción a REST - SymfonyVLC

Transferencia PUTActualizar un recurso

Cliente ServidorPUT /api/usuarios/X1B4Z3

Host: www.symfonyvalencia.es

Content-Type: application/json

Accept: application/json

{

“nombre”: “Miguel Ángel”,

“edad”: 27,

“lenguajes”: [„PHP‟, „Javascript‟],

“localidad”: “Valencia”

}

HTTP/1.1 204 No Content

Content-Type: application/json

Etag: W/2cc7-3f3ba34cc25d

Page 30: Introducción a REST - SymfonyVLC

Transferencia DELETEEliminar un recurso

Cliente ServidorDELETE /api/usuarios/B2K1E3

Host: www.symfonyvalencia.es

HTTP/1.1 204 No Content

Page 31: Introducción a REST - SymfonyVLC

API’S CRUDLas API‟s CRUD son el tipo de API más extendido en el mundo

REST

Page 32: Introducción a REST - SymfonyVLC

APIs CRUD• Son las APIs más habituales

• CRUDo Create (crear)

o Read (leer)

o Update (actualizar)

o 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

Page 33: Introducción a REST - SymfonyVLC

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.

Page 34: Introducción a REST - SymfonyVLC

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

Page 35: Introducción a REST - SymfonyVLC

Ejemplo 1/3

Cliente ServidorGET /api/usuarios/X1B4Z3 HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json;charset=utf-8

Etag: W/689438a788bbc2e

{

“id”: “X1B4Z3”,

“nombre”: “Miguel Ángel”,

“edad”: 27,

“lenguajes”: [“PHP”, “Javascript”]

}

Page 36: Introducción a REST - SymfonyVLC

Ejemplo 2/3

Cliente Servidor (Match OK)PUT /api/usuarios/X1B4Z3 HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

If-Match: W/689438a788bbc2e

Content-Type: application/json

{

“id”: “X1B4Z3”,

“nombre”: “Miguel Ángel Sánchez”,

“edad”: 23,

“lenguajes”: [“PHP”, “Javascript”],

“localidad”: “Valencia”

}

HTTP/1.1 204 No Content

Etag: W/91246ef669ab7

Page 37: Introducción a REST - SymfonyVLC

Ejemplo 3/3

Cliente Servidor (Match KO)PUT /api/usuarios/X1B4Z3 HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

If-Match: W/689438a788bbc2e

Content-Type: application/json

{

“id”: “X1B4Z3”,

“nombre”: “Miguel Ángel Sánchez”,

“edad”: 23,

“lenguajes”: [“PHP”, “Javascript”],

“localidad”: “Valencia”

}

HTTP/1.1 412 Precondition Failed

Etag: W/91246ef669ab7

Page 38: Introducción a REST - SymfonyVLC

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

Page 39: Introducción a REST - SymfonyVLC

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

Page 40: Introducción a REST - SymfonyVLC

Ejemplo de actualización

PATCH /api/usuarios/X1B4Z3 HTTP/1.1Host: www.symfonyvalencia.es

Accept: application/jsonIf-Match: W/979c576c5be5fa5Content-Type: application/usuario-diff+json

[{“tipo-cambio”: “sustituir”,

“campo”: “edad”,“valor”: “23”

},{

“tipo-cambio”: “anadir”,“campo”: “localidad”,

“valor”: “Valencia”}]

Page 41: Introducción a REST - SymfonyVLC

Operaciones de larga duración o asíncronas

Page 42: Introducción a REST - SymfonyVLC

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.

Page 43: Introducción a REST - SymfonyVLC

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

Page 44: Introducción a REST - SymfonyVLC

Ejemplo 1/4

Cliente ServidorPOST /api/pago HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

Content-Type: application/json

{

“metodo”: “visa”,

“numtarjeta”: 1234567812345678,

“cvv”: 123

“caducidad”: “12/17”

“cantidad”: 2500

}

HTTP/1.1 202 Accepted

Location: /api/cola-pago/XBC3719

{

“location”: “/api/cola-pago/XBC3719”,

“estado”: “pendiente”

}

Page 45: Introducción a REST - SymfonyVLC

Ejemplo 2/4

Cliente ServidorGET /api/cola-pago/XBC3719

HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

{

“estado”: “pendiente”

}

Page 46: Introducción a REST - SymfonyVLC

Ejemplo 3/4

Cliente Servidor (Pago OK)GET /api/cola-pago/XBC3719

HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

{

“estado”: “ok”,

“id”: “/api/pago/DEB743AC”

}

Page 47: Introducción a REST - SymfonyVLC

Ejemplo 3 bis/4

Cliente Servidor (Pago OK)GET /api/pago/DEB743AC HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

{

“metodo”: “visa”,

“numtarjeta”: 1234567812345678,

“cvv”: 123

“caducidad”: “12/17”

“cantidad”: 2500

“estado”: “pagado”

}

Page 48: Introducción a REST - SymfonyVLC

Ejemplo 4/4

Cliente Servidor (Error de pago)GET /api/cola-pago/XBC3719

HTTP/1.1

Host: www.symfonyvalencia.es

Accept: application/json

HTTP/1.1 200 OK

Content-Type: application/json

{

“estado”: “error”,

“error”: “sin fondos

}

Page 49: Introducción a REST - SymfonyVLC

Seguridad en RESTNo todas las API‟s son públicas

Page 50: Introducción a REST - SymfonyVLC

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

Page 51: Introducción a REST - SymfonyVLC

1. No uses IDs predecibles

Page 52: Introducción a REST - SymfonyVLC

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

Page 53: Introducción a REST - SymfonyVLC

2. Usa HTTPS

Page 54: Introducción a REST - SymfonyVLC

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

Page 55: Introducción a REST - SymfonyVLC

3. Genera Tokens de seguridad

Page 56: Introducción a REST - SymfonyVLC

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

Page 57: Introducción a REST - SymfonyVLC

4. Usa criptografía hardcore

Page 58: Introducción a REST - SymfonyVLC

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 Tokenen las componentes FIRMA y PARTE_PUBLICA, volver a calcular la firma con la PARTE_PUBLICA recibida y comparar la firma generada con la recibida

Page 59: Introducción a REST - SymfonyVLC

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.

Page 60: Introducción a REST - SymfonyVLC

5. Usa OAuth

Page 61: Introducción a REST - SymfonyVLC

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.

Page 62: Introducción a REST - SymfonyVLC

Testing y pruebas

Asegurándonos de que todo anda bien

Page 63: Introducción a REST - SymfonyVLC

Testing y pruebas

Page 64: Introducción a REST - SymfonyVLC

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 listenersde excepciones y evitan, por ejemplo que una página devuelva un 404, enmascarando el resultado con una respuesta 200.

Page 65: Introducción a REST - SymfonyVLC

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.

Page 66: Introducción a REST - SymfonyVLC

Testing con cURL

Page 67: Introducción a REST - SymfonyVLC

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.

Page 68: Introducción a REST - SymfonyVLC

Testing con Guzzle

… porque cURL no es para todos los públicos

Page 69: Introducción a REST - SymfonyVLC

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.

Page 70: Introducción a REST - SymfonyVLC

Testing con POSTMAN

Page 71: Introducción a REST - SymfonyVLC

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

Page 72: Introducción a REST - SymfonyVLC

Documentación con Swagger

Page 73: Introducción a REST - SymfonyVLC

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

Page 74: Introducción a REST - SymfonyVLC