GraphQl, contentful and next.js

Published on
post image

Intro

I have recently encountered some issues regarding the amount of data that I was retrieving from the contentful CMS database. At some point, next.js complained with a "Large Page Data" error about it. Because I was using 'getStaticProps' to retrieve the data from the database, next.js would permanently complain about the amount of data that I would be retrieving and thus delivering to the customers when the page loads.

How to find out how big the files are with js?

In the beginning, I struggled to find out the file size of the page data that I would retrieve from the database and which call would be responsible for the large page data prompt. So what I found was a tool to measure the array size of the data that I was receiving.

function memorySizeOf(obj) {
	var bytes = 0;

	function sizeOf(obj) {
		if (obj !== null && obj !== undefined) {
			switch (typeof obj) {
				case "number":
					bytes += 8;
					break;
				case "string":
					bytes += obj.length * 2;
					break;
				case "boolean":
					bytes += 4;
					break;
				case "object":
					var objClass = Object.prototype.toString.call(obj).slice(8, -1);
					if (objClass === "Object" || objClass === "Array") {
						for (var key in obj) {
							if (!obj.hasOwnProperty(key)) continue;
							sizeOf(obj[key]);
						}
					} else bytes += obj.toString().length * 2;
					break;
			}
		}
		return bytes;
	}

	function formatByteSize(bytes) {
		if (bytes < 1024) return bytes + " bytes";
		else if (bytes < 1048576) return (bytes / 1024).toFixed(3) + " KiB";
		else if (bytes < 1073741824) return (bytes / 1048576).toFixed(3) + " MiB";
		else return (bytes / 1073741824).toFixed(3) + " GiB";
	}

	return formatByteSize(sizeOf(obj));
}

How to reduce the amount of data pre-fetching for SSR?

So the SSR functionality of next.js is great and all but the question that I learned I should always be asking is what is the minimum amount of data I need for the page to be rendered?. Because what you want to do is to pre-fetch only the data that is necessary for this exact page to be rendered and not your entire dataset. So for your first setup, it is great to use the 'getStaticProps' function to retrieve the data from the database and then use the 'getStaticPaths' function to retrieve the paths of the pages that you want to pre-fetch. But as soon as your database has some data that is not necessary for each page to be rendered, you will have to change the 'getStaticProps' function to retrieve the data that is necessary.

I am using contentful as my CMS for the food blog project and initially I designed the data fetching process in that way so that I would retrieve the entire information into a giant array and then pass it to each component that needs certain data. While that works fine for the first few pages, it is not ideal as soon as your database grows.

GraphQl for data fetching

So I decided to change the data fetching process to retrieve the data that is necessary for each page to be rendered via GraphQl.

Contentful offers a great API to query data from the database via graphql, you can find the documentation here: contentful docs

What I found really helpful during the process of finding out how to use GraphQl to query data from the contentful CMS database was the GraphQl explore link that you could combine with GraphiQl to explore the schema of the database.

https://graphql.contentful.com/content/v1/spaces/{SPACE}/explore?access_token={CDA_TOKEN}

To use it, you simply need to exchange your contentful SPACE-ID and your contentful CDA token. You can find them in the Contentful dashboard.

The cool thing about this is that you get something like a tree-like structure of the database that you can easily navigate using control+Tab to find out your options on the current level . Using the play button it will also autocomplete certain information that you need to receive some data. With this, you have the ideal situation to generate the GraphQl queries that you need to retrieve exactly the data that you need.

GraphQl queries in next.js

The setup for GraphQL in next.js is really simple. The first thing to do is to install GraphQl and apollo client.

npm install @apollo/client graphql

The next thing for me is always to create a new file in the lib folder of my projects, as it's a function that I would possibly want to reuse somewhere. But of course, you do as you like.

After this we just need to import the 'gql' function from apollo and then use the 'new ApolloClient' function to create the GraphQl client.

import { gql } from "@apollo/client";
import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
	uri: `https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}/?access_token=${process.env.CONTENTFUL_ACCES_KEY}`,
	cache: new InMemoryCache(),
});

See that I used the process.env.CONTENTFUL_SPACE_ID and process.env.CONTENTFUL_ACCES_KEY variables to retrieve the necessary data from the environment variables.

Next, we need to create our queries. The queries are basically the same as the ones you would use in GraphiQl. Of course, they depend on your data structure.

const GET_POSTS = gql`
	query {
		posts {
			id
			title
			content
			slug
			createdAt
			updatedAt
		}
	}
`;

After this, all you need to do is to decide where to call the function that will retrieve the data. The function should look something like this.

async function getAllPosts() {
	const { data } = await client.query({
		query: GET_POSTS,
	});
	return data;
}

You can provide the data to your application via getStaticProps or getStaticPaths functions. Or use SWR to fetch the data on the client-side via an API call. But of course, for that, you will need to create the API, but that is another tutorial. You can find out more about API creation with next.js in the documentation here: next.js docs

Affiliate Disclaimer
Disclaimer:
Links on the site might be affiliate links, so if you click them I might earn a small commission.