GraphQL es una especificaci贸n para la consulta de datos, creado por facebook en el 2012 pero liberado como proyecto open source en el 2015 y que viene a ser una alternativa a las APIs basadas en el modelo Rest.
La idea con GraphQL es que el cliente, ya sea una aplicaci贸n Web, m贸vil o cualquier otro que quiera acceder a nuestros datos, pueda acceder a los datos que realmente necesita usar, para tener consultas m谩s optimas al servidor. Esto se diferencia mucho del modelo Rest donde los recursos a los que voy acceder est谩n definidos por los endpoints que estoy consultando.
Normalmente en Rest tenemos endpoints como el siguiente: GET: /api/v1/posts
Y este endpoint me devuelve un json como el siguiente:
1 2 { 3 "posts": [ 4 { 5 "userId": 1, 6 "id": 1, 7 "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 "body": "quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto" 9 }, 10 { 11 "userId": 1, 12 "id": 2, 13 "title": "qui est esse", 14 "body": "est rerum tempore vitae\\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\\nqui aperiam non debitis possimus qui neque nisi nulla" 15 }, 16 { 17 "userId": 1, 18 "id": 3, 19 "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", 20 "body": "et iusto sed quo iure\\nvoluptatem occaecati omnis eligendi aut ad\\nvoluptatem doloribus vel accusantium quis pariatur\\nmolestiae porro eius odio et labore et velit aut" 21 }, 22 { 23 "userId": 1, 24 "id": 4, 25 "title": "eum et est occaecati", 26 "body": "ullam et saepe reiciendis voluptatem adipisci\\nsit amet autem assumenda provident rerum culpa\\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\\nquis sunt voluptatem rerum illo velit" 27 } 28 ] 29} 30
Siempre que consulte este endpoint voy a conseguir estos datos con esta misma estructura, pero que pasa si de todos estos datos solo necesito el id
y el title
?, en este caso tenemos dos opciones:
- Modificar el endpoint para devolver solo los campos `id` y `title`
- Crear un nuevo endpoint que devuelva estos campos
La desventaja de la primera opci贸n es que puede que existan otros lugares de nuestra aplicaci贸n o otros clientes que si usen los campos body
y userId
por lo que tendr铆amos fallos en esos lugares, y la desventaja con la segunda opci贸n es que a lo largo del tiempo nuestra API tiende a crecer bastante para poder cumplir estas necesidades.
Justamente estos inconvenientes fueron los que llevaron a Facebook a crear GraphQL, en sus aplicaciones m贸viles estaban teniendo problemas con el rendimiento de sus peticiones, y justamente era por que descargaban datos que a la larga no utilizaban, por lo que crearon GraphQL para descargar solo los datos que se requer铆an.
Pero ahora, 驴C贸mo se hace una petici贸n en GraphQL?, la misma petici贸n de arriba lucir铆a de la siguiente manera:
1 2query { 3 posts { 4 userId 5 id 6 title 7 body 8 } 9} 10
Esta consulta nos devolver铆a la misma estructura que tenemos arriba, pero ahora si queremos solo el id
y el title
debemos eliminar userId
y body
de nuestra query.
1 2 query { 3 posts { 4 id 5 title 6 } 7 } 8
Esta query nos devolveria lo siguiente:
1 2 { 3 posts: [ 4 { 5 "id": 1, 6 "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 7 }, 8 { 9 "id": 2, 10 "title": "qui est esse", 11 }, 12 { 13 "id": 3, 14 "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", 15 }, 16 { 17 "id": 4, 18 "title": "eum et est occaecati", 19 } 20 ] 21} 22
Como podemos ver en la respuesta de la petici贸n, ahora solo nos llegan lo que expl铆citamente le indicamos en nuestra query, sin necesidad de crear un nuevo endpoint, el cliente, ya sea una aplicaci贸n web o una aplicaci贸n m贸vil es quien decide que campos quiere recibir.
Para entender un poco mejor como funciona esto debemos revisar algunos conceptos fundamentales de GraphQL.
Tipos personalizados
Los tipos personalizados es la forma que nos provee GraphQL de definir la forma que puede tener nuestros datos, por ejemplo para el caso de los posts el tipo seria as铆:
1 2 type Post { 3 id: Int! 4 userId: Int! 5 title: String! 6 body: String! 7} 8
En este caso he definido el tipo Post
donde en su esquema est谩n los campos que m谩s tarde mi cliente puede consultar.
GraphQL al ser tipado me obliga a decir de que tipo van a ser cada uno de mis campos, en el caso anterior podemos ver Int
y String
, y la lista completa de estos tipos son:
- Int
- String
- Boolean
- ID
- Float
El signo !
representa que el campo que estamos definiendo es obligatorio, es decir que no acepta valores nulos, este signo es opcional, por lo que podemos ponerlo o no dependiendo si queremos que el campo pueda ser nulo o no.
Adem谩s de los tipos anteriormente mencionados dentro de nuestros campos tambi茅n podemos poner otros tipos personalizados, por ejemplo:
1 2 type User { 3 id: Int! 4 name: String! 5 email: String! 6} 7 8type Comment { 9 id: Int! 10 content: String! 11 date: String! 12 author: User! 13} 14 15 type Post { 16 id: Int! 17 userId: Int! 18 title: String! 19 body: String! 20 comments: [Comment]! 21} 22
En el anterior ejemplo a nuestro tipo Post le a帽adimos el campo comments
que nos va a retornar un array con elementos del tipo Comment
, este a su vez va a contener adem谩s de los campos id
, content
y date
, tendr谩 un campo personalizado User
que me va a representar la informaci贸n del usuario que hizo el comentario.
Query
Los Query
es la herramienta que nos provee GraphQL para definir que informaci贸n vamos a exponer a nuestros clientes, se define de la siguiente manera:
1 2 type Query { 3 posts: [Post]! 4} 5
Aqu铆 estamos definiendo un query llamado posts con el cual nuestros usuarios podr谩n conseguir un array de nuestro tipo Post
, para consultar esta informaci贸n bastar铆a hacer la petici贸n anteriormente mostrada:
1 2 query { 3 posts { 4 id 5 title 6 } 7 } 8
A esa petici贸n le podr铆amos a帽adir el body
o el userId
si as铆 lo dese谩ramos, incluso como en nuestro tipo Post
estamos definiendo el campo comments
, lo podemos consultar de la siguiente manera cuando as铆 lo requiramos:
1 2 query { 3 posts { 4 id 5 title 6 comments { 7 id 8 content 9 } 10 } 11 } 12
Esta query nos devolver铆a la siguiente respuesta:
1 2 { 3 "posts": [ 4 { 5 "id": 1, 6 "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 7 "comments": [ 8 { 9 "id": 1, 10 "content": "Muy buen art铆culo" 11 }, 12 { 13 "id": 2, 14 "content": "Muy bien pero solo me queda una duda" 15 }, 16 ] 17 }, 18 { 19 "id": 2, 20 "title": "qui est esse", 21 "comments": [ 22 { 23 "id": 5, 24 "content": "Muy buen art铆culo, espero el pr贸ximo" 25 }, 26 { 27 "id": 6, 28 "content": "No me quedo muy claro" 29 }, 30 ] 31 }, 32 { 33 "id": 3, 34 "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", 35 "comments": [ 36 { 37 "id": 7, 38 "content": "Muy buen art铆culo" 39 }, 40 { 41 "id": 8, 42 "content": "Puede mejorar" 43 }, 44 ] 45 }, 46 { 47 "id": 4, 48 "title": "eum et est occaecati", 49 "comments": [ 50 { 51 "id": 9, 52 "content": "Muy buen art铆culo para empezar" 53 }, 54 { 55 "id": 10, 56 "content": "Excelente!" 57 }, 58 ] 59 } 60 ] 61} 62
Y de ser necesario tambi茅n podemos solicitar la informaci贸n del autor, ya que el tipo comments
incluye este campo
1 2 query { 3 posts { 4 id 5 title 6 comments { 7 id 8 content 9 author { 10 id 11 name 12 email 13 } 14 } 15 } 16 } 17
Como pueden ver la flexibilidad que esto nos provee es bastante grande, solo debemos indicar en nuestra query que campos queremos recibir y nuestro servidor internamente se encargara de enviarnos 煤nicamente esos campos que solicitamos y nada mas, haciendo nuestras peticiones mucho m谩s peque帽as, ya que nunca estaremos cargando campos que no necesitemos.
Ahora, si queremos una query que nos consulte solo un post, podemos agregar esta query a nuestro esquema de la siguiente manera:
1 2 type Query { 3 posts: [Post]! 4 post(id: Int!): Post! 5} 6
Con esto estamos agregando nuestra query post
, donde esta recibe como par谩metro un id
que representara el id del post que queremos conseguir, para ejecutar este query solo debemos hacer lo siguiente:
1 2 query { 3 post(id: 1) { 4 id 5 title 6 } 7 } 8
1 2 { 3 "post": { 4 "id": 1, 5 "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit" 6 } 7} 8
Esta query solo nos devolver谩 el id
y el title
del post que tenga el id 1
, y como post tiene el campo comments
, aqu铆 tambi茅n podr铆amos agregarlo y as铆 conseguir los comentarios del post con el id 1
.
1 2 query { 3 post(id: 1) { 4 id 5 title 6 comments { 7 id 8 content 9 } 10 } 11 } 12
Con esta query conseguir铆amos la siguiente respuesta:
1 2 { 3 "post": { 4 "id": 1, 5 "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 6 "comments": [ 7 { 8 "id": 1, 9 "content": "Muy buen art铆culo" 10 }, 11 { 12 "id": 2, 13 "content": "Muy bien pero solo me queda una duda" 14 }, 15 ] 16 } 17} 18
Mutation
Las Query
si lo comparamos con el modelo de Rest es equivalente a una operaci贸n GET
, es decir es una operaci贸n de lectura de nuestros datos, en cambio las mutaciones en GraphQL nos servir谩n como su nombre lo indica para mutar o modificar nuestra informaci贸n, lo cual seria equivalente a los verbos POST
, PUT
y DELETE
.
Para definir las mutaciones en GraphQl, se hace de la siguiente manera:
1 2 type Message { 3 message: String! 4} 5 6type Mutation { 7 addPost(userId: Int!, title: String!, body: String!): Post 8 deletPost(id: Int!): Message 9 updatePost(title: String!, body: String!): Post 10} 11
En este caso hemos definido tres mutaciones, una para agregar un post, otra para borrar un post y la ultima para actualizarlo.
Entre los par茅ntesis de cada mutaci贸n estamos definiendo los par谩metros que esta necesita, el signo !
como se menciono antes, me indica que es un par谩metro obligatorio y despu茅s de los dos puntos se indica que tipo de valor va a retornar nuestra mutaci贸n, en la mutaci贸n addPost
y updatePost
seria un elemento de tipo Post
y en la mutaci贸n deletPost
seria un objeto del tipo `} Message
que nosotros mismos definimos.
Para hacer uso de estas mutaciones seria de la siguiente manera:
1 2 mutation { 3 addPost(userId: 1, title: "Introducci贸n a GraphQl", body: "Contenido del post") { 4 id 5 title 6 } 7} 8
Esta mutaci贸n nos retornar铆a lo siguiente
1 2 { 3 "addPost" : { 4 "id": 5, 5 "title": "Introducci贸n a GraphQl" 6 } 7} 8
De esta forma podemos hacer uso de nuestra mutaci贸n addPost
y dentro de los corchetes podemos obtener la informaci贸n que queramos sobre el post reci茅n creado, y dado que es un objeto del tipo Post podemos hacer todas sus consultas permitidas.
Ahora usemos nuestra mutaci贸n deletPost
:
1 2 mutation { 3 deletPost(id: 1) { 4 message 5 } 6} 7
La mutaci贸n deletPost
recibe el id del post como su par谩metro y me retorna un objeto del tipo Message
, y as铆 estamos accediendo al campo message
.
1 2 { 3 "message": "Post eliminado con exito" 4} 5
Antes de terminar unas ultimas consideraciones:
- GraphQL es independiente del lenguaje de programaci贸n puede ser implementado en cualquier lenguaje de backend, para mas informaci贸n te invito a ver el siguiente link
- GraphQL es independiente de la base de datos, es decir que podemos usar cualquier fuente de datos al momento de desarrollar nuestra API basada en GraphQL, ya sea una base de datos relacional o no relacional, incluso podriamos consumir estos datos consumiendo otras APIs
Espero que te haya gustado este articulo, en pr贸ximos contenidos estaremos aprendiendo a como crear nuestra propia API con GraphQL y aprenderemos a consumirla desde React, hasta la pr贸xima.