Querying GraphCMS Content with urql

Jamie Barton
Jamie Barton

August 19, 2021

Querying GraphCMS Content with urql

urql is a GraphQL client for your frontend that boasts a smart caching mechanism, support for queries, mutations, subscriptions, and does it all in a very small ~7.4kb package.

We'll explore querying content at build using @urql/core (re-exported from urql) and urql react hooks to query content on the client-side on request.

Core urql

If you've used Next.js, then you'll be familiar with getStaticProps get your static content, and pass it as props to the page.

If you want to fetch any data on the client you should check out working with next-urql, but this guide is for fetching static data only. You'll also want to make sure your Permanent Auth Token has limited read permissions.

Let's first setup our urql client by importing createClient and passing it our GraphCMS endpoint:

import { createClient } from 'urql';
const client = createClient({
url: 'https://api-eu-central-1.graphcms.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master',
});

Then inside of getStaticProps you can use client.query() and pass it your query (and optional variables). You'll need to chain .toPromise() too.

You'll end up with something like this:

import { gql } from 'urql';
export const getStaticProps = async () => {
const ProductsQuery = gql`
{
products {
slug
name
}
}
`;
const {
data: { products },
} = await client.query(ProductsQuery).toPromise();
return {
props: {
products,
},
};
};

Now let's imagine we render a list of links to individual product pages, with this we can use Next.js dynamic routes to get the slug of a product page, and pass this to urql.

The file /products/[slug].js would look a little something like:

export async function getStaticProps({ params }) {
const { slug } = params;
const ProductBySlugQuery = gql`
query GetProductBySlug($slug: String!) {
product(where: { slug: $slug }) {
name
description
price
}
}
`;
const {
data: { product },
} = await client
.query(ProductBySlugQuery, {
slug,
})
.toPromise();
return {
props: {
product,
},
};
}

As with getStaticProps we'll need to declare getStaticPaths too. Unless you're adopting incremental static generation, you'll want to query GraphCMS to get all of your product slugs. It would look something like this:

export async function getStaticPaths() {
const ProductSlugsQuery = gql`
{
products {
slug
}
}
`;
const {
data: { products },
} = await client.query(ProductSlugsQuery).toPromise();
return {
paths: products.map(({ slug }) => ({
params: { slug },
})),
fallback: false,
};
}

That's the core urql client - fetching data!

You can play with this example on CodeSandbox:

Develop with Codesandbox

React urql

The developer experience shines thanks to the collection of methods urql has available for your framework.

Let's take a look at how you can use urql with React on the frontend, without statically building pages.

Before we can begin to update our index page of products, we'll need to wrap our application with a Provider component and pass it our client.

import React from 'react';
import ReactDOM from 'react-dom';
import { createClient, Provider } from 'urql';
import App from './App';
const client = createClient({
url: 'https://api-eu-central-1.graphcms.com/v2/ck8sn5tnf01gc01z89dbc7s0o/master',
});
ReactDOM.render(
<React.StrictMode>
<Provider value={client}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);

From here, we can import useQuery from urql and pass it on our query, but this time it'll be executed on the frontend.

We'll get from the array useQuery returns the first item, which we'll call result. This result will be an object, and we can get from that data, error and whether or not it's fetching.

useQuery doesn't need your GraphCMS endpoint (or a client) because it is aware of the context surrounding it that is <Provider value={client}>.

Now, all that's left to do is update our page to show a message when we're fetching, an error occurred, or the data we get back from GraphCMS.

import { gql, useQuery } from 'urql';
const ProductsQuery = gql`
{
products {
slug
name
}
}
`;
function App() {
const [result] = useQuery({ query: ProductsQuery });
const { data, fetching, error } = result;
if (fetching) return <p>Fetching products</p>;
if (error) return <p>Oh no... {error.message}</p>;
return (
<ul>
{data.products.map(({ slug, name }) => (
<li key={slug}>{name}</li>
))}
</ul>
);
}
export default App;

You can play with this example on CodeSandbox:

Develop with Codesandbox


It's Easy To Get Started

GraphCMS plans are flexibly suited to accommodate your growth. Get started for free, or reach out to our sales team to discuss larger projects with more complex needs