skip to Main Content

I’m new to using next.JS, Graphql/Apollo so I’m trying to build a simple e-commerce page, I’m creating a page for a single product with the route /products/[id] and I try to do Serverside Generation (SSG) by using getStaticPaths to generate all the paths and getStaticProps to return the product details but I keep getting an error that the paths are undefined in getStaticPaths. This is the error message I keep getting:

Error: Invalid `paths` value returned from getStaticPaths in /products/[id].
`paths` must be an array of strings or objects of shape { params: [key: string]: string }

This is my code for the page:
I’m currently using a graphql api

import {
  useQuery,
} from '@apollo/client';
import { initializeApollo, PRODUCTS_API } from '../../../lib/apollo';
import { GET_ALL_PRODUCTS_QUERY, GET_SINGLE_PRODUCT_QUERY, allProductsQueryVars } from '../../../lib/queries';
import SingleProduct from '../../../components/SingleProduct';

export default function ProductPage({ id }) {
  const {
    loading, error, data,
  } = useQuery(
    GET_SINGLE_PRODUCT_QUERY,
    {
      variables: { id },
    },
  );

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error</p>;

  if (data) {
    const { product } = data;

    return (
      <SingleProduct product={product} />
    );
  }
}

export async function getStaticPaths() {
  const client = initializeApollo();

  const data = await client.query({
    query: GET_ALL_PRODUCTS_QUERY,
    variables: allProductsQueryVars,
  });

  const paths = data.products?.edges.map(({ node: { id } }) => ({
    params: { id },
  }));

  return {
    paths,
    fallback: false,
  };
}

export const getStaticProps = async ({ params }) => ({
  props: {
    id: params?.id,
  },
});

This is my Apolloclient configuration code:

import merge from 'deepmerge';
import isEqual from 'lodash/isEqual';
import {
  ApolloClient, InMemoryCache, HttpLink, from,
} from '@apollo/client';
import { onError } from '@apollo/client/link/error';
import { relayStylePagination } from '@apollo/client/utilities';

let apolloClient;

export const PRODUCTS_API = 'https://unicorn-staging.eu.saleor.cloud/graphql/';

const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, locations, path }) => console.log(
      `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
    ));
  }
  if (networkError) console.log(`[Network error]: ${networkError}`);
});

const httpLink = new HttpLink({
  uri: PRODUCTS_API, // Server URL (must be absolute)
});

export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__';

function createApolloClient() {
  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: from([errorLink, httpLink]),
    cache: new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            products: relayStylePagination([]),
          },
        },
      },
    }),
  });
}

export function initializeApollo(initialState) {
  const _apolloClient = apolloClient ?? createApolloClient();

  if (initialState) {
    const existingCache = _apolloClient.cache.extract();

    const data = merge(initialState, existingCache, {
      arrayMerge: (destinationArray, sourceArray) => [
        ...sourceArray,
        ...destinationArray.filter((d) => sourceArray.every((s) => !isEqual(d, s))),
      ],
    });
    _apolloClient.cache.restore(data);
  }

  if (typeof window === 'undefined') {
    return _apolloClient;
  }

  if (!apolloClient) {
    apolloClient = _apolloClient;
  }

  return _apolloClient;
}

export function addApolloState(
  client,
  pageProps,
) {
  if (pageProps?.props) {
    pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract();
  }

  return pageProps;
}

and this is the graphql query and variable

export const GET_ALL_PRODUCTS_QUERY = gql`
  query GetProducts($first: Int!, $after: String){
    products(channel: "uk", first: $first, after: $after){
      edges {
        node {
          id
          name
          rating
          slug
          description
          isAvailable
          thumbnail {
            url
            alt
          }
          category {
            name
          }
          pricing {
            priceRange {
              start {
                gross {
                  amount
                }
              }
              stop {
                gross {
                  amount
                }
              }
            }
          }
        }
      }
      pageInfo {
        hasNextPage
        hasPreviousPage
        startCursor
        endCursor
      }
      totalCount
    }
  }
`;

export const allProductsQueryVars = {
  first: 10,
  after: '',
};

Please, any ideas on how I can fix this?

Whenever I try to visit the single products url, I get the error from getStaticPaths when trying to generate all the possible values for parameters in dynamic routes ahead of time when the website is being built.
Thank you in advance for any tip that could cause this. I tried alot of things but cant figure it out yet.

2

Answers


  1. Chosen as BEST ANSWER

    I fixed it by destructuring the value returned from the query in getStaticPaths.

    const {data} = await client.query({
        query: GET_ALL_PRODUCTS_QUERY,
        variables: allProductsQueryVars,
      });
    

  2. I got same error back then and that is natural you have to keep learning let me give you a hand in this

    and based on error message indicates that paths values which are returend by getStaticPaths is not in correct formats if i say specifically it should be an array of objects with shape like { params: [key: string]: string } but code is returning array of objects with the shape like { id: string }

    but dont worry you can fix this by map function in getStaticPaths to return objects in correct shapes as in my local server codes are working fine

    you have to use this variable are paths

    const paths = data.products?.edges.map(({ node: { id } }) => ({
      params: { id },
    }));
    
    

    this way you can create an array of objects with their correct params property that contains an object with respective id

    if that helped you . you can upvote this answer to help other junior developers like you 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search