How to Fix Undefined Error with GraphQL Request in Next.js

When you’re working with Next.js and Contentful, dynamic pages may sometimes return an “undefined” error when making GraphQL requests. This issue is common and often occurs due to improper query structure or missing error handling. I’ll explain the problem, walk through the fix, and show you the corrected code that should solve your issue.

Error Code

console.error("There was a problem retrieving entries with the query:", query);
console.error("Error details:", error);

Explanation of the Error

GraphQL Query Issue:

In your getStaticProps, you’re constructing a GraphQL query with a dynamic slug, but you aren’t passing the value correctly into the query. Instead of dynamically passing context.params.slug into the GraphQL query, you’re likely interpreting it as a string literal. This means the query is looking for an exact match of "context.params.slug" instead of the value you intend.

Query Construction:

The GraphQL query you’re using to fetch posts based on slug is not correctly formatted to handle dynamic values. This issue often causes Contentful to return an empty or undefined response when fetching dynamic pages, even though the same query works for the static news page.

Dynamic Data Handling:

The issue might also lie in how the getStaticProps and getStaticPaths functions are handling dynamic data from Contentful. If these functions aren’t receiving the expected data from Contentful, it can cause them to return an undefined result.

Solution and Fix

To fix this issue, you need to adjust how the slug parameter is passed into your GraphQL query and ensure that it’s properly interpolated. Below is the refactored code that resolves the issue by correctly passing the dynamic slug to the query.

Refactored Code

News Article Page (news/[slug].tsx):

tsxCopyimport { Box, Text } from "@chakra-ui/react";
import React from "react";
import { fetchContent } from "../../utils/contentful";

const NewsArticlePage = ({ post }) => {
  // Ensure post.slug is defined before attempting to use it
  if (!post) {
    return <Box>No Post Found</Box>;
  }

  return (
    <Box>
      <Text>{post.title}</Text>
      <Text>{post.slug}</Text>
    </Box>
  );
};

export default NewsArticlePage;

// Fetching data for dynamic pages
export async function getStaticProps({ params }) {
  console.log("Fetching post for slug:", params.slug);

  const response = await fetchContent(`
    query getBlogPost($slug: String!) {
      blogPostCollection(where: {slug: $slug}) {
        items {
          title
          slug
        }
      }
    }
  `, { slug: params.slug });

  console.log("Response:", response);

  const post = response?.blogPostCollection?.items?.[0] || null;

  if (!post) {
    return { props: {} }; // Return empty props if no post found
  }

  return {
    props: {
      post,
    },
  };
}

export async function getStaticPaths() {
  const response = await fetchContent(`
    query {
      blogPostCollection {
        items {
          slug
        }
      }
    }
  `);

  const paths = response?.blogPostCollection?.items.map((post) => ({
    params: { slug: post.slug },
  })) || [];

  return {
    paths,
    fallback: false,
  };
}

Utility Function to Fetch Data (utils/contentful.js):

space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;

export async function fetchContent(query, variables = {}) {
try {
const res = await fetch(
`https://graphql.contentful.com/content/v1/spaces/${space}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
},
body: JSON.stringify({ query, variables }),
}
);

if (!res.ok) {
throw new Error("Network response was not ok");
}

const { data } = await res.json();

return data;
} catch (error) {
console.error("Error fetching data from Contentful:", error);
throw error; // Propagate the error to be handled elsewhere
}
}

Key Fixes:

  1. Query Formatting: In the GraphQL query, the slug value is now passed as a variable ($slug) and included in the request through the variables parameter.
  2. Error Handling: I added better error handling within the fetchContent function using a try-catch block. This allows you to catch network errors or API-related issues and log them for debugging.
  3. Fetching Single Post: The way the post is fetched from the response has been modified. Instead of assuming a fixed structure, we safely access the first item in the response with response?.blogPostCollection?.items?.[0].
  4. Dynamic Paths Handling: The getStaticPaths function now fetches only the slug field for each post, which is sufficient for generating static paths. This ensures that a dynamic page is generated for each unique slug.

Additional Functionality:

  1. Error Handling for Undefined Posts: I added a safeguard to handle cases where no post is found, displaying a fallback message like “No Post Found” on the page. This will help you debug if something goes wrong.
  2. Query Optimization: The getStaticProps function is now optimized to properly accept the slug as a variable, reducing the chance of errors related to incorrect query construction.

Further Improvements:

  1. Fallback Handling: If you want Next.js to regenerate pages on-demand when new posts are added, you can modify the getStaticPaths fallback behavior to true. This way, it won’t block new slugs from appearing, and the page will be generated on the fly for those slugs that were not pre-generated.
  2. Caching: To minimize the number of requests to Contentful and improve performance, you could implement caching mechanisms such as using a CDN or storing the data locally for a set amount of time.

Conclusion

By ensuring the GraphQL query is properly constructed with dynamic variables and improving error handling in the fetch function, this solution should resolve the undefined error you’re encountering when working with dynamic pages in Next.js and Contentful. Always ensure that the slug or other dynamic parameters are correctly passed into the query, and handle edge cases like missing posts or errors gracefully.

Related blog posts