loading...
Cover image for Fundamentos de GraphQL

Fundamentos de GraphQL

gugadev profile image Gus Garzaki ・5 min read

No he visto mucho material de GraphQL en Español, así que, aprovechando que tengo un poco de tiempo libre, he preparado esta pequeña introducción a esta genial tecnología.

Descripción oficial de GraphQL:

🗒 GraphQL es un lenguaje de consultas para APIs y un entorno server-side para ejecutar consultas usando un sistema de tipos definido por ti en tus datos. GraphQL no está ligado a ninguna base de datos o motor de almacenamiento, en su lugar, está respaldado por tu código existente y tus datos.

Entendemos por GraphQL como un lenguaje de consultas, el cual usa un sistema de tipos previamente definido por nosotros. ¿Por qué entonces, es tan importante GraphQL?

Veamos el siguiente escenario para poder comprender mejor el funcionamiento de GraphQL. Supongamos que tenemos el siguiente endpoint:

  • /api/v1/project/:id

El cual nos trae un proyecto de la base de datos por medio de su id. Cada Project mantiene una dependencia con Manager. Nuestro endpoint nos traerá algo así:

{
  "projectId": "83ngrgn48t5rdg4tedgasdgasg",
  "name": "Bot integration for Messenger",
  "manager": {
    "managerId": "734gnrfgnfngvffasdgfasdngf",
    "firstname": "John",
    "lastname": "Doe",
    "area": "TI"
  }
}

Bien, hasta aquí perfecto, tenemos nuestro proyecto junto con su manager. Pero, digamos que a mi no me interesa los datos del proyecto ni del manager, solo me interesa saber a que área pertenece el manager de dicho proyecto. ¿Cómo lo haces?

La manera tradicional es haciendo un filtrado de datos:

const managerArea = project.manager.area

Ya lo tengo, simple. ¿Cuál es el chiste con GraphQL entonces? 🙄 Tranquilo, no te emociones. Te pregunto algo: ¿Es esto eficiente?

Digamos que Manager tiene una dependencia Area y Area otra dependencia con Organizatinn y así sucesivamente hasta tener una cantidad considerable de documentos anidados. ¿Crees que sería eficiente obtener todos estos documentos para obtener solo uno o dos datos?

GraphQL viene a solucionar este problema de una manera limpia y eficiente. Lo anterior, usando GraphQL quedaría de la siguiente manera:

query {
  getProject(id: "83ngrgn48t5rdg4tedgasdgasg") {
    manager {
      area {
        name
      }
    }
  }
}

Donde obtendríamos como respuesta:

{
  data: {
    getProject: "TI"
  }
}

Ahora nuestra solución es mucho más limpia y sobre todo, liviana, optimizando los recursos de red del usuario, sobre todo en dispositivos móviles. No te preocupes si no entiendes aún cómo funciona, lo veremos progresivamente en este tutorial.

Types

Ya vi cómo se usa, pero, ¿Cómo sabe GraphQL que datos debe seleccionar de la base de datos? 🤔

GraphQL no selecciona nada de la base de datos; lo que hace es hacer un mapeo de entidades a lo que se conoce como types. Un tipo es una representación de algún objeto o suceso dentro de nuestra aplicación. Por ejemplo, si tenemos un modelo User con la siguiente definición:

@Entity()
class User {
  @PrimaryGeneratedColumn()
  id: int
  @Column()
  name: string
  @Column()
  email: string
}

La definición anterior corresponde a Typescript usando el ORM TypeORM

Podemos mapear nuestro tipo User de la siguiente manera:

type User {
  id: Int
  name: String
  email: String
}

De manera que GraphQL ahora sabe qué propiedades de la entidad coger 😉. Puedes ver los tipos de datos de GraphQL aquí.

Queries

Vale, hasta aquí entiendo bien. Pero, ¿Cómo puedo obtener una respuesta de GraphQL? No entiendo esa parte 🤔. Calma, vamos a ver ello.

Para que GraphQL responda, necesitamos hacerle una consulta. Para que GraphQL sepa las consultas que tiene disponibles, necesitamos primero definir su estructura. Esto se hace así:

Query {
  user(id: Int!): User
}

Es súper sencillo: solo definimos el nombre, los argumentos que recibirá y el tipo de dato que retornará. Si prestamos atención es similar una definición de una función. Así mismo, para ejecutar esa consulta, es similar a la ejecución de una función:

{
  user(id: 4575) {
    name,
    email
  }
}

Dado que el tipo de retorno es de tipo User podemos decidir que tipos de datos queremos obtener. En este caso, solo necesitamos name y email.

Mutation

Un Mutation es muy similar a una Query, de hecho son prácticamente lo mismo. La diferencia radica en la naturaleza de su uso: Query está destinado a lectura de datos mientras que Mutation a escritura. Hay algunas diferencias a nivel técnico, pero nada que impacte a nivel de desarrollo.

Al igual que las Query, las mutaciones se definen:

type Mutation {
  createUser(name: String!, email: String!) : User
}

Y se ejecutan de la misma forma; pudiendo también obtener los campos que necesitemos.

{
  createUser(name: "Gustavo", email: "gusgarzaki@gmail.com") {
    id # solo queremos el id
  }
}

Input

Algunas veces necesitamos enviar un conjunto de valores como un solo parámetro sin necesidad definir cada propiedad como argumento. Para este propósito existen los input types.

input UserInput {
  firstName: String
  lastName: String
  cardId: Int
  email: String
}

type Mutation {
  createUser(data: UserInput!): User
}

Y de esta manera podemos pasarle un objeto con esas propiedades:

{
  firstName: "Gustavo",
  lastName: "Garzaki",
  cardId: 35551232,
  email: "gusgarzaki@gmail.com"
}

Fragment

Ahora que sabemos qué es un Type, un Query y un Mutation y para qué se usan, vamos a ver una estructura utilitaria. Un Fragment te permite definir un conjunto de campos y luego incluirlos en las consultas. Por ejemplo:

type User {
  id: Int
  firstName: String
  lastName: String
  cardId: Int
  address: String
  email: String
  phone: String
}

fragment PersonalData on User {
  firstName
  lastName
  cardId
  address
}

Y podemos reusar ese fragmento en cualquier consulta:

{
  findUser(id: 1099) {
    ...PersonalData
  }
}

Variables

Tan simples pero a la vez tan esenciales. ¡No podían faltar! En GraphQL, podemos realizar consultas dinámicas a través de variables. Veamos un ejemplo:

query FindUser($id: Int!) {
  user(id: $id) {
    ...PersonalData # hacemos uso de un fragmento para reforzar 😁
  }
}

De esta manera podemos tener un catálogo de queries a las cuales solo les pasamos variables en lugar de tener que escribir las consultas cada vez que vamos a realizarlas.

 Directives

Hemos visto como las variables nos ayudan a reutilizar consultas. Incluso esto no puede ser suficiente en algunos casos; quizás queramos incluir o excluir cierta información de forma dinámica de acuerdo a algún indicador. Para esto existen las directivas, que, por medio de una variable, nos permiten incluir o excluir ciertos campos. Veamos un ejemplo.

query FindUser($id: Int!, $onlyPersonalData: Boolean! = false) {
  user(id: $id) {
    ...PersonalData
    email @skip(if: $onlyPersonalData)
    phone @skip(if: $onlyPersonalData)
  }
}

Las directivas nos permiten obtener o evitar campos de manera dinámica. En el ejemplo anterior, definimos dos variables: $id que representa el id del usuario y $onlyPersonalData que indica si queremos incluir solo los datos personales, de esta manera, el resultado variará de acuerdo a si pasas true o false.

💡 GraphQL nos da dos directivas:

  • @include(if: Boolean), para incluir datos en el resultado solo si el argumento es true.
  • @skip(if: Boolean), para excluir datos en el resultado solo si el argumento es true.

Conclusión

Como puedes ver, GraphQL es radicalmente diferente a las APIs convencionales basadas en REST o SOAP; este tiene su propio lenguaje y te permite obtener datos precisos de forma eficiente gracias a su tremenda flexibilidad.

Recuerda que si bien la arquitectura GraphQL no es un reemplazo de las APIs convencionales, todo depende de tus necesidades. 😉

Posted on by:

gugadev profile

Gus Garzaki

@gugadev

Developer. Researcher. Student.

Discussion

markdown guide