Next 12 Quick start guide

Estimated duration: 10 minutes

This is a quick integration guide to connect Prepr to a Next project and fetch data from Prepr CMS.

Introduction

This guide is based on Next.js version 12. In this guide, you’ll learn how to build a simple blog with Next and Prepr CMS. When you reach the end of this guide, you'll have a working app that looks something like the image below.

blog site end result

Note

This guide is to get your app up and running with Prepr quickly so styling is not included. Visit our demo website to see a styled example of the Blog.

Prerequisites

You need to have the following setup before you connect your Next.js project to Prepr.

Note

Step 1: Create a new Next.js project

The instructions below will guide you on how to create an empty Next.js project for your blog app.

Install Next.js

You can skip this step if you have an existing Next project (version 12 or earlier).

  1. Open a terminal and execute the following command to create a new Next project called prepr-next:
npx create-next-app@12 prepr-next && npm i next@12
  1. Now that the project is successfully created, go to the prepr-next folder, the root directory of the project, and execute the following command in the terminal:
npm run dev
  1. You should now be able to view your app on your localhost, for example, http://localhost:3000/.

  2. Open your project with your preferred code editor.

  3. Update the index.js file in the pages folder with the following code to display your blog:

//  ./pages/index.js 

function Home() {
  return (
    <div>
      <h1>My home page</h1>
    </div>
  );
}

export default Home;

You should now see something like the image below on your localhost.

view component

Step 2: Install the Apollo client

The Apollo client is an integration tool that helps to retrieve CMS data with GraphQL. The instructions below show you how to install the Apollo client so that you can add GraphQL queries to request data from the Prepr API.

  1. Stop the server you started in the above step (CTRL-C) and execute the following command in the terminal:
npm install @apollo/client graphql
  1. Create a services folder in the root directory of the project. Then, create a file called apollo-client.js in this folder. Copy the following code to this file to import and initialize the Apollo client:
// ./services/apollo-client.js

import { ApolloClient, InMemoryCache } from "@apollo/client";

const client = new ApolloClient({
    uri: `https://graphql.prepr.io/${process.env.PREPR_ACCESS_TOKEN}`,
    cache: new InMemoryCache(),
});

export default client;

This client will be used to make API requests to endpoints provided by the Prepr CMS across your Next application.

  1. Get an access token by logging into your Prepr account:

a. Go to Settings > Access tokens to view all the access tokens. b. Copy the GraphQL Production access token to only retrieve published content items on your site.

access token

Note

Use the GraphQL Production access token to request published content items for your live app and use the GraphQL Preview token to make a preview of unpublished content items for your content editors.

We recommend using environment variables to store sensitive information like access tokens.

  1. To add environment variables, create a .env file in the root directory of your project and add the access token like this:
# ./.env

PREPR_ACCESS_TOKEN=<YOUR-ACCESS-TOKEN>
  1. Execute the following commands to make sure that the Apollo client is installed correctly:
npm install
npm run dev

If your app runs without errors, then the setup above was done correctly. The next step is to fetch content from Prepr using the installed Apollo client.

Step 3: Fetch multiple articles

Now that your Apollo client is installed and connected to Prepr, let's fetch the blog articles from Prepr.

Add a GraphQL query

  1. Create a queries directory in the root directory of your project and create a file named get-articles.js.

  2. Add the following query to this file to retrieve all articles:

// ./queries/get-articles.js

import { gql } from "@apollo/client";

export const GetArticles = gql`
  query {
    Articles {
    items {
      _id
      _slug
      title
    }
  }
 }
`

Tip

You can create and test GraphQL queries using the Apollo explorer from Prepr. Open the API Explorer from the Article content item page in Prepr or the access token page.

If you’re using preloaded demo data in your CMS environment as mentioned above in the Prerequisites section, you should have a few published articles. The query will retrieve the id, slug, and title of the articles.

The JSON response to the query looks like this:

{
  "data": {
    "Articles": {
      "items": [
        {
          "_id": "a1fa4389-25ca-429e-908b-e5d85d1f9d4a",
          "_slug": "say-quiche",
          "title": "Say quiche!"
        },
        {
          "_id": "cd398f61-0557-4ddb-b2e8-9af0233cee7a",
          "_slug": "ole-ole-souffle",
          "title": "Olé olé soufflé"
        },
        {
          "_id": "87d264af-9481-4e31-b042-70794730602c",
          "_slug": "excuse-my-french-toast",
          "title": "Excuse my french toast"
        }
      ]
    }
  }
}

In the next step, we'll fetch and process this response.

Fetch data

Now that the query has been added, let's fetch the articles from Prepr and display them in the app.

  1. Open the index.js file in the pages folder and replace the content with the code below to display the data retrieved from the query.

If you need to render your site statically, copy the code under the SSG tab. Check out the rendering strategies doc for more details.

// ./pages/index.js

import { GetArticles } from "../queries/get-articles";
import client from "../services/apollo-client";

function Home({ articles }) {
  return (
    <div>
      <h1>My blog site</h1>
      <ul>
        {articles.map((article) => (

          //List the fetched articles
          <li key={article._id}>
            {article.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default Home;
 
// Function for server-side rendered app
// Articles are retrieved when the the page is opened

export async function getServerSideProps(context) {

  // Run GetArticles query using apollo client
  const { data } = await client.query({
    query: GetArticles,
  })
  const articles = data.Articles.items

  // Pass Articles as props to the visited page
  return {
    props: { articles },
  };
}
// ./pages/index.js

import { GetArticles } from "../queries/get-articles";
import client from "../services/apollo-client";

function Home({ articles }) {
  return (
    <div>
      <h1>My blog site</h1>
      <ul>
        {articles.map((article) => (

          //List the fetched articles
          <li key={article._id}>
            {article.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default Home;

// Specific function for static site generation and ISR
// All articles are retrieved when the site is deployed

export async function getStaticProps(context) {

  // Run GetArticles query using apollo client
  const { data } = await client.query({
    query: GetArticles,
  })
  const articles = data.Articles.items

  // Pass Articles as props to the visited page
  return {
    props: { articles },
  };
}

Now when you view the website on your localhost, you'll see something like the image below.

Local

Step 4: Fetch individual articles

Now that we have the list of articles, we want to add links to them. When a visitor clicks on a link, your app should open a detailed article page automatically. The instructions below show you how to set up the routing from the main page to the detailed page and how to fetch the article details based on the slug of the article that was clicked.

Let's first add links to the articles.

  1. Update the index.js file to include a link tag on each article title as shown in the code below.
// ./pages/index.js

import { GetArticles } from "../queries/get-articles";
import client from "../services/apollo-client";

//Import next links to enable linking 
import Link from "next/link";

function Home({ articles }) {
  return (
    <div>
      <h1>My blog site</h1>
      <ul>
        {articles.map((article) => (

          //Add link to each article in the list
          <li key={article._id}>
            <Link href={`${article._slug}`}>{article.title}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

Now when you view the app, each article has its own link. When you click on the link, a new page opens with the slug in the URL, but a Page 404 error is displayed. Let's continue with the next step to fetch the article details and resolve this error.

Fetch article details

Let's add another query to fetch a specific article by its slug and make this page visible when clicking on an article.

  1. Create a file called get-article-by-slug.js in the queries folder and add the following to query a specific article by its slug:
// ./queries/get-article-by-slug.js

import { gql } from "@apollo/client";

export const GetArticleDetail = gql`
query ($slug: String) {
   Article (slug: $slug) {
     _id
     title
     content {
       __typename
       ... on Text {
         body
         text
       }
       ... on Assets {
         items {
           url
         }
       }
     }
   }
}`

Now that the query is added, let's fetch the individual article by its slug. We want to fetch the article title and the article content.

Note

  1. Open the pages folder and create a file [slug].js file with the following code:
// ./pages/[slug].js

import { GetArticleDetail } from "../queries/get-article-by-slug";
import client from "../services/apollo-client";

export default function Article({ article }) {
    return (
      <>
        <h1>
          { article.title }
        </h1>

        {/* Loop through content types in article content */}
   
        {article.content.map((contentType) => {

          //Display image if it exists
            if (contentType.__typename === 'Assets' && contentType.items.length) {
              return (
                <div className="my-10">
                  <img
                    src={contentType.items[0]?.url}
                    width="300"
                    height="250"
                  />
                </div>
              )
            }

            //Display text as HTML
  
            if (contentType.__typename === 'Text') {
              return (
                <div dangerouslySetInnerHTML={{ __html: contentType.body }}></div>
              )
            }
          })}
      </>
    )
  }
  
  export async function getServerSideProps({ params }) {

    // Get the slug in the URL
    const { slug } = params;
  
    // Request an article by the slug
    const { data } = await client.query({
      query: GetArticleDetail,
      variables: {
        slug,
      },
    });
  
  // Pass Article data as props to the visited page
    return {
      props: {
        article: data.Article,
      }, 
    };
  }
// ./pages/[slug].js

import { GetArticles } from "../queries/get-articles";
import { GetArticleDetail } from "../queries/get-article-by-slug";
import client from "../services/apollo-client";

export default function Article({ article }) {
    return (
      <>
        <h1 >
          { article.title }
        </h1>
  
        {article.content.map((contentType) => {
            if (contentType.__typename === 'Assets' && contentType.items.length) {
              return (
                <div className="my-10">
                  <img
                    src={contentType.items[0]?.url}
                    width="300"
                    height="250"
                  />
                </div>
              )
            }
  
            if (contentType.__typename === 'Text') {
              return (
                <div dangerouslySetInnerHTML={{ __html: contentType.body }}></div>
              )
            }
          })}
      </>
    )
  }
  
//Get all article slugs at deployment for static site
export async function getStaticPaths() {
    const { data } = await client.query({
      query: GetArticles,
    })
    return {
      paths: data.Articles.items.map((article, index) => {
        const slug = String(article._slug)
        return {
          params: { slug },
        }
      }),
      fallback: false,
    }
  }
  
  export async function getStaticProps({ params }) {

    // Get the slug from the retrieved articles
    const { slug } = params;
  
    // Request an article by the slug
    const { data } = await client.query({
      query: GetArticleDetail,
      variables: {
        slug,
      },
    });
  
    // Pass Article data as props to the visited page
    return {
      props: {
        article: data.Article,
      }, 
    };
  }

Now, when you view your site, you can click on an article which will direct you to that specific article like in the image below.

article detail

All done

Congratulations! You have successfully connected a Next project to Prepr for a simple Blog app.

Next steps

To learn more on how to expand your project, check out the following resources: