Desplegando una API GraphQL en minutos con Hasura y Docker
GraphQL es un lenguaje de consultas y manipulación de datos de código abierto para datos nuevos o …
leer másEn el capítulo anterior veíamos cómo crear un proyecto con Hasura y Docker en
cuestión de minutos,
con docker-compose up -d
hemos lanzado una API GraphQL lista para utilizar a partir de la configuración del
fichero docker-compose
indicado en
la documentación oficial de Hasura.
Principalmente GraphQL especifica tres clases de operaciones:
Las query (consulta) son la forma más común de interacción con una API GraphQL. Como una consulta de las clásicas bases de datos nos permite obtener información del servidor, en este caso a través de la API previamente expuesta en condiciones de seguridad. Hasura nos permite gestionar roles y permisos para limitar la información que se expone pero eso lo veremos en otro capítulo.
Podemos por ejemplo obtener los id
(ID interno), title
(Título) y created_at
(Fecha de creación) de todas las tareas con la query
:
SOLICITUD
query AllTasksQuery{
task {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 8,
"title": "Limpiar la casa",
"created_at": "2022-11-30T11:20:46.148+00:00"
},
{
"id": 12,
"title": "Crear una lista de tareas",
"created_at": "2022-12-13T00:31:17.686201+00:00"
},
{
"id": 10,
"title": "Escribir un informe",
"created_at": "2022-07-17T00:10:33.29+00:00"
},
...
]
}
}
También podemos establecer un límite de dos tareas con la opción limit
:
SOLICITUD
query AllTasksQuery{
task(limit: 2) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 8,
"title": "Limpiar la casa",
"created_at": "2022-11-30T11:20:46.148+00:00"
},
{
"id": 12,
"title": "Crear una lista de tareas",
"created_at": "2022-12-13T00:31:17.686201+00:00"
}
]
}
}
Nos devuelve las dos primeras tareas de la base de datos, consulta que podemos combinar con una operación de ordenación por fecha.
SOLICITUD
query LimitedTasksQuery{
task(limit: 2, order_by: {created_at: desc}) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 19,
"title": "Comprar polvorones",
"created_at": "2022-12-13T01:29:53.106341+00:00"
},
{
"id": 17,
"title": "Visitar a la familia",
"created_at": "2022-12-13T01:28:04.622421+00:00"
}
]
}
}
El parámetro where
nos permite filtrar los resultados de la consulta, en este caso por ejemplo recibiremos únicamente
aquellas tareas creadas después del 1 de diciembre de 2022:
SOLICITUD
query FilteredTasksQuery{
task(where: {created_at: {_gt: "2022-12-01"}}) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 12,
"title": "Crear una lista de tareas",
"created_at": "2022-12-13T00:31:17.686201+00:00"
},
{
"id": 13,
"title": "Bajar al perro",
"created_at": "2022-12-13T01:13:49.136216+00:00"
},
{
"id": 14,
"title": "Hacer deporte",
"created_at": "2022-12-13T01:16:35.274353+00:00"
},
...
]
}
}
Cada una de las funcionalidades ofrecidas por GraphQL pueden ser combinadas entre sí para ajustar la respuesta del servidor a las necesidades del cliente, en este caso le añadimos una ordenación por fecha de creación ascendente:
SOLICITUD
query FilteredTasksQuery{
task(order_by: {created_at: asc}, where: {created_at: {_gt: "2022-12-01"}}) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 7,
"title": "Planificar una fiesta",
"created_at": "2022-12-03T05:45:22.096+00:00"
},
{
"id": 5,
"title": "Crear un presupuesto",
"created_at": "2022-12-06T10:28:59.551+00:00"
},
{
"id": 1,
"title": "Hacer una lista de la compra",
"created_at": "2022-12-09T01:37:55.790089+00:00"
},
...
]
}
}
Podemos también filtrar variables por texto por ejemplo recogiendo todas las tareas cuyo usuario de creación coincida con un nombre específico:
SOLICITUD
query FilteredTasksQuery{
task(where: {user: {name: {_eq: "Alfred"}}}) {
user {
name
}
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"user": {
"name": "Alfred"
},
"id": 12,
"title": "Crear una lista de tareas",
"created_at": "2022-12-13T00:31:17.686201+00:00"
},
{
"user": {
"name": "Alfred"
},
"id": 7,
"title": "Planificar una fiesta",
"created_at": "2022-12-03T05:45:22.096+00:00"
},
{
"user": {
"name": "Alfred"
},
"id": 5,
"title": "Crear un presupuesto",
"created_at": "2022-12-06T10:28:59.551+00:00"
},
...
]
}
}
Hasta ahora hemos estado introduciendo los datos directamente en la consulta pero también tenemos la posibilidad de utilizar variables en GraphiQL si pulsamos el símbolo del dólar al lado del parámetro en cuestión.
SOLICITUD
query FilteredTasksQuery($userName: String!){
task(where: {user: {name: {_eq: $userName}}}) {
user {
name
}
id
title
created_at
}
}
En el recuadro inferior Query Variables
podemos introducir en formato JSON las variables que vayamos a utilizar en la consulta:
VARIABLES
{
"userName": "Alfred"
}
RESPUESTA
{
"data": {
"task": [
{
"user": {
"name": "Alfred"
},
"id": 12,
"title": "Crear una lista de tareas",
"created_at": "2022-12-13T00:31:17.686201+00:00"
},
{
"user": {
"name": "Alfred"
},
"id": 7,
"title": "Planificar una fiesta",
"created_at": "2022-12-03T05:45:22.096+00:00"
},
{
"user": {
"name": "Alfred"
},
"id": 5,
"title": "Crear un presupuesto",
"created_at": "2022-12-06T10:28:59.551+00:00"
},
...
]
}
}
También podemos obtener todas aquellas tareas que contengan la palabra casa
en su título:
SOLICITUD
query FilteredTasksQuery{
task(where: {title: {_like: "%casa%"}}) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 8,
"title": "Limpiar la casa",
"created_at": "2022-11-30T11:20:46.148+00:00"
}
]
}
}
El offset
nos permite saltarnos un número de resultados, por ejemplo para obtener las tareas empezando a partir de la
tercera nos saltamos las dos primeras:
SOLICITUD
query FilteredTasksQuery{
task(offset: 2) {
id
title
created_at
}
}
RESPUESTA
{
"data": {
"task": [
{
"id": 10,
"title": "Escribir un informe",
"created_at": "2022-07-17T00:10:33.29+00:00"
},
{
"id": 13,
"title": "Bajar al perro",
"created_at": "2022-12-13T01:13:49.136216+00:00"
},
{
"id": 14,
"title": "Hacer deporte",
"created_at": "2022-12-13T01:16:35.274353+00:00"
},
...
]
}
}
En GraphQL una mutation es una operación que permite modificar los datos del servidor. Es similar a una consulta pero en lugar de obtener datos (más allá de los recién creados), realiza una acción que modifica algún aspecto del estado del servidor.
Para agregar un nuevo usuario o una tarea podemos utilizar las siguientes mutation
.
En esta primera llamada añadimos un nuevo usuario introduciendo los parámetros directamente en la consulta:
MODIFICACION
mutation InsertUserMutation {
insert_user(objects: {
uid: "25d4c7b0-1b5a-4b9e-8c5a-2c7f3a7478e9",
username: "monique",
name: "Monique"}) {
affected_rows
returning {
id
name
}
}
}
RESPUESTA
{
"data": {
"insert_user": {
"affected_rows": 1,
"returning": [
{
"id": 10,
"name": "Monique"
}
]
}
}
}
Y esta otra para insertar una nueva tarea utilizando variables. En nuestro ejemplo la clase task_insert_input
es generada por
Hasura automáticamente y define los campos que podemos utilizar para insertar una nueva tarea.
MODIFICACION
mutation InsertTaskMutation($objects: [task_insert_input!] = {}) {
insert_task(objects: $objects) {
affected_rows
returning {
id
title
created_at
}
}
}
Pasándole de nuevo los parámetros mediante variables en formato JSON:
VARIABLES
{
"objects": {
"title": "Escribir un artículo",
"uid": "486a4252-6576-45d3-bc9a-1d6f0388b581",
"user_id": 6
}
}
RESPUESTA
{
"data": {
"insert_task": {
"affected_rows": 1,
"returning": [
{
"id": 21,
"title": "Escribir un artículo",
"created_at": "2022-12-20T22:30:23.434237+00:00"
}
]
}
}
}
En el panel derecho de Hasura llamado Documentation Explorer
encontramos la documentación generada para ver
los campos requeridos por nuestras consultas, por ejemplo la clase task_insert_input
del ejemplo:
Las subscription (subscripción) nos sirven para comunicarnos en tiempo real y de forma bidireccional con el servidor, actualizando la información en los clientes inmediatamente. Utiliza la tecnología WebSockets para mantener un canal abierto y así poder comunicarse sin tener que iniciar de nuevo la conexión.
Su uso excesivo puede llegar a provocar un gran consumo de recursos y dependiendo la casuística del proyecto pueden no ser necesarias o añadir complejidad a la implementación. Siguiendo con el ejemplo, podríamos crear una subscripción para tener la lista de usuarios actualizados en tiempo real:
subscription AllUsersSubscription {
user {
id
name
}
}
También podemos utilizar los filtrados y ordenaciones como en este ejemplo para obtener las tareas de todos los usuarios
con nombre Bob
:
subscription BobTasksSubscription {
task(where: {user: {name: {_eq: "Bob"}}}) {
id
title
created_at
}
}
Para ver los resultados de las subscripciones en vivo te recomiendo el vídeo de un poco más adelante.
Los Fragment no son operaciones como tal pero no está de más mencionarlos ya que suelen acompañar a estas operaciones porque nos permiten reutilizar partes de las consultas y crear una especie de plantillas para no repetir código y simplificar así la organización.
Estas son las operaciones básicas que podemos realizar con GraphQL, para ver los Fragment
, tipos de datos personalizados
y otros detalles todo está definido a la perfección en la especificación oficial.
A mi parecer se trata de un lenguaje con una sintaxis bastante sencilla pero con una flexibilidad a la hora de diseñar y estructurar las consultas espectacular que nos permite crear aplicaciones de una forma rápida y eficiente. Como siempre, todo depende de las necesidades de cada proyecto. Conociéndolo ya sabemos si nos puede ser útil o no y cómo afrontar su implementación.
Quizá te puedan interesar
GraphQL es un lenguaje de consultas y manipulación de datos de código abierto para datos nuevos o …
leer másEn anteriores capítulos hemos visto cómo gestionar una API GraphQl con Hasura. En este capítulo …
leer másYa hemos hablado de Flutter y como ha ganado popularidad como uno de los frameworks más potentes …
leer másDe concepto a realidad