El Protocolo de Comunicación
Existen distintos tipos de APIs que pueden utilizar diferentes protocolos de comunicación. Por ejemplo, el protocolo FTP (File Transfer Protocol) es un protocolo de tipo asíncrono, es decir, la comunicación entre el cliente y el servidor no ocurre en tiempo real por este motivo es un tipo de protocolo que ha sido usado en situaciones en las que no era necesaria una respuesta inmediata. FTP es un protocolo que se usa en ocasiones para servicios web que se ajusten a los siguientes dos requerimientos: una comunicación asíncrona y un volumen importante de información. FTP tiene otra característica que lo hacen muy interesante y es que puede gestionar el intercambio de volúmenes grandes de información de manera muy eficiente.
Pero el protocolo de comunicación más usado en el caso de las APIs es HTTP (HyperText Transfer Protocol), el mismo que usamos diariamente para navegar por internet desde nuestro navegador. HTTP es un protocolo de comunicación basado en el uso de mensajes de texto para gestionar peticiones a un servidor y para las respuestas desde éste. Se trata de un protocolo que es síncrono, es decir, la respuesta a la petición ocurre inmediatamente. Tanto las peticiones (request) o las respuestas (response) siguen un vocabularioy una sintaxix definida. Por ejemplo, las peticiones generalmente están basadas en verbos, que se denominan métodos, como GET o POST.
Este es un ejemplo de la cabecera de una petición de la Home de este blog al servidor, como se puede ver el método que está usando es GET, a continuación tiene el nombre del Host, sencillamente identifica el servidor conectado a Internet en el que se alojan los contenidos del blog. La última parte de la primera línea indica la versión de HTTP que está usando nuestro navegador (el cliente).
GET / HTTP/1.1
Host: errequeerre.es
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Upgrade-Insecure-Requests: 1
Cookie: _ga=GA1.2.628481325.1524899780; …
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15
Accept-Language: es-es
Accept-Encoding: gzip, deflate
Connection: keep-alive
Una vez que hemos enviado una petición a un servidor este nos devolverá una respuesta que vendrá establecida por una codificación de posibles respuestas estandarizadas. Usando las herramientas para desarrolladores que nos ofrece Chrome podemos comprobar el estado de las respuestas a las diferentes peticiones que ocurren al cargar la página de Linkedin.com
En lo que nos interesa fijar la atención en este caso son las primeras columnas. En la primera columna se identifican los recursos que se han solicitado al servidor (Name), la siguiente muestra el código de respuesta del servidor (Status), en este caso la primera línea indica el valor 200 que quiere decir que todo ha ido sobre ruedas. Lo siguiente que vemos es la clase o tipo de recurso (script, gif, png…).
Hay dos elementos que siempre tienen que formar parte de una petición a una API REST, una método y un identificador del recurso al que queremos acceder.
Los Métodos
Los métodos que podemos usar vienen definidos por lo que permite la API en función de lo que han definido los desarrolladores de la misma. Habitualmente usaremos alguno de estos métodos:
- GET: nos sirve para solicitar datos de lectura, es decir, contra este método la respuesta esperable es un objeto de datos. Para este tipo de peticiones podemos obtener un código 200 (todo ha ido bien y se ha encontrado el recurso) o un 404 (algo ha ido mal y no se ha encontrado el recurso).
- POST: se usa para la creación de nuevos recursos en el servidor normalmente subordinados a un recurso ya existente en el servidor. Si todo va bien deberíamos recibir un 201 (tu petición ha sido creada).
- PUT: la usamos para actualizar datos en el servidor, en la petición deberíamos enviar la representación de los datos que queremos modificar en el recurso alojado en el servidor. EL uso de PUT debería restringirse a la actualización completa de un recurso individual mientras que POST se usa para conjuntos de recursos.
- PATCH: Se utiliza para hacer una actualización parcial de un recurso, al contrario que PUT que actualiza el recurso entero. No todas las APIs permiten el uso de este método.
- DELETE: te puedes imaginar que este método sirve para eliminar recursos del servidor.
- OPTIONS: puede resultar tremendamente útil, ya que nos devuelve todas las opciones y requerimientos asociados con un recurso sin que sirva para realizar ninguna acción sobre este.
He mencionado algunas de las respuestas HTTP que podemos recibir a nuestra petición. Pero las opciones son muchas más. Algunas de ellas os sonarán como el famoso 404 que nos encontramos en más de un sitio web al solicitar una página haciendo click en un enlace a un recurso (una página HTML generlamente) que, por algún motivo, ya no está disponible en el servidor o simplemente el identificador de la URL está mal construido y es incorrecto.
Los códigos de respuestas más habituales siguen la siguiente estructura:
2xx – Indican que la petición se ha satisfecho correctamente
Serán habituales el código 200 (todo fue bien y se ha encontrado el recurso y procesado la respuesta), el 201 (todo OK se ha creado el nuevo recurso) o 204 (todo bien pero no se ha devuelto ningún contenido).
3xx- indican que el recurso solicitado está en otra URI diferente
Son comunes la 301 (el recurso se ha cambiado de ubicación definitivamente y nos indica la nueva ubicación), el 302 (el recurso que solicitas se ha movido temporalmente a este otro recurso), aquellos que tengan nociones básicas de SEO estarán familiarizados con estos dos casos.
4xx – indican códigos de error en el lado del cliente
En este caso el uso de 400 nos indica que hay un error en el formato o que es demasiado largo, 401 para decirnos que no tenemos autorización para ese recurso o 403, para indicarnos que el acceso al recurso no está permitido y el servidor ha rechazado nuestra petición. También es relevante el error 405 que nos indica que el método no se admite en la API.
5xx- indican códigos de error en el lado del servidor
En este último grupo están el error 500, cuando ha habido algún error interno del servidor, 502, cuando el servidor hace de Gateway o proxy y ha recibido una respuesta de error a donde quiera que intentase conectarse o el 503 cuando el servicio en el servidor no está accesible, normalmente debido a una sobrecarga o algún problema similar.
No es el objetivo de este post entrar en mayor profundidad sobre este asunto así que si estáis interesados en conocer todos los códigos de respuesta posibles os recomiendo que sigáis el siguiente link a una página de Mozilla que lo explica francamente bien.
La autenticación
Existen una montón de APIs abiertas disponibles en Internet pero la mayoría de las que usaremos en un contexto de negocio estarán protegidas por algún protocolo de autenticación. Por ejemplo, si queremos usar una de las APIs de Google Maps nos vamos a encontrar que podemos hacer una petición de manera abierta pero para hacer más de una al día necesitaremos un token, una clave que nos dar acceso autorizado a hacer muchas más peticiones diarias, aunque seguirá habiendo una limitación.
Si visitas la consola para desarrolladores de Google puedes gestionar tus accesos para el uso de las APIs de los productos de Google
Por ejemplo, el uso estándar de esta API está restringido a 2.500 solicitudes gratuitas diarias, número que supone tanto peticiones como respuestas, o a 50 solicitudes por segundo calculadas de la misma forma. Google, como era de esperar, ofrece un plan premium para mayores volúmenes de peticiones que podéis consultar aquí si tenéis interés.
En el mundo de la autenticación tenemos que hablar de dos conceptos diferentes, por un lado la autenticación en sí, que hace referencia a la capacidad de identificar que uno es quién dice ser, y la autorización, que sirve al propósito de verificar si la persona tiene derechos para acceder a un recurso o no.
Los tres métodos más habituales de autenticación son los siguiente:
Autenticación básica basada en HTTP
En este caso un User Agent HTTP proporciona un usuario y una contraseña para probar que es quién dice ser. Para ello se usa la propia cabecera del HTTP lo que lo convierte en una solución muy sencilla de usar. Aunque este tipo de autenticación usa SSL para incrementar la seguridad lo cierto es que se trata de un sistema que viaja sobre lineas que no son del todo seguras y son susceptibles de sufrir algún tipo de ataque. Además el uso de SSL tiene un efecto colateral no deseable: un mayor tiempo de procesado, lo que denominamos latencia. Este método por sus riesgos se suele usar fundamentalmente en redes internas.
Clave de API (API Keys)
Surgieron precisamente como una alternativa para intentar resolver parte de los problemas de seguridad del método anterior. En este caso se genera una clave única que autoriza a un usuario conocido, es decir debidamente autenticado. En las conexiones que se usen con el servidor se utilizará esta llave para acceder. Por lo tanto la clave de una API es un método de autenticación del usuario. Lo cierto es que no aportan un cambio relevante en el territorio de la seguridad al primer caso.
OAuth
Lo mejor de este sistema es que auna ambas cosas, una solución para la autenticación y a la vez permite gestionar la autorización de acceso. En este caso el usuario se loga en el sistema, a partir de ahí el sistema solicitará la autenticación del usuario, habitualmente en la forma de un token. A partir de ahí el usuario dirigirá su petición a un servidor de autenticación el cual le dará acceso o no en función de los derechos para ese usuario. Se proporciona el token al usuario y luego al que realiza la petición. Ese token puede ser verificado en cualquier momento para hacer una validación del usuario y podrá ser utilizado más de una vez a lo largo del tiempo aunque tendrá una vida útil determinada y un limite en el tiempo. Con el paso del tiempo OAuth se está convirtiendo en el estándar de facto para la autenticación, y el control de acceso, en el mundo de las APIs.
Hay diferentes tipos de Tokens pero el que parece más extendido es el JSON Web Token o JWTs, un tipo de token basado en una estructura de datos en un JSON (JavaScritpt Objetct Notation). El proceso es el siguiente: el usuario se autentica en nuestra aplicación, bien con un par usuario/contraseña, o a través de un tercero (Twitter, Facebook o Google por ejemplo). A partir de entonces, cada petición HTTP que haga el usuario va acompañada de un Token en la cabecera. Este Token no es más que una firma cifrada que permite a nuestro API identificar al usuario. Pero este Token no se almacena en el servidor, si no en el lado del cliente y es el API es el que se encarga de descrifrar ese Token y redirigir el flujo de la aplicación en un sentido u otro.
Las Seis Restricciones de REST
Para que una API se pueda considerar que cumple con los estándares para ser REST debe cumplir las siguientes restricciones:
1. Arquitectura Cliente Servidor
Se asegura de que las tareas estén perfectamente definidas entre el servidor y el cliente, el cliente manejará las correspondientes al interfaz de usuario y el servidor la del almacenamiento y gestión de datos. Gracias a esta arquitectura podemos tener un sistema que es capaz de gestionar clientes diferentes con interfaces distintos sin preocuparse de la presentación al usuario que se gestionará en el cliente (web, apps, mobile…)
2. Sin Estado (Stateless)
El servidor no almacena ningún tipo de información o contexto (lo que se denomina estado) del cliente entre las distintas peticiones. El cliente será el responsable de gestionar el estado de sus sesiones, es decir la información que necesita tener accesible para la sesión. Cualquier petición realizada desde el cliente tendrá que contener toda la información que se necesite para poderla procesar en el servidor. Si el estado de la sesión es relevante para la petición, como por ejemplo las variables para la autenticación de la petición, se tendrá que incluir en la petición al servidor.
3. Cacheable
Cada respuestas a una petición deberá indicar si se puede cachear en el cliente o no y por qué periodo de tiempo. La capacidad de cachear información en el lado del cliente es una parte esencial del rendimiento de la arquitectura.
4. Sistema por Capas (Layered System)
Para el cliente debería ser indiferente si está conectado directamente al servidor o se conectar a través de algún tipo de intermediario como un CDN (Content Delivery Network). Esto es un componente esencial de la capacidad para escarlar la arquitectura.
5. Código bajo Demanda
Los servidores podrán enviar también código que se pueda ejecutar en el cliente en formato JavaScript o en componentes compilados para ampliar y personalizar la funcionalidad. Aunque este es un uso mucho menor en REST deberá estar soportado para que se considera que un servicio es RESTful.
6. Interfaz Uniforme
- Tenemos que usar un identificador del recurso en nuestras peticiones, la URI como hemos visto.
- Una vez que el cliente tiene la representación de un recurso podrá modificarlo o eliminarlo, siempre y cuando cuente con los permisos adecuados para acceder y editar el recurso en el servidor.
- Tanto al enviar una petición como al recibir la representación de un recurso tenemos que indicar cual es el formato que usamos en cada caso. Sin esta información no se puede parsear los datos de manera confiable.
- Tenemos que tener un interfaz uniforme que a través del protocolo HTTP pueda acceder al recurso en el servidor. Esto es una manera bastante retorcida de decir que cuando tenemos acceso a un servicio REST deberíamos ser capaces de describir todos los recursos y métodos disponibles a través de los hiperenlaces que nos proporcione.
Sólo si una API cumple con estas restricciones podemos considerarla una API RESTful. No todas las APIs REST usan el protocolo HTTP pero si todas las APIs RESTful, es decir, el uso de HTTP es una condición para ser una API RESTful.
Un par de ejemplos con la API RESTful de WordPress
Los siguientes ejemplos han sido realizados sobre una extensión de Google Chrome fantástica para testar APIs que se llama Restlet Client – REST API Testing por si os sentís tentados de hacer vuestros propios experimentos en este mundo.
A continuación voy a mostraron una petición a WordPress para este blog usando el método GET y la URI http://errequeerre.es/wp-json/wp/v2/posts a partir de lo cual obtenemos lo siguiente:
En la parte izquierda podemos ver las cabeceras de la petición donde podemos observar que tipo de contenido nos ha devuelto, la representación de los datos del servidor, se han solicitado en JSON y eso es precisamente lo que nos ha devuelto el servidor y que aparece a la derecha en el body.
Los primeros datos corresponden al post con id: 391
con un conjunto de metadatos que incluyen la fecha de publicación, la fecha de modificación, el estado del post (publicado), el tipo de publicación (post), el slug (que es el nombre del recurso) y otros muchos datos. Esta petición nos devuelve todos los posts publicados por este blog desde su creación en formato JSON.
Si queremos ver cuales son los métodos y opciones que nos permite la API de WordPress podemos usar OPTIONS, un método que no todas las APIs nos va a permitir usar
Como podemos ver nos indica que la API a la que estamos accediendo permite dos métodos: GET y POST. A continuación podemos ver los argumentos que podemos utilizar para una petición GET. El primer argumento sería context
que no es obligatorio (de ahí el FALSE
) y que según la descripción “Ámbito de aplicación de la solicitud; determina los campos presentes en la respuesta.Y a continuación nos indica que el tipo de datos es un string
, es decir, una cadena de una serie de caracteres.
Veamos que pasa si usamos algunos de estos argumentos para cambiar nuestra petición. En esta ocasión le vamos a pedir que nos devuelva los post sólo de la primera página (page=1
) y que limite los resultados a un post (per_page=1
) .
La nueva petición tendrá la siguiente estructura http://errequeerre.es/wp-json/wp/v2/posts?page=1&per_page=1
donde los argumentos se incluyen como parámetros en nuestra petición, y el resultado es el siguiente.
En el JSON podemos ver todas la estructura de los atributos de ese primer post de la página 1 del blog en el bloque de la derecha.
Espero que estos ejemplos sirvan para ilustrar algunos casos muy sencillos de cómo podemos interactuar con un servicio web usando la API, en este caso de WordPress, que los desarrolladores han puesto a nuestra disposición. Aunque los ejemplos son sencillos son ilustrativos de cómo es la anatomía de un petición a una API Restful.