Apollo es un conjunto de herramientas que permiten crear servidores GraphQL y también consumir APIs GraphQL. En este tutorial vamos a ver en detalle qué son y cómo se utilizan tanto Apollo Client como Apollo Server. Crearemos un pequeño proyecto de modo que, cuando termines este tutorial, puedas comenzar a utilizarlo con tus proyectos.
Para seguir este tutorial necesitarás ciertos conocimientos acerca de la línea de comandos. Si no los tienes, consulta primero el tutorial de introducción a la línea de comandos. También necesitarás tener instalado tanto Node.js como el gestor de paquetes npm. Si no tienes estas herramientas instaladas, consulta el tutorial de instalación y configuración de Node.js y npm. También estaría bien que echases un vistazo al tutorial de introducción a GraphQL.
Contenidos
- 1 Introducción a Apollo
- 2 El cliente de Apollo (Apollo Client)
- 2.1 Creando y configurando la aplicación
- 2.2 Configuración con Apollo Boost
- 2.3 Instancia del Cliente de Apollo
- 2.4 Conexión o link con el servidor
- 2.5 Configuración del sistema de caché
- 2.6 Configuración de ApolloProvider
- 2.7 Estructura de las consultas GraphQL
- 2.8 Obteniendo el token de acceso
- 2.9 Autenticación con el link de Apollo
- 2.10 Creación de una consulta GraphQL
- 2.11 Mostrando los resultados de una consulta
- 3 El servidor de Apollo (Apollo Server)
- 4 Sandbox de Apollo
Introducción a Apollo
Durante los últimos años se ha extendido bastante el uso de GraphQL a la hora de crear un API frente a la arquitectura REST tradicional. Mediante los grafos GraphQL se da la libertad al cliente de que decida aquellos datos que se deben obtener, de modo que no existen una serie de endpoints fijos.
Esto dota al sistema de una gran flexibilidad a la hora de obtener los datos, ya que también podrás obtener datos o recursos anidados, reduciendo considerablemente la cantidad de código que necesitarás en tu servidor, siendo también menor la posibilidad de que necesitemos crear peticiones adicionales a nuestra API, algo habitual cuando usamos la arquitectura REST con microservicios.
Lo cierto es que GraphQL no se adaptaría demasiado bien a la arquitectura basada en microservicios como concepto, siendo aquí donde entra en juego Apollo, que simplifica el desarrollo de aplicaciones basadas en microservicios, combinando diferentes APIs y bases de datos.
Apollo consta de diversas herramientas: el cliente, el servidor y el motor. A continuación tienes una descripción acerca de lo que hace cada una de ellas:
- Cliente de Apollo: El cliente de Apollo te ayudará a consumir cualquier API GraphQL, incluyendo también soporte para las tecnologías web frontend más utilizadas, como React, Vue, Angular, Svelte o Meteor, incluyendo también a sus versiones nativas, como React Native, que te ayudarán a consumir tu API cuando creas aplicaciones para Android o iOS.
- Servidor de Apollo: El servidor de Apollo es la parte de GraphQL que se ejecuta en el servidor, funcionando a modo de interfaz entre el las peticiones entrantes y tu código backend, encargándose también de enviar de vuelta una respuesta a dichas peticiones.
- Apollo Graph Manager: Se trata de un servicio cloud opcional que se sitúa entre el cliente y el servidor de Apollo, encargándose de proporcionar un mecanismo de caché y de gestión de métricas de rendimiento y errores, así como otras estadísticas, guardando un completo historial de uso de las peticiones entre el cliente y el servidor. Este servicio, al que también se le conoce como Apollo Engine, es gratuito a no ser que excedas un cierto número de peticiones mensuales, en cuyo caso existe una comisión. Es el único componente de Apollo que no es open source. Puedes encontrar más de información de Apollo Graph Manager en su documentación.
Todas estas herramientas son opcionales. Es decir, que puedes utilizar solamente aquellas que necesites. Por ejemplo, podrás usar el cliente de Apollo para realizar peticiones a tu servidor y gestionar las peticiones entrantes manualmente. Del mismo modo, podrás enviar las peticiones desde el cliente sin usar el cliente de Apollo y usar el servidor de Apollo en tu servidor para responder a las mismas.
El estándar GraphQL no te fuerza a que uses una u otra tecnología, aunque lo cierto es que suele ser conveniente el uso de todo el conjunto de herramientas de Apollo, ya que de este modo te ahorrarás bastante trabajo. Aprender a usar Apollo no te llevará demasiando tiempo, ya que parte de una serie de conceptos muy sencillos, siendo en esta sencillez en donde radica su éxito. Apollo resulta útil tanto en pequeños proyectos como en proyectos de gran envergadura, con lo cual una vez te acostumbres a utilizarlo, prácticamente podrás establecerlo como un estándar en tu metodología de desarrollo.
El cliente de Apollo (Apollo Client)
El cliente de Apollo o Apollo Client es un cliente JavaScript para GraphQL diseñado poder crear componentes que hagan uso de GraphQL. Estos componentes podrán obtener y mostrar datos o también realizar cambios o mutaciones cuando ocurran ciertas acciones. Lo mejor de todo es que podrás comenzar con cosas sencillas, por lo que no te verás obligado a modificar toda la estructura de tu API para usar el cliente de Apollo; bastará con que comiences a utilizarlo con algún componente y más adelante podrás ir extendiendo su uso en tu aplicación.
El cliente de Apollo es relativamente simple y no consta de demasiado código, siendo una de sus prioridades la flexibilidad desde la que poder aplicar esta tecnología. A modo de ejemplo, en este tutorial vamos a crear una aplicación usando React que luego integraremos con el cliente de Apollo. Para simplificar las cosas, usaremos la API GraphQL de GitHub, que ya incluye todo lo necesario para ser integrada en un proyecto.
Creando y configurando la aplicación
Para crear la aplicación con React tendremos que instalar los paquetes necesarios, para lo cual nos apoyaremos en la herramienta create-react-app
. Dado que solamente necesitaremos este paquete una sola vez, es preferible usar el comando npx
en lugar de npm
. El comando npx
permite ejecutar ciertos paquete útiles durante el desarrollo de la aplicación pero sin guardarlos, así que abre la terminal e introduce este comando para crear y configurar la aplicación con React:
npx create-react-app tutorial-apollo
Seguidamente, espera a que la creación de la aplicación termine e inicia la aplicación mediante el siguiente comando:
npm start
Una vez iniciada la aplicación, podrás utilizarla accediendo a la URL http://localhost:3000/
desde tu navegador.
A continuación, edita el archivo /src/index.js
del proyecto que acabas de crear. El archivo contendrá el siguiente código, que debes eliminar en su totalidad:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
Configuración con Apollo Boost
Apollo Boost es una herramienta que te permitirá configurar Apollo Client en un proyecto nuevo. Además de instalar el paquete apollo-boost
, también instalaremos el paquete de Apollo para React, llamado react-apollo
, y el paquete graphql
. Instalaremos todos estos paquetes a la vez mediante el siguiente comando:
npm install apollo-boost react-apollo graphql
Instancia del Cliente de Apollo
A continuación vamos a crear la instancia del cliente de Apollo en el archivo /src/index.js
. Para ello, primero debes importar el cliente de Apollo y, seguidamente, crear la instancia del mismo:
import { ApolloClient } from 'apollo-client';
const cliente = new ApolloClient();
Conexión o link con el servidor
El cliente de Apollo usa por defecto el endpoint /graphql
, al que hará referencia para cualquier petición que realicemos al servidor. Dicho esto, vamos a crear un enlace de conexión o Apollo Link mediante el cual podremos especificar los detalles de la conexión al servidor GraphQL y la URL del endpoint.
Los links o enlaces de Apollo se estructuran mediante un objeto de la clase HttpLink
que importaremos desde el módulo apollo-link-http
. Gracias a estos links o enlaces podremos especificar el modo mediante el cual queremos que se obtengan los resultados de cualquier petición GraphQL, además de las tareas que queremos realizar con las respuestas.
Los habitual es crear varias instancias de estos enlaces para que interactúen con las peticiones GraphQL, ejecutándose una tras otra, pudiendo cruzar los resultados obtenidos de diferentes fuentes y dando lugar al resultado final que queremos obtener.
A continuación vamos a agregar un Link de Apollo al cliente que hemos creado para que pueda usar el endpoint GraphQL de GitHub, cuya URL es https://api.github.com/graphql
. Para ello, edita el código anterior de modo que le pasemos el enlace al cliente cuando lo creamos:
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
const httpLink = createHttpLink({ uri: 'https://api.github.com/graphql' });
const cliente = new ApolloClient({
link: httpLink,
});
Configuración del sistema de caché
El cliente de Apollo utiliza por defecto un sistema de caché en memoria que permite incrementar la velocidad de ejecución de las consultas que no necesitan datos que puedan ser modificados en tiempo real. Existen diferentes estrategias de caché, aunque en este tutorial utilizaremos el sistema de caché en memoria, que cumple bastante bien su función. Para ello, modifica el código anterior de modo que importemos el módulo de caché, que pasaremos al cliente de Apollo en su creación:
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
const httpLink = createHttpLink({ uri: 'https://api.github.com/graphql' });
const cliente = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
Configuración de ApolloProvider
Antes de poder iniciar nuestro ejemplo, necesitamos conectar el cliente de Apollo con React, de modo que podamos utilizar GraphQL con cualquier componente de React. Para ello usaremos ApolloProvider, que tendremos que importar del módulo react-apollo
.
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import App from './App';
const httpLink = createHttpLink({ uri: 'https://api.github.com/graphql' });
const cliente = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
Lo que vamos a hacer ahora es incluir nuestro componente principal de React, que es nuestra aplicación <App/>
, en el interior de del componente ApolloProvider
, de modo que esté disponible en cualquier componente. Así que agrega este código justo a continuación del anterior:
ReactDOM.render(
<ApolloProvider client={cliente}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
Y con esto ya tendremos la aplicación de nuevo en funcionamiento, por lo que si accedes de nuevo a la URL http://localhost:3000/
, deberías ver la pantalla que se muestra por defecto cuando usas create-react-app
.
Estructura de las consultas GraphQL
Para crear consultas en GraphQL utilizamos template tags o plantillas literales. Primero necesitamos importar la template tag graphql-tag
de GraphQL al principio de nuestro archivo src/index.js
. Tras esto, ya podremos crear consultas mediante la siguiente estructura:
const query = gql`
query {
// Consulta
}
`;
Si quieres, puedes consultar el tutorial de introducción a GraphQL, en donde se explica con más detalle la estructura de las consultas GraphQL. Lo que vamos a hacer es obtener datos desde la API de GitHub y mostrarlos por pantalla.
En este apartado, una vez hemos importado ya gql
, vamos a ver en detalle cómo realizar una petición GraphQL utilizando el cliente de Apollo. Primero nos centraremos en la petición y seguidamente en cómo gestionar el resultado que obtengamos de vuelta.
Obteniendo el token de acceso
Lo primero que tendremos que hacer será obtener el token de acceso a la API de GitHub, por lo que debes acceder a la interfaz de GitHub y hacer clic en Settings (Configuración).
Debes acceder a la sección de tokens de acceso y generar un nuevo token. No te molestes en seleccionar los permisos que verás, ya que en este caso solamente obtendremos información pública, así que simplemente introduce un nombre para el token y haz clic en Generate token (generar token). El token de acceso que verás por pantalla es un bearer token que sigue el estándar OAuth 2.0.
Antes de continuar vamos a comprobar que el token funciona correctamente. Para ello, abre una ventana de terminal e introduce el siguiente comando usando curl
, reemplazando TU_TOKEN
, por el toquen que has obtenido en GitHub:
curl -H "Authorization: bearer TU_TOKEN" -X POST -d "\
{\
\"query\": \"query { viewer { login }}\" \
}\
" https://api.github.com/graphql
Lo que hemos hecho es enviar una petición HTTP agregando el token de autorización en la cabecera de la misma. Hemos incluido también una pequeña consulta. Es importante que hayas reemplazado el token, ya que de lo contrario la conexión no funcionará. Si todo ha ido bien, debería mostrarse por pantalla el siguiente resultado en formato JSON:
{"data":{"viewer":{"login":"edulazaro"}}}
Como ves, en mi caso se muestra por pantalla edulazaro
en el campo del login, en donde deberías poder ver tu nombre de usuario en GitHub.
En caso de que la conexión falle, se mostrará un error como el siguiente, por lo que tendrías que volver a asegurarte de que has introducido correctamente el token:
{
"message": "Bad credentials",
"documentation_url": "https://developer.github.com/v4"
}
Autenticación con el link de Apollo
Del mismo modo que hemos enviado el toquen de acceso junto con la petición que hemos hecho desde la terminal, también tendremos que enviarlo junto con las peticiones GraphQL que hagamos. El mejor modo de hacerlo consiste en crear un middleware para nuestro link o enlace de Apollo.
apollo-link-context
, que nos permitirá agregar un mecanismo de autenticación a las consultas. Puedes instalar el paquete mediante el siguiente comando:
npm install apollo-link-context
Seguidamente, importa el módulo setContext
en el archivo src/index.js
:
import { setContext } from 'apollo-link-context';
Acto seguido, agrega el siguiente código tras la creación del httpLink
, en el archivo src/index.js
, reemplazando TU_TOKEN
por el token que has obtenido en GitHub:
const authLink = setContext((_, { headers }) => {
const token = 'TU_TOKEN';
return {
headers: {
...headers,
authorization: `Bearer ${token}`,
}
}
});
Ahora debemos unir este nuevo link, llamado authLink
, al httpLink
que ya teníamos. Para ello puedes usar la función concat()
tal que así:
const link = authLink.concat(httpLink);
Y finalmente vamos a ver el código completo del archivo index.js
con todos los cambios que hemos hecho hasta ahora:
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import { setContext } from 'apollo-link-context';
import App from './App';
const httpLink = createHttpLink({ uri: 'https://api.github.com/graphql' });
const authLink = setContext((_, { headers }) => {
const token = '2fbd4e06d66f0e56d41e1ce26fe4efad6bfa1368';
return {
headers: {
...headers,
authorization: `Bearer ${token}`,
}
}
});
const link = authLink.concat(httpLink);
const cliente = new ApolloClient({
link: link,
cache: new InMemoryCache(),
});
ReactDOM.render(
<ApolloProvider client={cliente}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
Creación de una consulta GraphQL
Una vez finalizada la configuración de Apollo, ya podemos crear nuestra primera consulta GraphQL. Para ello edita el archivo src/App.js
e importa graphql
y gql
en la parte superior del archivo:
import React from 'react';
import { graphql } from 'react-apollo';
import { gql } from 'apollo-boost';
Seguidamente, agrega esta consulta GraphQL, mediante la cual pretendemos obtener los 20 repositorios con más estrellas de GitHub, de entre los los que tienen más de 10.000 estrellas::
const listaRepositorios = gql`
{
search(query: "stars:>10000", first: 20, type: REPOSITORY) {
repositoryCount
edges {
node {
... on Repository {
name
owner {
login
}
stargazers {
totalCount
}
}
}
}
}
}
`;
Mostrando los resultados de una consulta
Ahora vamos a ver cómo ejecutar la consulta GraphQL y mostrar los resultados en nuestro componente:
const App = graphql(listaRepositorios)(props =>
<ol>
{props.data.loading ? '' : props.data.search.edges.map((repo, i) =>
<li key={repo.node.owner.login + '-' + repo.node.name}>
<b>{repo.node.owner.login} / {repo.node.name}</b>: {' '}
{repo.node.stargazers.totalCount}
</li>
)}
</ol>
);
Como ves, le hemos pasado la consulta al método graphql
y seguidamente hemos renderizado el componente usando JSX. Aquí tienes el resultado que hemos obtenido:
En cuanto al código resultante, aquí tienes el código completo del archivo src/App.js
con lo que hemos hecho hasta ahora:
import React from 'react'
import { graphql } from 'react-apollo'
import { gql } from 'apollo-boost'
const listaRepositorios = gql`
{
search(query: "stars:>10000", first: 20, type: REPOSITORY) {
repositoryCount
edges {
node {
... on Repository {
name
owner {
login
}
stargazers {
totalCount
}
}
}
}
}
}
`;
const App = graphql(listaRepositorios)(props =>
<ol>
{props.data.loading ? '' : props.data.search.edges.map((repo, i) =>
<li key={repo.node.owner.login + '-' + repo.node.name}>
<b>{repo.node.owner.login} / {repo.node.name}</b>: {' '}
{repo.node.stargazers.totalCount}
</li>
)}
</ol>
);
export default App
Puedes consultar el código de este proyecto en GitHub:
- Cliente: Código de este proyecto en GitHub
El servidor de Apollo (Apollo Server)
El servidor de GraphQL es el segundo componente de esta tecnología. Se utiliza para gestionar las peticiones que se hacen a los endpoints, obteniendo los datos que sean necesarios para construir la respuesta a las peticiones entrantes.
Dependiendo del lenguaje de programación que se utilice, existen diferentes implementaciones de GraphQL, y el servidor de Apollo, es la implementación más utilizada en servidores Node.js que usan JavaScript. Actualmente Apollo se integra con los frameworks más utilizados, ya sea Express, Hapi o Koa, entre otros.
Apollo Server incluye diversas funcionalidades. Por un lado, te permitirá crear un esquema que defina los datos de tu proyecto, y por otro también te permitirá crear las funciones que se usan para obtener los datos que necesitan las diversas peticiones que puedan entrar. Estos últimos métodos reciben el nombre de resolvers.
Apollo también incluye otras funcionalidades. Por ejemplo, incluye mecanismos que facilitan la autenticación en tu API.
Configuración del proyecto
Crea un directorio para el proyecto. En este ejemplo le llamaremos tutorial-apollo-server
. Luego introduce el siguiente comando para inicializar el proyecto:
npm init
Ahora debes instalar tanto GraphQL como el servidor Apollo. Para ello instala los paquetes apollo-server
y graphql
mediante el siguiente comando:
npm install apollo-server graphql
Creación del servidor Apollo
Para empezar, crea un archivo llamado index.js
e importa en él tanto Apollo Server como GraphQL:
const { ApolloServer, gql } = require('apollo-server');
Ahora vamos a definir un esquema utilizando el template tag de gql
. La definición de un esquema no es otra cosa que un template literal o plantilla literal, que es un tipo de cadena de texto a la que se le aplica una función. Dicha cadena contiene la descripción de la consulta y el tipo de los datos asociados a cada campo. Si todavía te resultan confusos loas plantillas literales, consulta el siguiente tutorial en donde se explica qué son y cómo se utilizan los template literals en JavaScript.
Aquí tienes un ejemplo en el que definimos el esquema de una consulta:
const typeDefs = gql`
type Query {
nombre: String
}
`;
A continuación vamos a definir un resolver, que no es otra cosa que un objeto que mapea los campos definidos en un esquema y los asocia a funciones que se encargan de obtener los datos para dar forma a la respuesta de la consulta.
A continuación tienes un resolver que mapea el campo nombre
y obtiene la cadena 'Edu Lazaro'
como respuesta:
const resolvers = {
Query: {
nombre: (root, args, context) => {
return 'Edu lazaro';
}
}
};
Una vez tengas tanto la definición del esquema como el resolver asociado, debes inicializar el servidor de Apollo:
const servidor = new ApolloServer({ typeDefs, resolvers });
Luego debes invocar al método listen()
del servidor para que este comience a escuchar peticiones entrantes.
servidor.listen().then(({ url }) => {
console.log(`El servidor está esperando en la URL ${url}`);
});
Y aquí tienes el código completo del servidor de ejemplo que hemos creado:
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Query {
nombre: String
}
`;
const resolvers = {
Query: {
nombre: (root, args, context) => {
return 'Edu lazaro';
}
}
}
const servidor = new ApolloServer({ typeDefs, resolvers });
servidor.listen().then(({ url }) => {
console.log(`El servidor está esperando en la URL ${url}`);
});
Ejecutando el servidor Apollo
Ahora vamos a probar el servidor que hemos creado. Para ello, usa el siguiente comando para iniciar Apollo en el puerto 4000, que es el que se usa por defecto:
node index.js
Para comprobar si el servidor funciona, puedes probar a enviar una petición mediante curl
o Postman. Para enviarla mediante curl
, introduce este comando en la terminal:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '{ "query": "{ nombre }" }' \
http://localhost:4000/graphql
En mi caso se ha mostrado el siguiente resultado:
{"data":{"nombre":"Edu Lazaro"}}
Creando un cliente para el servidor
Vamos a crear una pequeña aplicación de ejemplo con React que usaremos para llamar a la API. Para ello crea un nuevo proyecto con la utilidad create-react-app
:
npx create-react-app tutorial-apollo-server-client
Luego instala los siguientes paquetes:
npm install apollo-boost react-apollo graphql
Y finalmente inicia la aplicación usando el comando npm start
.
Ahora edita el archivo src/index.js
y agrega el siguiente código:
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import App from './App';
const httpLink = createHttpLink({ uri: 'http://localhost:4000/graphql' });
const cliente = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
ReactDOM.render(
<ApolloProvider client={cliente}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
Lo único que hemos modificado con respecto al ejemplo que hemos seguido para crear la primera aplicación usando el cliente de Apollo ha sido el enlace, cuya uri será en este caso http://localhost:4000/graphql
, que es la de nuestro servidor Apollo.
Ahora vamos a editar el archivo src/App.js
y a agregar el código encargado de obtener los datos del endpoint que hemos creado y los muestre por pantalla:
import React from 'react';
import { gql } from 'apollo-boost';
import { Query } from 'react-apollo';
const App = () => (
<Query
query={gql`
{
nombre
}
`}
>
{({ loading, error, data }) => {
if (loading) return <p>Cargando...</p>
if (error) return <p>Error</p>
return data.nombre
}}
</Query>
);
export default App;
Si ahora accedes mediante tu navegador a la aplicación React que acabas de crear en la URL http://localhost:3000/
, deberías ve por pantalla el nombre que has establecido que se devuelva como respuesta en el resolver que se encarga de devolver los datos de la consulta nombre
.
Puedes consultar el código de este proyecto en GitHub:
- Servidor: Código del servidor de Apollo en GitHub
- Cliente: Código del cliente de Apollo en GitHub
Sandbox de Apollo
Si quieres, puedes echar un ojo a algunos de los sandboxes que existen para Apollo:
- Apollo Launchpad: Apollo Launchpad en Glitch
- Apollo Server: Playground de Apollo server en CodeSanbox
Si quieres puedes practicar o modificar estos proyectos. Esto ha sido todo.