Introducción #
En este artículo se comenzaba a explicar como configurar el servidor GraphQL para conectarlo contra una base de datos MongoDB en el cloud. Ahora vamos usar el mismo proyecto para configurar el cliente para consumir en la aplicación los datos. Esta configuración puede servir para consumir datos de un servidor externo de GraphQL.
Como en el servidor vamos a usar NextJS para instalar y probar los ejemplos.
El ejemplo que voy explicar es usando el hook porque los ejemplos donde se llaman a las consultas desde el lado servidor no me funciona y me peta las consultas y no soy capaz de hacerlo funcionar.
Instalando el cliente #
El paquete que vamos a instalar es el apollo-cliente:
npm install @apollo/client
Configurando el cliente #
Dentro de la carpeta del proyecto graphql he creado el fichero client.js, en este fichero he copiado la configuración que hay en los ejemplos de NextJS en concreto de este ejemplo.
El contenido exacto del fichero es este:
import { useMemo } from "react";
import { ApolloClient, InMemoryCache } from "@apollo/client";
import merge from "deepmerge";
let apolloClient;
function createIsomorphLink() {
if (typeof window === "undefined") {
const { SchemaLink } = require("@apollo/client/link/schema");
const schema = require("./schema_def");
return new SchemaLink({ schema });
} else {
const { HttpLink } = require("@apollo/client/link/http");
return new HttpLink({
uri: "/api/graphql",
credentials: "same-origin",
});
}
}
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: createIsomorphLink(),
cache: new InMemoryCache(),
});
}
export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient();
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// get hydrated here
if (initialState) {
// Get existing cache, loaded during client side data fetching
const existingCache = _apolloClient.extract();
// Merge the existing cache into data passed from getStaticProps/getServerSideProps
const data = merge(initialState, existingCache);
// Restore the cache with the merged data
_apolloClient.cache.restore(data);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === "undefined") return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}
En la introducción hablaba que no me funciona las consultas en el modo servidor. La configuración se indica aquí:
if (typeof window === "undefined") {
const { SchemaLink } = require("@apollo/client/link/schema");
const schema = require("./schema_def");
return new SchemaLink({ schema });
}
Esto es lo que no me funciona
Añadiendo el contexto del apollo/client en _app.js #
En el fichero _app.js hay que añadir el contexto de esta manera:
import { ApolloProvider } from "@apollo/client";
import { useApollo } from "graphql/client";
function MyApp({ Component, pageProps }) {
const apolloClient = useApollo(pageProps.initialApolloState);
return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
);
}
export default MyApp;
Haciendo la primera consulta #
El archivo index.js lo he cambiado para hacer la primera consulta:
import Head from "next/head";
import Image from "next/image";
import { useQuery, gql } from "@apollo/client";
import styles from "../styles/Home.module.css";
const QUERY = gql`
query Query {
getAll {
_id
mueble
material
}
}
`;
export default function Home() {
const { data, loading, error } = useQuery(QUERY);
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Pruebas de GraphQL</h1>
<p className={styles.description}>
{loading && <p>Leyendo los datos....</p>}
{!loading && <p>Datos leídos</p>}
</p>
<div className={styles.grid}>
<ul>
{!loading &&
data.getAll.map((row) => <li key={row._id}>{row.mueble}</li>)}
</ul>
</div>
</main>
<footer className={styles.footer}>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{" "}
<span className={styles.logo}>
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
</span>
</a>
</footer>
</div>
);
}
La consulta la podemos tener en una variable como en el ejemplo o directamente en con el useQuery de la siguiente manera:
const { data, loading, error } = useQuery(gql`
query Query {
getAll {
_id
mueble
material
}
}
`);
El hook useQuery nos devuelve tres variables:
- data -> resultado de la búsqueda
- loading -> Variable si la consulta esta en ejecución
- error -> Si se ha producido un error en la búsqueda