GraphQL es un lenguaje de consulta de datos para APIs. Funciona como alternativa a las API REST convencionales, pero agiliza el desarrollo y cambios que se realizan en el cliente (frontend) porque nos permite obtener solo los datos necesaria.
Ventajas de GraphQL
Las ventajas más notables de GraphQL son las siguientes:
- Está basado en schemas, lo que te permite describir que esperas recibir como respuesta.
- Resuelve los problemas de Over fetching (obtener data de más) y Under fetching (obtener data de menos y tener que hacer una llamada extra a otro endpoint).
- Nuestro único endpoint será
/graphql
, por lo que no debes preocuparte por hacer un llamado a ninguna otra ruta. - Únicamente usamos el método POST
Este blogpost se centra en como hacer consultas o querys a un recurso, dejaremos para otro momento el hacer mutaciones y suscripciones, que son las formas de cambiar y obtener actualizaciones en tiempo real de la data de GraphQL
Por otro lado, Apollo Client es una librería que te ayudará con el manejo de estado cuando consumas un recurso con GraphQL, facilitándonos el obtener la data y consumirla dentro de nuestra aplicación. Solo basta con instalar la librería @apollo/client
para adquirir todo el set de herramientas que nos facilita.
Creando nuestra aplicación
Vamos a crear una aplicación consumiendo la API de SpaceX con GraphQL y el set de herramientas que provee Apollo client
Setup
El setup para crear un pequeño proyecto usando GraphQL será el siguiente:
- Inicializar un proyecto con React desde 0 con webpack o hacerlo con
npx create-react-app [appName]
- Instalar
graphql
y@apollo/client
con NPM o yarn
npm install --save graphql @apollo/client
- Instanciar ApolloClient dentro de
index.js
y envolver nuestra aplicación con él de la siguiente forma:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
// Hasta aquí tienes la estructura básica de tu archivo index.js
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
gql,
} from "@apollo/client";
// Apollo client provee estas y otras herramientas, como te comenté antes
// Más abajo conocerás para que sirve cada una
const myClient = new ApolloClient({
uri: "https://api.spacex.land/graphql",
// La uri será el único lugar al cual harás consultas, ahí estará almacenada toda nuestra data
cache: new InMemoryCache(),
// InMemoryCache guarda la información ya consultada para evitar el pedir la misma dos o más veces
});
ReactDOM.render(
// ApolloProvider permite a toda la App hacer consultas desde cualquier lugar
// Algo parecido a lo que se haría con Context.Provider
<ApolloProvider client={myClient}>
<App />
</ApolloProvider>,
document.getElementById("root")
);
Crea tu componente base para consumir la data
Este será un componente como cualquier otro que harías con React, los parámetros que recibe se renderizarán para ser mostrados en pantalla, por lo que esto lo puedes customizar como mejor te parezca.
Te dejo aquí abajo el como yo lo hice, los estilos los encontrarás en el Repositorio
// LaunchCard.js
import React from "react";
import "./css/launch-card.css";
export const LaunchCard = ({
links,
id,
details,
launch_success,
mission_name,
launch_site,
launch_year,
rocket,
}) => {
return (
<div className="launch">
<div className="launch--info">
<div className="launch--header">
<div className="launch--id">
<span>{id}</span>
</div>
<img src={links.flickr_images[0]} alt={rocket.rocket_name} />
{/* Esta es una pequeña validación para mostrar el mensaje de success o failed
según el valor de launch_success */}
{launch_success ? (
<div className="launch--status launch-success">
<span>Success</span>
</div>
) : (
<div className="launch--status launch-failed">
<span>Failed</span>
</div>
)}
</div>
<div className="launch--body">
<div className="launch--title">
<h2>{mission_name}</h2>
</div>
<p>Ubication: {launch_site.site_name_long}</p>
<p>Year: {launch_year}</p>
</div>
<div className="launch--footer">
<h3>{rocket.rocket_name}</h3>
<span>{rocket.rocket_type}</span>
</div>
</div>
<div className="launch--description">
<div className="launch--details">
<p>{details}</p>
</div>
<a href={links.article_link} target="__blank">
See article
</a>
<a href={links.video_link} target="__blank">
See video
</a>
</div>
</div>
);
};
Haz los llamados a la API con graphQL
Llegó el momento de ver de manera práctica el como funciona este lenguaje de consulta.
Esto lo puedes hacer dentro del mismo componente que consume la data, pero, en este caso en particular, lo que se espera recibir es un array y renderizar el componente anterior por cada item del array.
El componente contenedor lo llamaremos LaunchesDetailed.js
(Puedes poner cualquier otro nombre sin problema) y su estructura será la siguiente:
Puedes probar hacer las query antes de ponerlas en tu código desde el GraphiQL
// LaunchesDetailed.js
import React from 'react'
import { gql, useQuery } from '@apollo/client'
// gql nos permite escribir una consulta de GraphQL desde JavaScript plano
// Las consultas que hagas a GraphQL tienen que poseer la keyword "query"
// Otra facilidad de algunos recursos es que permite definir un límite para no recibir data en exceso
const LAUNCHES_INFO = gql`
query getLaunches {
launches(limit: 10) {
id
mission_name
launch_success
details
launch_year
launch_site {
site_name_long
}
links {
flickr_images
article_link
video_link
}
rocket {
rocket_name
rocket_type
}
}
}
`
// Puedes consumir más o menos data de esta, en el recurso de arriba está todo con más detalle
export const LaunchesDetailed = () => {
// useQuery es el hook que nos permite hacer la consulta de forma sencilla
// Nos facilita el crear una vista en los siguientes casos
// 1. Tener la data completa
// 2. Estar obteniendo la data
// 3. Obtener un error en lugar de la data
const { data, loading, error } = useQuery(LAUNCHES_INFO)
// En cada caso es necesario mostrar un componente en pantalla o puedes tener errores
// Esto ayuda a mejorar tu UI usando Loaders con CSS o mostrar pantallas de errores
// más descriptivos
if(loading) return <p>Loading... </p>
if(error) return <h2>Error</h2>
// En el caso de tener la data no es necesario el poner un condicional, ya que se da por
// hecho que se tiene sin ningún problema
return(
<div className="launches">
{data.launches.map((item) => (
// Puedes hacer object destructuring, debido a que en el componente tienes
// los parámetros con los nombres igual que en GraphQL
<LaunchCard key={item.mission_name} {...item} />
))}
<div>
)
}
Une todos tus componentes
Al final, tu componente App.js
deberá quedarte muy limpio solo con los componentes que has creado importados en él, en mi caso, este fue el resultado final y tu aplicación deberá mostrarse sin ningún error en pantalla
import { LaunchesDetailed } from "./components/LaunchesDetailed";
function App() {
return (
<div className="App">
<h1 className="title">SpaceX launches</h1>
<LaunchesDetailed />
</div>
);
}
export default App;

Visita la demo live aquí
Los estilos no son lo mejor pero se que lo harás mejor que yo 😉
Ya aprendiste una nueva forma de consumir recursos que no es con una API REST y sin tener que preocuparte por las promesas o por poner un solo fetch
Esto es un poco del gran potencial que tiene GraphQL. Esta vez solo lo consumimos, pero aún tiene un par de funcionalidades y herramientas más. Te sugiero ver esta serie de cursos para que tengas un dominio completo sobre este lenguaje de consultas y puedas combinarlo como todo un experto o experta en React.
#NuncaParesDeAprender
Curso de Next.js con GraphQL