In the following code, I run into the issue that I get a 400 BAD REQUEST and pageData doesn't load. When I simply remove the GridText module the code is working fine though. ChatGPT and I are running out of ideas. I hope someone can help.. I added GridText exactly as I did for the other modules, the API looks correct when I test it in the env link.
[slug].tsx
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { GraphQLClient, gql } from "graphql-request";
import NotFound from "./NotFound";
import "../styles/index.css";
import Nav from "../modules/Nav/index";
import { navigationQuery, NavigationResponse } from "../modules/Nav/fragment";
import Footer from "../modules/Footer/index";
import { footerQuery, FooterResponse } from "../modules/Footer/fragment";
import TextImage from "../modules/TextImage/index";
import {
TEXT_IMAGE_FRAGMENT,
TextImageFields,
} from "../modules/TextImage/fragment";
import Hero from "../modules/Hero/index";
import { HERO_FRAGMENT, HeroFields } from "../modules/Hero/fragment";
import GridTour from "../modules/GridTour/index";
import {
GRID_TOUR_FRAGMENT,
GridTourFields,
} from "../modules/GridTour/fragment";
import GridText from "../modules/GridText/index";
import {
GRID_TEXT_FRAGMENT,
GridTextFields,
} from "../modules/GridText/fragment";
// Define the structure of the page data
interface PageData {
title: string;
modules: Array<
{
identifier: string;
} & (TextImageFields | HeroFields | GridTourFields | GridTextFields)
>;
}
// Define the expected shape of the GraphQL response
interface GraphQLResponse {
page: PageData;
}
// Initialize the GraphQL Client with the endpoint from Vite's environment variable
const graphConnect = new GraphQLClient(import.meta.env.VITE_ENDPOINT);
// GraphQL query to fetch page data by slug
const pageQuery = gql`
query ($slug: String!) {
page(where: { slug: $slug }) {
title
modules {
...TextImageFields
...HeroFields
...GridTourFields
...GridTextFields
}
}
}
}
${TEXT_IMAGE_FRAGMENT}
${HERO_FRAGMENT}
${GRID_TOUR_FRAGMENT}
${GRID_TEXT_FRAGMENT}
`;
const Page: React.FC = () => {
const { slug } = useParams<{ slug: string }>(); // Get slug from URL params
const [pageData, setPageData] = useState<PageData | null>(null); // State to hold page data
const [navigationData, setNavigationData] =
useState<NavigationResponse | null>(null); // State for navigation data
const [footerData, setFooterData] = useState<FooterResponse | null>(null); // State for footer data
const [loading, setLoading] = useState(true); // Loading state
const [error, setError] = useState<string | null>(null); // Error state
useEffect(() => {
const fetchData = async () => {
setLoading(true); // Start loading
setError(null); // Reset error state
try {
// Fetch page data
const response = await graphConnect.request<GraphQLResponse>(
pageQuery,
{
slug,
}
);
if (!response.page) {
throw new Error(`No page found for slug: ${slug}`);
}
setPageData(response.page); // Set page data
// Fetch navigation data
const navigationResponse =
await graphConnect.request<NavigationResponse>(navigationQuery);
setNavigationData(navigationResponse);
// Fetch footer data
const footerResponse = await graphConnect.request<FooterResponse>(
footerQuery
);
setFooterData(footerResponse);
} catch (err: any) {
// Log GraphQL specific error response if available
if (err.response && err.response.errors) {
console.error("GraphQL Response Error Details:", err.response.errors);
} else {
console.error("Unexpected error:", err);
}
setError("Failed to load data."); // Set error message
} finally {
setLoading(false); // End loading
}
};
fetchData();
}, [slug]); // Run effect when slug changes
if (loading) {
return <div>Loading...</div>; // Show loading state
}
if (error) {
return <div>{error}</div>; // Show error message
}
if (!pageData) {
return <NotFound />; // Show 404 if no page data
}
return (
<>
{navigationData && <Nav data={navigationData.navigation} />}
<div className="relative top-16">
{pageData.modules.map((module) => {
if (!module.id) {
return null;
}
switch (module.identifier) {
case "TextImage":
return (
<TextImage key={module.id} data={module as TextImageFields} />
);
case "Hero":
return <Hero key={module.id} data={module as HeroFields} />;
case "GridTour":
return (
<GridTour key={module.id} data={module as GridTourFields} />
);
case "GridText":
return (
<GridText key={module.id} data={module as GridTextFields} />
);
default:
return null;
}
})}
</div>
{footerData && <Footer data={footerData.footer} />}
</>
);
};
export default Page;
GridText index.tsx
import React from "react";
interface HeadlineData {
size: string;
text: string;
}
interface GridTextProps {
data: {
headline?: HeadlineData | null;
};
}
const GridText: React.FC<GridTextProps> = ({ data }) => {
return (
<div>
<p>{data?.headline?.text}</p>
</div>
);
};
export default GridText;
GridText fragment.ts
import { gql } from "graphql-request";
export const GRID_TEXT_FRAGMENT = gql`
fragment GridTextFields on GridText {
id
identifier
headline {
size
text
}
}
`;
export interface GridTextFields {
id: string;
identifier: string;
headline: {
size: string;
text: string;
} | null;
}
This is the full error message:
Error fetching data: _ClientError: GraphQL Error (Code: 400): {"response":{"status":400,"headers":{}},"request":{"query":"\n query ($slug: String!) {\n page(where: { slug: $slug }) {\n title\n modules {\n ... on TextImage {\n ...TextImageFields\n }\n ... on Hero {\n ...HeroFields\n }\n ... on GridTour {\n ...GridTourFields\n }\n ... on GridText {\n ...GridTextFields\n }\n }\n }\n }\n \n fragment TextImageFields on TextImage {\n id\n identifier\n headline\n image {\n url\n alt\n }\n paragraph {\n text {\n html\n }\n }\n }\n\n \n fragment HeroFields on Hero {\n id\n identifier\n imageLarge {\n url\n alt\n }\n links {\n ...PagelinkFields\n ...URLFields\n }\n paragraph {\n text {\n html\n }\n }\n imageSmall {\n url\n alt\n }\n headline {\n size\n text\n }\n }\n \n fragment PagelinkFields on Pagelink {\n identifier\n id\n text\n page {\n slug\n }\n }\n\n \n fragment URLFields on URL {\n identifier\n id\n url\n text\n }\n\n\n \n fragment GridTourFields on GridTour {\n id\n identifier\n headline {\n size\n text\n }\n gridTourSection {\n id\n headline\n guidedTour {\n slug\n id\n bookingForm\n coverImage {\n url\n alt\n }\n description\n distance\n duration\n highlights\n images {\n id\n url\n alt\n width\n height\n }\n title\n }\n }\n }\n\n \n fragment GridTextFields on GridText {\n id\n identifier\n headline {\n size\n text\n }\n }\n\n","variables":{"slug":"home"}}}
at runRequest (graphql-request.js?v=51386c9c:7767:12)
at async GraphQLClient.request (graphql-request.js?v=51386c9c:7962:22)
at async fetchData ([slug].tsx:91:26)
When I look at the error message Error fetching data: _ClientError: GraphQL Error (Code: 400)
, this tells me it's a GraphQL query syntax error.
Meaning, the GraphQL query you're sending has an issue. Not sure it's related to GridText.
I would suggest to isolate the GraphQL query you're sending from your React.js code, and make sure the query is correct. The right tool for this is a GraphQL playground, e.g. if you're serving your GraphQL server with Apollo, what I'm talking about would be at this address http://localhost:4000/graphql
This will allow you to iterate on your query syntax and eliminate this as the source of the issue.