SEUNGJUN LEE.

Using nextjs + contentful

Why I chose Contentful CMS

I created my first portfolio and blog site using Gatsbyjs, creating markdown files in the project and importing them into GraphQL for display.

When I planned to create a new version of my portfolio website this year, I wondered if I should manage all the markdowns in the project repo, so I looked for a CMS (Content Management System) and chose Contentful.

This time, I decided to try next.js and started my journey...

Start with the token

I won't write down what you need to do in the contenful dashboard, it's pretty intuitive, just do what it says.

After that, I added the tokens to .env.local. Preview is a feature that allows you to see your changes live on the website as you write content, but I didn't add it because I didn't see a need for it.

CONTENTFUL_SPACE_ID=YOUR_SPACE_ID
CONTENTFUL_ACCESS_TOKEN=YOUR_ACCESS_TOKEN 
CONTENTFUL_PREVIEW_ACCESS_TOKEN=YOUR_PREVIEW_TOKEN

At first, I used the SDK

library provided in the SDK, but it worked locally but not in the environment after deploying to cloudflare pages.

I couldn't find the cause, so I gave up and later changed to the REST API... It was simple to use.

npm i contenful

// utils/contentful.ts
import { createClient } from 'contentful';

const client = createClient({
    space: process.env.CONTENTFUL_SPACE_ID,
    accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
})

// fetch blog posts
export const getBlogPosts = async () => {
  const results = await client.getEntries({
    content_type: 'blogPost', // content type created in the dashboard
  })
  
  return response.items
}

Using the REST API

// utils/contentful.ts
const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID!;
const CONTENTFUL_ACCESS_TOKEN = process.env.CONTENTFUL_ACCESS_TOKEN!;

export async function fetchPosts() {
  const url = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/master/entries?access_token=${CONTENTFUL_ACCESS_TOKEN}&content_type=blogPost`;

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${CONTENTFUL_ACCESS_TOKEN}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch posts: ${response.statusText}`);
  }

  const data = await response.json();
  return data;
}

export async function fetchPostBySlug(slug: string) {
  const url = `https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/master/entries?access_token=${CONTENTFUL_ACCESS_TOKEN}&content_type=blogPost&fields.slug=${slug}`;

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${process.env.CONTENTFUL_ACCESS_TOKEN}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch post: ${response.statusText}`);
  }

  const data = await response.json();
  const post = data.items[0];

  if (!post) {
    throw new Error("Post not found");
  }

  return post;
}

Calling from a page

If you are using Next.js 13 and app router, you can fetch data like below.

const Blog: React.FC = async () => {
  const posts = await fetchPosts();
 ...