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:
- Install packages
- Add endpoint to the
api
directory - Connect the Apollo Server to the database
- Update the resolvers
- 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.
>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
Thanks for the suggestion, Cory! Showing how to use Apollo Client and a code generator would be a great next step.
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.
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.
Thanks for catching the code formatting errors. Fixed!
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()?