¡No te pierdas ninguna publicación! Suscríbete a The Softtek Blog
Tras bastantes años investigando, publicando, consumiendo e, incluso, dando formación o impartiendo webinars sobre ello, sigo recibiendo preguntas o leyendo cosas en foros que me dejan ojiplática y que me dan muchas ganas de publicar un post como éste. Incluso, hay quien dice que su API es RESTful y luego lo escribe así: RESTfull... por lo que empecemos por el principio.
En 2011 ya usaba Servlets Java que recibían JSON. Luego conocí los controladores en Spring y, más tarde, los controladores REST con SpringBoot. Está claro que la evolución Web va en esa dirección, en busca del consumo de APIs ligeras y el desacoplamiento con las capas cliente.
Pero no queremos saber cómo funciona a bajo nivel
Aún con las “ayudas” de los frameworks, y pongo “ayudas” entre comillas porque muchas veces lo que consiguen es que no sepamos, si no queremos, lo que hay por detrás (como un protocolo HTTP estupendo), seguimos haciendo APIs poco amigables y RESTless, sin utilizar los estándares que se van haciendo innegablemente necesarios cuando el número de este tipo de servicios, y de sus consumidores, va en aumento casi a diario.
Tampoco hay nada que nos obligue a hacerlo de una manera concreta, lo cual tiene su parte buena: es totalmente flexible; y su parte mala: porque cada uno lo hace como quiere
Si el código compila y no hay nada ni nadie que nos impida hacer un servicio a nuestro libre albedrío, podría tomar como normal que, al principio de su uso, cada uno lo hagamos a nuestra manera. Pero ya no es el caso, ahora tenemos mucha más experiencia como consumidor y/o publicador como para darnos cuenta de lo que aporta un API bien hecha, tanto como cliente a la hora de integrarla como para poder mantenerla y extenderla.
Y para más inri, existiendo documentación extensa de cómo funciona el protocolo en el que basa.
Hoy ya no es ayer, el mundo web es nuestro
Antes (y me siento viejuna), los servicios se hacían para un cliente concreto, que normalmente se solía implementar por gente cercana... o hacíamos servicios que tenían que tener tal interfaz para cumplir lo que el cliente ya estaba consumiendo y reducir el impacto. A día de hoy, las APIs se implementan por un lado y tenemos clientes desperdigados por el mundo que las consumen. Hay que cambiar el chip y ser consciente de que el mundo web es para todos, fomentando estar conectados. ¿No creéis que tiene sentido facilitarlo de alguna forma?
Por todo eso y porque me duele ver, a día de hoy, una nueva API hecha sin cariño, os quiero mostrar una forma de diseñar APIs RESTful (o pragmatic, al menos) y, lo más importante, todos los motivos que me llevan a hacerlo de esa manera y no de otra.
Como ya mencionaba, trabajamos con Internet que se basa en el protocolo HTTP. Aunque me digáis que soy una friki, es muuuy importante conocer con lo que tratamos día a día, por lo que os dejo un link a las especificaciones que se definieron en el RFC de HTTP 1/1 que tanto usamos (https://tools.ietf.org/html/rfc2616). Os animo a echarle un ojo y a que me digáis si no os asombra que conteste muchas de las preguntas que nos seguimos haciendo cuando estamos diseñando un API, incluso indicando cómo DEBE utilizarse concretamente, no de forma abstracta.
Por ejemplo, vemos párrafos como el siguiente hablando de los métodos HTTP, donde nos dicen claramente para lo que sirven (operación a realizar sobre el recurso identificado en la URI) y cómo hay que indicar al cliente (en cuanto a métodos disponibles) los diferentes casos que se pueden dar:
Solamente es un ejemplo de todo lo que ya se ha pensado y documentado. ¿Por qué inventar o hacerlo como nos parece? ¿Por qué no partimos de una base de la gente que ha creado nuestra herramienta de comunicación? ¿Por qué acabamos conociendo bien el API de Java o de .NET, pero no esto? No sé si por desconocimiento, desgana, ayudas que te alejan de lo que haces o poco cariño diseñando... sólo espero que sirva como reflexión y entendáis la importancia que veo en seguir unas pautas que, curiosamente, ya existen, pero que nadie te obliga forzosamente a seguir.
Siendo diseñador de APIs puedo tomar esta documentación como referencia a la hora de implementarlas; y como cliente consumidor, ¡¡también!!. Es algo más ágil y estándar que tener que ir a preguntar al que ha hecho el API, ¿verdad?
Quizá me he puesto un poco tostón con el RFC, así que voy a intentar aligerarlo resumiendo unos conceptos básicos para esta primera entrega, pero muuuy a tener en cuenta en todo momento:
Orientado a recursos
Recurso: cuando diseñamos APIs, tenemos que orientarlas a recursos. Es decir, dejemos de pensar en las entidades que tenemos en base de datos y pensemos en entidades con funcionalidad por sí mismas de cara a un usuario, pensemos en recursos.
Antes hacíamos CRUD de tablas de bbdd, ahora hacemos CRUD de Recursos (que normalmente tienen datos de varias tablas de nuestro modelo de entidades).
Con esta forma de pensamiento, surge la necesidad de tener subrecursos. Por ejemplo, un contacto no tiene funcionalidad por sí mismo si no hay un usuario asociado; o un movimiento entre cuentas no puede existir sin una cuenta origen, que no puede existir a su vez sin un cliente y/o contrato. De esta forma podemos ir diseñando los recursos y subrecursos que necesitaremos exponer en nuestra happyAPI y, por tanto, las URIs.
URIs amigables y entendibles
URI: Universal Resource Interface; o, lo que es lo mismo, endpoint o URL relativa con la que acceder a cada recurso. Y sabiendo ya que hablamos de recursos y subrecursos, podríamos tener algunas URIs como las siguientes:
/customers/
/customers/1/accounts/2/movements
/users/
/users/225369/contacts
Así, sin explicar nada, ¿sabríais interpretar qué representa cada una? Probablemente sí... vosotros y cualquiera que necesite consumir nuestra API.
Es cierto que la decisión de qué es subrecurso o cómo acceder a él muchas veces genera discusión, o la forma de facilitar el acceso a los datos para no tener una URI que sobrepase los límites de 255 caracteres. Por ejemplo, igual preferimos recuperar todos los contactos de cualquier usuario (raro, pero es nuestra API y exponemos la funcionalidad que creemos necesaria), con lo que tendríamos:
/contacts
En la respuesta, para cada contacto, se debería linkar con el usuario propietario para que el API sea útil, pero así podríamos acceder directamente a toda la lista de contactos existentes.
NOTA: Como veis, no siempre es sencillo tomar determinadas decisiones, ¡todo compila!. Pero, desde mi experiencia, a no ser que tengamos una jerarquía infernal de recursos, lo suyo es anidarlos para acceder desde los recursos principales a los diferentes subrecursos, de forma que sea mucho más amigable y entendible simplemente viendo la URI que lo referencia.
Así también podremos utilizar mecanismos como el “expand”, que sirve para indicar si queremos que en la respuesta nos devuelva toda la información de determinados subrecursos o solamente la URI relacionada para obtenerlos en otra petición.
Uso correcto de métodos HTTP
Método HTTP: otra parte importante de un API es la definición de los métodos HTTP para consumirla. He visto cosas que no creeríais...
En la imágen del RFC se ven algunos de los métodos más utilizados. Los más importantes y que nos deben sonar bastante son POST, GET, PUT, PATCH y DELETE.
Cada uno, además, podemos asociarlo fácilmente con una acción de los típicos CRUD de recursos (Create, Read, Update, Delete), respectivamente.
Peeeero cierto es que todo compila y que aunque se llame con un POST, puede que, en la implementación del API, estemos borrando el recurso.
Como todo, necesitamos aplicar sentido común, y en este caso es sencillo implementar nuestra API como manda el paradigma RESTful:
POST | Crear recurso |
PUT | Actualizar recurso completo |
PATCH | Actualizar parte del recurso |
GET | Recuperar uno o varios recursos |
DELETE | Eliminar recurso |
Uso correcto de códigos HTTP
Código HTTP: igual de importante es usar el método HTTP que indica el protocolo, como sus códigos. Tenemos muchos disponibles, y cada uno con su significado concreto, ¡¡usémoslos!!
Los códigos están agrupados en cinco bien diferenciados, según su sentido:
Además de tener dichos grupos genéricos, también definieron códigos concretos (con su documentación en diferentes secciones), como por ejemplo:
Con estos conceptos claros, ya tendríamos lo mínimo para poder crear una interfaz de API REST siguiendo el paradigma RESTful.
De momento, nos sirve para ir viendo por dónde van a ir los tiros... ¡espero que sirva para la reflexión y que no os perdáis las siguientes entregas!