Implementing GraphQL with NextJS

Implementing GraphQL with NextJS

NextJS can make your website blazing fast. Thanks to the server side rendering, website of your single-page app is preloaded. However, despite being built on React, NextJS has some differences that make integrating GraphQL an unique challenge. I had a very hard time finding a tutorial like that so I decided to write one on my own. We'll explore First, let's create our next app:

npx create-next-app

Give your app a name. We'll be running in a development environment with

npm run dev

Enter the project folder:

cd MyApp

Install the packages

npm install apollo-server-micro graphql apollo-boost graphql-tag @apollo/react-hooks

Backend

Inside the 'pages/api' create a file named 'graphql.js'. We'll create an apollo server on this endpont (NextJS will make an endpoint on 'api/graphql' for this server).

Let's define the type for query:

import { ApolloServer, gql } from "apollo-server-micro";

const typeDefs = gql`
  type Query {
    user: String,
    email: String
  }
`;

Now, let's create resolvers with dummy data. In another post we'll replace this with mongoose resolvers:

const test_user = 'jaguar'
const test_email = 'jaguar@gmail.com'

const resolvers = {
    Query: {
      user: () => test_user,
      email: () => test_email,
    },
  };

Let's run the Apollo Server:

const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: () => {
    return {};
  }
});

const handler = apolloServer.createHandler({ path: "/api/graphql" });

Also make sure that this API route is not parsed and interpreted by NextJS. It has to be interpreted by the Apollo Server: nextjs.org/docs/api-routes/api-middlewares#.. Add the configuration:

export const config = {
  api: {
    bodyParser: false
  }
};

The whole graphql.js file is now:

import { ApolloServer, gql } from "apollo-server-micro";

const typeDefs = gql`
  type Query {
    user: String,
    email: String
  }
`;

const test_user = 'jaguar'
const test_email = 'jaguar@gmail.com'

const resolvers = {
    Query: {
      user: () => test_user,
      email: () => test_email,
    },
  };

const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: () => {
    return {};
  }
});

const handler = apolloServer.createHandler({ path: "/api/graphql" });

export const config = {
  api: {
    bodyParser: false
  }
};

export default handler;

Frontend

In the 'pages/_app.js' import the Apollo Client and react hook:

import ApolloClient from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks';

point the Apollo Client instance to the Apollo Server:

const client = new ApolloClient({
  uri: 'http://localhost:3000/api/graphql'
});

And add Apollo Provider wrapper for the Component:

function MyApp({ Component, pageProps }) {

  return <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
}

So the whole '_app.js' file is:

import '../styles/globals.css'
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks';

const client = new ApolloClient({
  uri: 'http://localhost:3000/api/graphql'
});
function MyApp({ Component, pageProps }) {

  return <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
}

export default MyApp

Now let's use the data inside the 'index.js' file. First, let's import the GraphQL query parser and useQuery hook:

import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';

Inside the 'Home' function we'll be resolving a query:

  const USER_QUERY = gql`
    {
      user
      email
    }
  `;
  const { loading, error, data } = useQuery(USER_QUERY);
  if (loading) {
    return <p>Loading...</p>;
  }
  if (error) {
    console.log(error)
    return <p>Error :(</p>;
  }

So we can use it inside 'main' component:

            <p>
              User is: {data.user}
            </p>
            <p>
              Email is: {data.email}
            </p>

Finally, the whole 'index.js' file is:

import Head from 'next/head'
import styles from '../styles/Home.module.css'
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';

export default function Home() {
  const USER_QUERY = gql`
    {
      user
      email
    }
  `;
  const { loading, error, data } = useQuery(USER_QUERY);
  if (loading) {
    return <p>Loading...</p>;
  }
  if (error) {
    console.log(error)
    return <p>Error :(</p>;
  } 
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App with GraphQL</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
            <div className="App">
          <header className="App-header">
            <p>
              User is: {data.user}
            </p>
            <p>
              Email is: {data.email}
            </p>
          </header>
        </div>

      </main>
      <footer className={styles.footer}>
      </footer>
    </div>
  )
}

Let's check the browser at 'localhost:3000/'. You should see:

image.png

Voila! We successfully integrated GraphQL with NextJS. Next - integrating mongoose.

Let the good times roll!