
La expansión en el desarrollo de API’s ha provocado que los modos de implementación y exposición de los recursos de cara al cliente final se hayan diversificado.
Actualmente, REST es la principal arquitectura utilizada para ofrecer un servicio mediante un API. La arquitectura REST define una serie principios y restricciones a la hora de desarrollar un API. Los desarrolladores tienen cierta libertad a la hora de implementar un API siempre que se ajusten a esos principios y restricciones. Esto provoca que cada API REST, según el equipo de desarrollo, pueda tener diferencias respecto a otros en los siguientes aspectos:
- cómo ofrece los recursos según la semántica
- cómo ejecuta procesamiento en el servidor al recibir peticiones del cliente
- cómo deben formarse las peticiones por parte del cliente
- cómo responde el servidor las peticiones del cliente
- etc
Estas diferencias provocan que sea complicado crear una especie de plantilla de cliente para acceder a los recursos de API’s diferentes.
A la hora de componer una petición al servidor, el cliente debe adaptarla a la representación de los recursos en el lado del servidor y la semántica utilizada para acceder a esos recursos.
La respuesta del API devuelve datos que pueden ser incompletos para nuestras necesidades, como por ejemplo las relaciones de un recurso con otras entidades del dominio. En estos casos, es necesario realizar múltiples peticiones al API para completar toda la información necesaria que sería deseable obtener en una sola petición.
GraphQL es un lenguaje para ejecutar queries en un servidor API mediante el cual se provee al cliente de una descripción detallada de las estructuras de datos que ofrece.
Este lenguaje fue creado por Facebook en 2012 y cuya estandarización se comenzó a desarrollar en 2015, por lo que es un lenguaje en continuo desarrollo.
Las principales características y funcionalidades que ofrece GraphQL son las siguientes:
- Describe la estructura/organización de los datos ofrecidos por el API mediante un sistema de fuerte tipado en el que se detallan los recursos y las relaciones existentes entre estos.
- Permite solicitar al servidor tan sólo la información que necesitamos de un recurso en una sola petición incluyendo los datos de otros recursos que se relacionen con el recurso raíz.
- Ofrece una única URI en la que se realizan todas las peticiones, por lo que no debemos preocuparnos de la semántica implementada por cada API.
- Es un lenguaje independiente de la fuente de datos. Los datos pueden obtenerse de un servicio web, una base de datos, un fichero, etc.
- Permite la evolución de un API sin crear nuevas versiones
- Existen múltiples librerías para implementar en distintos lenguajes (JavaScript, Go, Ruby, Java …)
Vistazo rápido a GraphQL
Una vez conocemos las principales características de GraphQL, explicaremos de forma breve las principales características técnicas de este lenguaje que nos servirán para integrarlo con nuestro API o nuestros servicios.
GraphQL es un lenguaje que permite la obtención de los campos necesarios de un objeto. El modelo de datos de un API se define en GraphQL mediante un Schema, que contendrá:;
- una serie de Types, que representan los objetos;
- y una serie de operaciones
- Queries, para obtener datos (petición GET en REST)
- Mutations, para realizar modificaciones en el servidor (PUT/POST/DELETE en REST).
Type es la representación de un objeto mediante la cual definimos los fields o campos/atributos que lo componen. GraphQL aporta una serie de tipos escalares o ‘primitivos’ como son Int, Float, String, Boolean, ID y Enum.
Como se ha comentado en el párrafo anterior, debemos definir la estructura de datos de nuestro modelo creando los tipos necesarios y sus relaciones. De este modo, un tipo puede contener la referencia a otro tipo generado por nosotros.
El siguiente código muestra cómo se definirían los tipos para el modelo que desarrollaremos más tarde, basado en StarWars. Definimos los tipos Planet y People y la relación que existe entre ellos:
type Planet{ id: ID name: String terrain: String } type People{ id: ID name: String age: Int homeworld: Planet }
Una Query es un tipo especial dentro del esquema de GraphQL. Al igual que cualquier otro tipo, definirá fields que en este caso serán los puntos de entrada para cada una de las consultas que definamos.
De este modo, dentro del tipo Query definiríamos un field con nombre character en el que indicamos que devolverá un tipo People. Para consultar un tipo People comenzaríamos la query (veremos más tarde como realizar las consultas con la sintaxis de GraphQL) referenciando al field character y dentro de ese field, los datos que queremos del tipo People.
En un tipo Query podemos definir argumentos de entrada para, por ejemplo, filtrar una búsqueda.
Con el siguiente código definiríamos la consulta de un tipo People informando su ID, por el que se filtrará:
type QueryDef { character(characterId: ID): People } schema { query: QueryDef }
Para ejecutar esta query tan solo ejecutaríamos el siguiente código:
query{ character(characterId: 1){ name age homeworld { name } } }
que devolvería los atributos name y age del personaje y, en la misma petición, devolvería el nombre del planeta con el que el personaje se relaciona.
Aquí reside una de las principales ventajas sobre la arquitectura REST, en la que normalmente recibiríamos un identificador de planeta o una URI y deberíamos formar una nueva petición al API para obtener la información del planeta con el que se relaciona el personaje.
Un Mutation se comporta de igual manera que un tipo Query pero se utiliza para realizar un procesamiento en el servidor. En muchos casos necesitaremos enviar datos al servidor, para lo cual habrá que definir un tipo Input.
Estos tres elementos que hemos visto son los pilares sobre los que pivota GraphQL. Evidentemente hay muchas características que escapan del alcance de este artículo y que pueden consultarse en la documentación de GraphQL.
En el siguiente artículo desarrollaremos la implementación de un API con GraphQL.