DEV Community

Anthony Weston
Anthony Weston

Posted on

How do I get a post by slug in a Next.js app using GraphQL?

The setup

I have a KeystoneJS headless CMS providing my API and I have a Next.js app for the client. In index.js I have successfully managed to return a list of posts, but I want to get the post from the API using its slug using a URL like /lingo/[slug].js.

I am using Apollo Client to talk to the API.

What I've tried

I have an apolloClient.js file in _utils with the following code:

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

export default new ApolloClient({
  uri: "http://localhost:3000/admin/api",
  cache: new InMemoryCache(),
});
Enter fullscreen mode Exit fullscreen mode

In _services/lingo.service.js I have 2 queries. The first works to return the list of posts, but the second returns Error: Response not successful: Received status code 400 and I can't figure out why?

The lingo.service.js code is:

import { gql } from "@apollo/client";
import apolloClient from "../_utils/apolloClient";

export async function getAll() {
  return apolloClient
    .query({
      query: gql`
        query {
          allTerms {
            id
            term
            slug
          }
        }
      `,
    })
    .then((result) => result.data.allTerms);
}

export async function getBySlug(slug) {
  return apolloClient
    .query({
      query: gql`
        query {
          Term(where: { slug: $slug }) {
            term
            lead
          }
        }
      `,
    })
    .then((result) => {
      console.log(result.data);
      return result.data.Term;
    });
}
Enter fullscreen mode Exit fullscreen mode

And finally, in lingo/[slug].js I have:

import Head from "next/head";
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
import { getAll, getBySlug } from "../../_services/lingo.service";

export default function Term({ term }) {
  return (
    <div>
      <Head>
        <title>Launchpad</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <h1>{term.term}</h1>
      </main>
      <footer>
        <p>{term.lead}</p>
      </footer>
    </div>
  );
}

export async function getStaticPaths() {
  const lingo = await getAll();

  const paths = lingo.map((term) => ({
    params: { id: term.slug },
  }));

  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const term = await getBySlug(params.id);

  return { props: { term } };
}
Enter fullscreen mode Exit fullscreen mode

Where am I going wrong?

Top comments (0)