3

How to fetch the response of a graph ql query from next js

4 Answers 4

1

You can use GraphQLRequestClient to make a request to GraphQL from Next.js application.

  1. As a first step, you will need to create GraphQLRequestClient as below.
import { GraphQLRequestClient } from '@sitecore-jss/sitecore-jss-nextjs';
import config from '@/temp/config';

export function GraphQLSearchClient() {
  const graphqlEndPoint = config.graphQLEndpoint;
  const apiKey = config.sitecoreApiKey;
  const graphClient = new GraphQLRequestClient(graphqlEndPoint, {
    apiKey: apiKey,
  });
  return graphClient;
}
  1. Construct the GraphQL query using graphql-tag package as below.
import gql from 'graphql-tag';
const SiteInfoQuery = (
) => {
  return gql`
    query {
     site {
      siteInfo(site: "example") {
      routes(language: "en") {
        results {
          route {
            id
          }
          routePath
        }
        total
        pageInfo {
          endCursor
          hasNext
        }
      }
    }
  }
}
  `;
};

export default SiteInfoQuery;
  1. Then finally you can call the above functions as below to get the GraphQL output inside the api created inside pages/api folder.
import { NextApiHandler } from 'next'; 
const handler: NextApiHandler<unknown> = async (request, response) => {
  try {
    const siteQuery = SiteInfoQuery();
    const graphClient = GraphQLSearchClient();
    const siteData = graphClient.request(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      siteQuery as any
    );
    return response.status(200).json(siteData);
  } catch (error) {
    return response.status(500).json(error);
  }
}

This api then can be called in your Next.js application. Using above way, you can succesfully make a call to GraphQL and read the desired output.

Below is the code on how you can call above api inside your component to read the site output.

fetch('/api/{{apifoldername}}', {
   method: 'GET
})
.then((response) => {
   return response.json();
})
.then((data) => {
   console.log(data);
})

Note: The endpoints for GraphQL and Api key needs to set inside .env file as below.

GRAPH_QL_ENDPOINT_PATH={{SiteDomainUrl}}/sitecore/api/graph/edge
SITECORE_API_KEY={{APIKeyCreatedInSitecore}}

Hope this helps!!! Let me know in case you face any issues.

1

In your Next.js project, you can use graphql-request to execute the GraphQL query. Here’s an example of how to fetch data from the GraphQL endpoint and display it in a Next.js page.

Create a new file in the pages directory, e.g., pages/routes.js, and add the following code:

import { GraphQLClient, gql } from 'graphql-request';
import React, { useState } from 'react';

// Define the GraphQL query with variables
const QUERY = gql`
  query GetRoutes($site: String!, $language: String!, $cursor: String) {
    site {
      siteInfo(site: $site) {
        routes(language: $language, after: $cursor) {
          results {
            route {
              id
            }
            routePath
          }
          total
          pageInfo {
            endCursor
            hasNext
          }
        }
      }
    }
  }
`;

// Fetch data from the GraphQL endpoint
export async function getServerSideProps(context) {
  const endpoint = 'https://your-sitecore-instance/graphql'; // Replace with your GraphQL endpoint
  const graphQLClient = new GraphQLClient(endpoint, {
    headers: {
      'Authorization': `Bearer ${process.env.GRAPHQL_API_TOKEN}`, // Replace with your auth token or custom headers
      'Content-Type': 'application/json'
    }
  });

  const variables = {
    site: 'example',
    language: 'en',
    cursor: context.query.cursor || null
  };

  const data = await graphQLClient.request(QUERY, variables);
  
  return {
    props: {
      data
    }
  };
}

// Component to display fetched data with pagination
const RoutesPage = ({ data }) => {
  const [routes, setRoutes] = useState(data.site.siteInfo.routes.results);
  const [hasNext, setHasNext] = useState(data.site.siteInfo.routes.pageInfo.hasNext);
  const [endCursor, setEndCursor] = useState(data.site.siteInfo.routes.pageInfo.endCursor);

  const fetchMore = async () => {
    const endpoint = 'https://your-sitecore-instance/graphql'; // Replace with your GraphQL endpoint
    const graphQLClient = new GraphQLClient(endpoint, {
      headers: {
        'Authorization': `Bearer ${process.env.GRAPHQL_API_TOKEN}`, // Replace with your auth token or custom headers
        'Content-Type': 'application/json'
      }
    });

    const variables = {
      site: 'example',
      language: 'en',
      cursor: endCursor
    };

    const newData = await graphQLClient.request(QUERY, variables);
    
    setRoutes([...routes, ...newData.site.siteInfo.routes.results]);
    setHasNext(newData.site.siteInfo.routes.pageInfo.hasNext);
    setEndCursor(newData.site.siteInfo.routes.pageInfo.endCursor);
  };

  return (
    <div>
      <h1>Sitecore Routes</h1>
      <ul>
        {routes.map(({ route, routePath }) => (
          <li key={route.id}>
            <strong>ID:</strong> {route.id} <br />
            <strong>Path:</strong> {routePath}
          </li>
        ))}
      </ul>
      {hasNext && (
        <button onClick={fetchMore}>Load More</button>
      )}
    </div>
  );
};

export default RoutesPage;

Hope this helps!!!

2
  • I have update answer how you can add headers and query variables to the request here in next js Commented Sep 4 at 8:36
  • I Used getStaticProps as export method in a layout.tsx file and wrote the logic but its not executing. there are no console erros.
    – coder
    Commented Sep 4 at 12:00
1

you have added endCursor, hasNext in your query. so, If you want to get all the data based on these two variables and in small chunks.

You can try this.

I already tried for my footer component, there so many navigation links. so, I called graphql query multiple times to get navigation links in small chucks.

I called in graphql query in getStaticProps, so it will get call the query multiple time in build time only. and i added query in diffent file ./Footer.graphql

import React from 'react';
import { FooterNavDocument } from './Footer.graphql';
import {
  GetStaticComponentProps,
  GraphQLRequestClient,
  constants,
} from '@sitecore-jss/sitecore-jss-nextjs';
import config from '@/temp/config';

const Footer = (_props: any): JSX.Element => {
  return <>Footer</>;
};
export const getStaticProps: GetStaticComponentProps = async (rendering, layoutData) => {
  if (process.env.JSS_MODE === constants.JSS_MODE.DISCONNECTED) {
    return null;
  }
  const graphQLClient = new GraphQLRequestClient(config.graphQLEndpoint, {
    apiKey: config.sitecoreApiKey,
  });
  const result = await graphQLClient
    .request(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      FooterNavDocument as any,
      {
        datasource: rendering.dataSource,
        contextItem: layoutData?.sitecore?.route?.itemId,
        language: layoutData?.sitecore?.context?.language,
        afterValue: '',
      }
    )
    .then(async (data: any) => {
      while (data.pageInfo.hasNext) {
        await graphQLClient
          .request(
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            FooterNavDocument as any,
            {
              datasource: rendering.dataSource,
              contextItem: layoutData?.sitecore?.route?.itemId,
              language: layoutData?.sitecore?.context?.language,
              afterValue: data.pageInfo.endCursor,
            }
          )
          .then(async (newdata: any) => {
            data.results.push(...newdata.results);
            data.pageInfo = newdata.pageInfo;
            return data;
          });
      }
      return data;
    });
  return result;
};
export default Footer;

so, here it will call graphql call till data.pageInfo.hasNext, and it will give data after data.pageInfo.endCursor value in every call.

Example: First I added footer.tsx file

import React from 'react';
import { FooterNavDocument } from './Footer.graphql';
import {
  GetStaticComponentProps,
  GraphQLRequestClient,
  constants,
} from '@sitecore-jss/sitecore-jss-nextjs';
import config from '@/temp/config';

const Footer = (_props: any): JSX.Element => {
  return <>Footer</>;
};
export const getStaticProps: GetStaticComponentProps = async (rendering, layoutData) => {
  if (process.env.JSS_MODE === constants.JSS_MODE.DISCONNECTED) {
    return null;
  }
  const graphQLClient = new GraphQLRequestClient(config.graphQLEndpoint, {
    apiKey: config.sitecoreApiKey,
  });
  const result = await graphQLClient
    .request(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      FooterNavDocument as any,
      {
        datasource: rendering.dataSource,
        contextItem: layoutData?.sitecore?.route?.itemId,
        language: layoutData?.sitecore?.context?.language,
        afterValue: '',
      }
    )
    .then(async (data: any) => {
      while (data.homeItem.primaryMenu.pageInfo.hasNext) {
        await graphQLClient
          .request(
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            FooterNavDocument as any,
            {
              datasource: rendering.dataSource,
              contextItem: layoutData?.sitecore?.route?.itemId,
              language: layoutData?.sitecore?.context?.language,
              afterValue: data.homeItem.primaryMenu.pageInfo.endCursor,
            }
          )
          .then(async (newdata: any) => {
            data.homeItem.primaryMenu.results.push(...newdata.homeItem.primaryMenu.results);
            data.homeItem.primaryMenu.pageInfo = newdata.homeItem.primaryMenu.pageInfo;
            return data;
          });
      }
      return data;
    });
  return result;
};
export default Footer;

then I added footer.graphql file

query FooterNav($datasource: String!, $language: String!, $afterValue: String!) {
  #Ancestor Template ID should be Your Headless Site Template ID
  homeItem: item(path: "/sitecore/content/abc/abc/Home", language: "en-US") {
    primaryMenu: children(
      hasLayout: true
      #first: 40
      after: $afterValue
    ) {
      pageInfo{
        endCursor
        hasNext
      }
      results {
       menuTitle: field(name: "menuTitle") {
          jsonValue
        }
        }
      }
    }
  }
}

when you rerun application it will autometic generate file with name :

Footer.graphql.d.ts

and it is working.

3
  • getStaticProps is not wokring
    – coder
    Commented 2 days ago
  • let me add exact example here that is working in my case
    – Krushna
    Commented 2 days ago
  • can you please share why getStaticProps is not working
    – Krushna
    Commented 2 days ago
0

You are trying to use component-level data fetching in your Next JS app. You can go through these steps to get the data for a component.

  1. Write your query like this.

    export const GQL = `
      query {
        site {
         siteInfo(site: "example") {
         routes(language: "en") {
          results {
         route {
           id
         }
         routePath
        }
        total
       pageInfo {
         endCursor
        hasNext
       }
      }
     }
    }
    }
    `;
    
  2. Now use the graphQLClient to process your request. It will look like this.

    export const getStaticProps: GetStaticComponentProps = async (
       _rendering: ComponentRendering,
       layoutData: LayoutServiceData
     ) => {
     const graphQLClient = new GraphQLRequestClient(config.graphQLEndpoint, {
    apiKey: config.sitecoreApiKey,
    

    });

      let query = GQL;
    
      const res = await graphQLClient.request(query);
    
      return res;
    };
    

For more details, like if you want to pass the parameters and replace them, you can refer to my blog with video content.

https://sbhatiablogs.wordpress.com/2023/11/16/component-level-data-fetching-in-next-js/

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.