Quick Next.js + GraphQL Integration via API Routes

This is a quick guide to getting a lightweight GraphQL server via API route in a Next.js app. This is not a detailed tutorial of how to create a beautiful, semantic GraphQL and Next.js toolkit.

Where we’re starting: A basic Next.js app with a Postgres database.

Where we’re going: A request to an api/graphql endpoint that gets real data back.

How we’re getting there:

  1. Install packages
  2. Add endpoint to the api directory
  3. Connect the Apollo Server to the database
  4. Update the resolvers
  5. Make a request and get that data

1. Install Packages

We’ll start simple and use the Apollo’s micro-service. It will give us everything we need for a lightweight server.

Run yarn add apollo-server-micro graphql.

2. Add an Endpoint in the api Directory

Building from the example that Next.js supplies, add a file in pages/api/ for the graphql endpoint.

// pages/api/graphql.ts
import { ApolloServer, gql } from 'apollo-server-micro'

const typeDefs = gql`
  type Query {
    users: [User!]!
  }
  type User {
    id: Int!
    firstName: String
  }
`

const resolvers = {
  Query: {
    users(parent, args, context) {
      return [{ firstName: 'Nextjs' }]
    },
  },
}

const apolloServer = new ApolloServer({ typeDefs, resolvers })

export default apolloServer.createHandler({ path: '/api/graphql' })

We want to make sure that the Apollo Server is parsing the request body rather than Next.js. In pages/api/graphql, add:

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

The Next.js doc have more about the Next.js API middleware.

3. Connect the Apollo Server to the Database

Next, let’s get real data by accessing the database from the resolver. When the Apollo Server is initialized, we can pass it a database connection directly or through a context.

For the sake of simplicity, we can get a database instance right in our GraphQL endpoint.

import knex from "knex";

const db = knex({
  client: "postgres",
  connection: {
    host: process.env.POSTGRES_HOST,
    user: process.env.POSTGRES_USER,
    password: process.env.POSTGRES_PASSWORD,
    database: process.env.POSTGRES_DB
  }
});

Now replace the server initialization with something like this:

const apolloServer = new ApolloServer({ typeDefs, resolvers, context => { db })

In practice, the database should likely be stored in a context with other tooling for the server. In that case, we can pass the whole context to the resolvers using the same means.

4. Update the resolvers

Now it’s time to make the resolvers return real data from the database. Using the connection we passed in, we can now query for the users.

const resolvers = {
  Query: {
    users(parent, args, { db }) {
      return db.select("*").from("users")
    },
  },
}

5. Make a request and get that data

The last step is making a query in the client and displaying data. We can make a request to the GraphQL endpoint in the getInitialProps for a page.

import * as React from "react";
import axios from "axios";
import { gql } from "apollo-server-micro";

interface IndexPageProps {
  users?: any;
}
const Index = ({ users }) => <>{JSON.stringify(users)}</>;

const getUser = gql`
  query {
    user {
      id
      firstName
    }
  }
`;

Index.getInitialProps = wrapWithPageContext(async () => {
  try {
    const response = await axios.post("http://localhost:3000/api/graphql", {
      query: getUsers
    });

    return { users: response.data };
  } catch (error) {
    return {};
  }
});

export default Index;

Made it! We are now successfully using GraphQL and Apollo via the Next.js API routes. We could make this cleaner by, for example, pulling in Apollo Client for helpful hooks on the client or using a code generator to have Typescript types that describe the GraphQL schema.

Conversation
  • Cory says:

    >We could make this cleaner by, for example, pulling in Apollo Client for helpful hooks on the client or using a code generator to have Typescript types that describe the GraphQL schema.

    Would love to see this + GraphQL playground. o_o

    • Meredith Lind Meredith Lind says:

      Thanks for the suggestion, Cory! Showing how to use Apollo Client and a code generator would be a great next step.

  • Alexander says:

    Also you should use `apollo-link-schema` instead of http-links, because you’re using Next’s API routes, http requests are redundant in your case.

  • Steven Kalt says:

    For the webmaster: I’m seeing html escaping displayed within the code blocks of this blog post (specifically, `=>` is getting displayed as `() =>`). I suspect this is a build error.

    • Meredith Lind Meredith Lind says:

      Thanks for catching the code formatting errors. Fixed!

  • deh3nne says:

    Hi! I have the problem that the database connection is never closed and remains open. For each request, I get a new database and after a while, the first limits are reached.

    What is the correct point to call something like db.close()?

  • Comments are closed.