DEV Community

Cover image for Connecting GraphCMS and Next.js: Finding A CMS Part 3
James 'Dante' Midzi
James 'Dante' Midzi

Posted on

Connecting GraphCMS and Next.js: Finding A CMS Part 3

In this third part, we take a look at another headless CMS I found whilst doing my research - GraphCMS

When I did my exploration of Contentful with Next, I intentionally didn't use their GraphQL API.

GraphCMS is one of the reasons I didn't use Contentful's. Why?

For starters, GraphCMS's API is superior to Contentful's given that it's built initially with GraphQL in mind - it wasn't an afterthought.

Secondly, GraphCMS assists you by constructing the queries you will use with just a few clicks.


What is GraphCMS?

I've been going on singing praises of GraphCMS, but what is it?

GraphCMS is an API-first Headless CMS that allows you to instantly build GraphQL Content APIs, which you can deliver to various platforms. It also offers several options for working with the APIs you create.

Here is what they say:

GraphCMS gives you instant GraphQL Content APIs to create, enrich, unify, and deliver your content across platforms.

  • Build your production-ready Content API within minutes
  • Remote data fetching to federate content from external sources
  • Leading GraphQL APIs for Querying, Mutations, and Assets

MORE HOUSEKEEPING

Again, this is a proof of concept article. I am not explaining every single thing - this is also not a beginner walkthrough. I will gladly explain further if you ask me to.

Also, I did not show screenshots of the pulled data rendered in the Next app, you have already seen those. There is no point in showing them again. This article if you want to see them Sanity and NextJS

Just like before we are going to get everything in GraphCMS ready first.


Setup GraphCMS

Let's head over to GraphCMS and create an account. Or log in if you already have one.

We will then create a Blank Project

new.png

GraphCMS has a Blog project example but we are going to go through each step ourselves.

  • We'll give our project a name, select a server closest to use and click Create Project.
  • On the next page, we will choose the free plan, it's more than enough for what we want to do

We are then prompted to invite members, we'll skip this for now. I'll show you where it is later.

We are then taken to our project home with some things they suggest we do. We will follow the steps...

home.png

The left bar is how you navigate around your project.

Create Schemas

We will make an Author and Post schema just like we did in Contentful and NextJS: Finding A CMS Part 2

Either select "Set up your schema" or the Schema icon in the bar.

model.png

My screen might look a little bit different from yours, but that's okay.

Choose Create model and call it Author. We will then add these fields to that model:

author.png

Then create a Post model with these fields:

post.png

Note

Modify the slug field so that it is generated automatically from the title.

slug.png

The last field we need for the Post is a reference to the Author model

ref.png

Create Content

Now we switch to the Content section - create an Author and a couple of posts

content.png

Explore API

For the fun part. We'll switch to the API playground section. While here we can build our queries and run mutations (changes or additions) to the API we made.

playground.png

You could choose to build the queries yourself, or in our case, we will use the explorer to get our post data.

myPostsQuery.png

We can save our queries in the left bar, we'll do that with our post query as we'll need it later

I advise you to spend some time in the playground and figure out what kind of queries and mutations you can make.

Single Post Query

While we're here, let's also create the query for the single post as well.

single post.png

Short Explanation of Graphql

To get the post with the slug that matches, we pass the where parameter with the value we want to match.

To be able to use the query in our code, we then use GraphQL variables $slug

  • query getSinglePost($slug: String!): In this line, we create our query and specify that it takes a variable $slug of type String and it is required
  • post(where: { slug: $slug }): Then in this line, we specify that we want to rerun a post where the slug is equal to the slug variable we passed to it

Victoria Lo has a whole series dedicated to GraphQL you can check out

Or use this link to learn more about GraphQL

Generate Key

As with our other showcases, we will need a key to connect to our GraphCMS project fto Next.js

Switch to the Project Settings section and then API access

api.png

The one we need is the Content API. Copy it and save it to a text file.

Then scroll down the page and select the "Yes, initialise defaults" option
defaults.png

With that done, we can move on to Next.js


Setup Next.js

Just like last time we need my starter. Clone it:

git clone https://github.com/Psypher1/next-cms-starter.git
Enter fullscreen mode Exit fullscreen mode

Navigate into it and install the dependencies:

cd next-cms-starter

npm install
Enter fullscreen mode Exit fullscreen mode

Additional Dependencies

There are a couple of extra dependencies we will need to work with GraphQL and render rich text. Let's install them.

To work with GraphQL:

npm i graphhql graphql-request
Enter fullscreen mode Exit fullscreen mode

To render rich text:

npm i @graphcms/rich-text-react-renderer
Enter fullscreen mode Exit fullscreen mode

Setup env

Let's get our env stuff out of the way.

In the root of the project, create a file called .env, and paste the content key we got into it:

 GRAPHCMS_ENDPOINT=
Enter fullscreen mode Exit fullscreen mode

Then also in the root, make a folder called services and in it a file called index.js.
This is where we will store our queries

// ...services/index.js
import { GraphQLClient, gql } from "graphql-request";

const graphcms = new GraphQLClient(process.env.GRAPHCMS_ENDPOINT);
Enter fullscreen mode Exit fullscreen mode

The query for all posts:

export async function getAllPost() {
  const query = gql`
    {
      postsConnection {
        edges {
          node {
            id
            title
            slug
            excerpt
            createdAt
            image {
              url
            }
            author {
              name
              photo {
                url
              }
            }
            body {
              raw
            }
          }
        }
      }
    }
  `;

  const results = await graphcms.request(query);
  return results.postsConnection.edges;
}
Enter fullscreen mode Exit fullscreen mode

Single Post Query

export async function getSinglePost(slug) {
  const query = gql`
    query getSinglePost($slug: String!) {
      post(where: { slug: $slug }) {
        id
        title
        slug
        excerpt
        createdAt
        image {
          url
        }
        author {
          name
          photo {
            url
          }
        }
        body {
          raw
        }
      }
    }
  `;

  const results = await graphcms.request(query, { slug });
  return results.post;
}
Enter fullscreen mode Exit fullscreen mode

NOTE: raw is deprecated now. So when you make the fetch for rich text, use json instead.

Load Post Onto Blog Home

Now let's move to ..pages/blog/index.js and let's render the list of our posts there

First import our query

// ...pages/blog/index.js

import { getAllPosts } from "../../services";

//  fetch  our posts
export async function getStaticProps() {
  const posts = (await getAllPosts()) || [];

  return {
    props: { posts },
  };
}
Enter fullscreen mode Exit fullscreen mode

We use getStaticPros to fetch our post, return props from it and pass those to our component

Render the list of posts:

//  ...pages/blog/index.js

export default function Blog({posts}){

    return {
        <div>
            {posts && posts.map(post =>(
                <div key={post.id}>
                    <Link href={`/blog/${post.node.slug}`}>
                        <a>{post.node.title}</a>
                    </LInk>
                    <img src={post.node.image.url}>
                </div>
            ))}
        </div>
    }

Enter fullscreen mode Exit fullscreen mode

Render Detail Page

We can now move on to the detail page. Let's open ...pages/blog/[slug].js and add this code to it

Let's import our functions and the additional package we installed:

// pages/blog/[slug].js 

import { getAllPosts, getSinglePost } from "../../services";
import { RichText } from "@graphcms/rich-text-react-renderer";
Enter fullscreen mode Exit fullscreen mode

To render a detail page in Next.js we need two functions that work in tandem:

// we use this function to tell Nextjs how many paths to pre render
export async function getStaticPaths() {
  const posts = (await getAllPosts()) || [];

   //map through the post slugs and return them as params
  const paths = posts.map(({ node: { slug } }) => ({ params: { slug } }));

  return {
    paths,
    fallback: false,
  };
}

// this function is rsponsible for fetching the individual post data
export async function getStaticProps({ params }) {
  const data = await getSinglePost(params.slug);

  return {
    props: { post: data },
  };
}
Enter fullscreen mode Exit fullscreen mode

Render the detail page:

// load post data onto page
export default function PostDetail({ post }) {

    return(
      <div>
        <h2>{post.title}</h2>
        <img src={post.image.url} alt={post.title} />

        // author info
         <div>
            <p>{post.author.name}</p>
        </div>
        // post body
         <hr />
        <div >
            {/* use the package to render post body*/}
             <RichText content={post.body.raw.children} />
        </div>

        // useful links
        <hr />
        <br />
        <div >
           <Link href="/blog">
                 <a> {"<Back to Blog"}</a>
           </Link>
           <Link href="/">
             <a > {"<Home"}</a>
          </Link>
       </div>
    </div>
    )
}

Enter fullscreen mode Exit fullscreen mode

And there we go! We've created a schema and content, and made queries to fetch our content. We've used those queries to render data on our Next.js site both in list and detail format.


Other GraphCMS features

  1. To add team members to your project, go to Project settings in your project home and chose Team members
  2. When we were creating our Models there were other things there, namely:
    1. Components
    2. Enumerations
    3. Remote Sources

Components

Components are new to GraphCMS, released on the 29th of March. I'll let the team tell you about them:

Breeze through content creation with components! Move away from rigid content structures to start experiencing cleaner schemas, flexible content models, and intuitive content operations with reusable content templates.

Enumerations

These are for lists of items you want to use in a content model. That's how I understand them

Remote Sources

This is a feature that we are still testing. In essence, you would be able to use data from other sources in your GraphCMS project (I am writing a more detailed article about it.)


Scoring

So how did GraphCMS do? Let's find out, shall we ...

1. Ease of Use

For me

GraphCMS is straightforward enough for me to use. I see myself using more of it in the future.

For user

There was a little bit of friction when I asked a user to add content, but after a bit of explanation, they were able to get around quite well.

2. How Well Data Can Be Queried

Of the Headless CMS I have tested so far, GraphCMS is the most efficient at querying data. Owing to the fact that it has a seamless approach to building your queries.

3. Ease of Integration with Next

I have had the good fortune of testing Headless CMS that play well with my Next.js. I am very happy about that

4. Time Taken To Production

No time at all, you publish, it's live.

5. Support/Community

The GraphCMS slack is the place to go with all your questions and queries.

6. Ease of Deployment

No deployment required. Once you publish your content, it is ready to be consumed. Your choice of frontend is what remains.

Conclusion

I enjoy working with GraphCMS. So much so that I am using it as the backend for my new portfolio site. I like that have a deeper level of access to my data.


Thank you for coming along with me on this exploration. If you have any questions, please leave a comment. If you noticed a mistake kindly let me know.


Thank you for reading, let's connect!

Thank you for visiting this little corner of mine. Let's connect on Twitter, Polywork and LinkedIn

Top comments (6)

Collapse
 
chipuikasar profile image
Chipui Kasar • Edited

Hi, Please help,
Whenever I add new post in graph cms it shows up in my page but I can't view the post details.
It will work only if I Push my code in github again.
tengkuma.vercel.app/blog
Url :

Collapse
 
psypher1 profile image
James 'Dante' Midzi

Hey ... Sorry for not getting back to you sooner.

If I understand you correctly: when you add a post on Graphcms, you can't see the details of it unless you push to GitHub?

Follow up questions:
Is this in a deployed site?
Can I have a look at your code?

Collapse
 
chipuikasar profile image
Chipui Kasar • Edited

Yes, exactly.
But somehow I've manage to solve the issue
`export async function getStaticPaths() {
const { posts } = await graphcms.request(SLUGLIST);

return {
paths: posts.map((post: any) => ({ params: { slug: post.slug } })),
fallback: "blocking",
};
}`
In the fallback previously i used false, after changing it to 'blocking' it works,
I don't know if this is the correct solution for this or not

Thread Thread
 
psypher1 profile image
James 'Dante' Midzi

Oh? That's brilliant! I'm glad you found a solution.

You arrived at one of the confusing things about Next.js.
Basically, the fallback you end up using is more about how you want your data to be rendered and how frequently you want it updated.

So in your case, I think that's the right approach

Collapse
 
eliaskibret profile image
Elias-Kibret

You saved my time , thank you

Collapse
 
psypher1 profile image
James 'Dante' Midzi

Of courses, I'm glad I could help :)