How to fetch the response of a graph ql query from next js
4 Answers
You can use GraphQLRequestClient
to make a request to GraphQL from Next.js
application.
- 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;
}
- 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;
- 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.
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!!!
-
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.– coderCommented Sep 4 at 12:00
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.
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.
Write your query like this.
export const GQL = ` query { site { siteInfo(site: "example") { routes(language: "en") { results { route { id } routePath } total pageInfo { endCursor hasNext } } } } } `;
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.