Background
As we have seen before, setting up Content Graph on the CMS side is pretty easy. However, when it comes to the “head” part of the setup, things can get a bit tricky at times. There’s a lot of ways to achieve the same results on the frontend side of things.
Note: I’m using next.js and yarn for my frontend setup. Also I’m assuming that you have a content-graph endpoint that you can query without which none of the following would be possible
Tools that we need
- vscode
- yarn/npm
Let’s start by installing the following packages
- yarn add graphql
- yarn add @graphql-codegen/cli
- yarn add @graphql-codegen/typescript
- yarn add @graphql-codegen/typescript-operations
- yarn add @graphql-codegen/typescript-react-query
- yarn add @tanstack/react-query
Once these are installed, time to setup the codegen.yaml file. The codegen.yaml file tells the system how to generate the required custom react hooks which will make our life easy when we need to make the Content Graph calls
More information on how graphql codegen works can be found here - https://the-guild.dev/graphql/codegen
After setting up the codegen.yaml file we need to add a “generate” command by modiying the package.json. Open the package.json file and under “scripts” add the following:
{
"generate": "npx gql-sdl \"https://cg.optimizely.com/content/v2?auth=${CG_SINGLE_KEY}\" && npx gql-generator --schemaFilePath ./schema.generated.graphql --destDirPath ./graphql/generated --ext graphql --depthLimit 2 && graphql-codegen -r dotenv/config",
}
The generate command above can be broken down into 3 pieces.
npx gql-sdl
This command executes the package gql-sdl and generates the schema definition in a file called schema.generated.graphql.
The contents of the file should something like this:
type Content implements IContent {
_children: QueryRef
_fulltext: [String]
_score: Float
}
npx gql-generator
This command takes the schema file generated by the previous command and then executes the gql-generator package which then generates graphql queries based on the schema definitation that was provided to it. This will create a bunch of .graphql files that contain the queries based on the schemas present in your content-graph instance:
graphql-codegen
This command takes the queries generated by the previous commands and creates custom react hooks which we can invoke and get data from without having to create queries by hand or wiring up the “fetch” calls
Using all the generated goodness
Once the setup above is done, you can run “yarn generate” or “npm run generate” to have the system generate all the graphql boilerplate code for you.
After this you can start fetching the content from content-graph in your frontend application (I’m using next.js so I’ve just created a test page that fetches the content).
If you have a BlogItemPage type defined in your cms then the corresponsing react-hook function to use would be useBlogItemPageQuery. Here’s an example list of how the CMS types map to custom react hooks:
Type in CMS | custom react-hook name in frontend |
---|---|
AdaptiveHeroBlock | useAdaptiveHeroBlockQuery() |
AdaptiveImage | useAdaptiveImageQuery() |
HeroBlock | useHeroBlockQuery() |
Normally the pattern is use{Type-In-Cms}Query()
import {useBlogItemPageQuery, Locales} from "@/generated";
export default function Test() {
const data = useBlogItemPageQuery({
locale: Locales.En,
});
return (
<>
{data &&
<ul className={"m-10 list-disc"}>
{data?.data?.BlogItemPage.items.map((content) => {
return <li className={"text-4xl text-gray-700 font-mono italic m-3"}
key={content.Name}>{content.Name}</li>
})}
</ul>
}
</>
);
}
You are also able to pass in other variables (without touching the generated graphql queries) like limit and where which gives you granular control on the data that you can fetch and filter
import {
useBlogItemPageQuery,
Locales,
} from "@/generated";
export default function Test() {
const data = useBlogItemPageQuery({
locale: Locales.En,
where: {
_fulltext: {contains: "awesome"}
},
limit: 2
});
return (
<>
{data &&
<ul className={"m-10 list-disc"}>
{data?.data?.BlogItemPage.items.map((content) => {
return <li className={"text-4xl text-gray-700 font-mono italic m-3"}
key={content.Name}>{content.Name}</li>
})}
</ul>
}
</>
);
}
Conclusion
Hopefully this post gives you a good idea on how you can connect your frontend with content-graph and leverage automatic generation of most of the boilerplate code for GraphQL queries.
If you want custom graphql queries then you can do that as well.
As long as the queries are placed in the folder configured in the codegen.yml file the custom react hook for them will be automatically generated.
References
- https://github.com/jkmartindale/gql-sdl
- https://github.com/timqian/gql-generator
- https://the-guild.dev/graphql/codegen
- https://tanstack.com/query/latest/docs/react/overview
- https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs
- https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs/tutorial-create-a-site-with-strongly-typed-music-festival-content-using-react-and-content-graph