Add a Contentful blog to your NextJS app and Typescript
November 10, 2022
Learn how to add a blog page to your existing NextJS React app using Contentful, React, Typescript, GraphQL code generator and urql
1. Prerequisites
Have a Contenful account
Have a Contenful "space" created
Have a "Blog" model created in the space
2. Get the Contentful access tokens
You need the SpaceId
, the Content Delivery Access Token
and the Content Preview Token
On your Contenful account click on Settings > API Keys
Then Click on Add Api Key
Copy the SpaceId
, the Content Delivery Access Token
and the Content Preview Token
Add the tokens to your .env
file
CONTENTFUL_SPACE_ID=your Space ID
CONTENTFUL_ACCESS_TOKEN=Content Delivery API token
CONTENTFUL_PREVIEW_ACCESS_TOKEN=Content Preview API token
3. Setup GraphQL codegen
Install graphql-codegen
First install graphql-codegen dependencies to automatically generate types from the Contentful GraphQL Schema
npm install --save graphql
npm install --save-dev @graphql-codegen/cli
Auto Let's graphql-codegen
to setup everything by simply running the following command
npx graphql-codegen init
It should ask some questions so it can generate the file codegen.ts
For the following questions enter:
Where is your schema?: (path or url) https://graphql.contentful.com/content/v1/spaces/1234
Change 1234 with your spaceId
Where are your operations and fragments?: "pages/**/*.tsx","components/**/*.tsx"
Here I am going to read the graphql queries from the pages and the components
This is what I answered for the other questions:
After this, we should see the codegen.ts file has been created.
Now, install the required dependencies that were added to the package.json by the wizard
npm install
Next, we need to change the codegen.ts
file so it can connect to the Contentul graphql with authentication. We are going to read this from the env variables. Change the file like this:
import type { CodegenConfig } from "@graphql-codegen/cli";
import { loadEnvConfig } from "@next/env";
const dev = process.env.NODE_ENV !== "production";
loadEnvConfig("./", dev).combinedEnv;
const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID;
const CONTENTFUL_PREVIEW_ACCESS_TOKEN =
process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN;
const config: CodegenConfig = {
overwrite: true,
schema: [
{
[`https://graphql.contentful.com/content/v1/spaces/${CONTENTFUL_SPACE_ID}`]:
{
headers: {
Authorization: `Bearer ${CONTENTFUL_PREVIEW_ACCESS_TOKEN}`,
},
},
},
],
documents: ["pages/**/*.tsx", "components/**/*.tsx"],
generates: {
"src/gql/": {
preset: "client",
plugins: [],
},
},
};
export default config;
Generate needed node
Generate some code we need BEFORE writing our first query Run the command
npm run codegen
You should see a new folder called gql
has been created along with some files inside it.
You can see the typescript types have been generated for the Contentful schema
Add a graphql query
Let's add a query to get all the blog titles.
Create a new page called blogs.tsx
In this page add the the following query. This is a simple query that will return all the blog titles
const blogListForHome = graphql(`
query blogListForHome {
blogCollection(order: date_DESC) {
items {
title
}
}
}
`);
Run the code generator command to generate the types for this query
npm run codegen
4. Install urql
Run the command
npm install urql
Setup urql
Create the file urqlClient.ts
Add the following code to setup the urql client
import { createClient } from "urql";
export const client = createClient({
url: `https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}`,
fetchOptions: {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${
process.env.CONTENTFUL_PREVIEW
? process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN
: process.env.CONTENTFUL_ACCESS_TOKEN
}`
}
}
});
5. Fetch data and render in the page
Add the getStaticProps
function to get the data from Contenful
Render the data
type Props = {
blogCollection: BlogCollection;
};
const BlogPage = ({ blogCollection }: Props) => {
return (
<div>
<ul>
{blogCollection.items.map((el, idx) => (
<li key={idx}>{el?.title}</li>
))}
</ul>
</div>
);
};
That's it.