GraphQLNext.js
Last updated at 2023-08-30

Create an Apollo Server GraphQL in Serverless Typescript Next.js

ClickUp
Note
AI Status
Last Edit By
Last edited time
Aug 30, 2023 12:42 AM
Metatag
Slug
graphql-nextjs-api-apollo-tutorial-typescript
Writer
Published
Published
Date
Aug 25, 2023
Category
GraphQL
Next.js
So, you have a Next.js TypeScript project that needs to expose an API for your clients to consume. You don't want to provide a REST API for some reason. Then, welcome to GraphQL!
🥸
If you are a seasoned developer, you can jump to the code if you want.

Can I Serve GraphQL Endpoint in Next.js?

Expose GraphQL using Next.js API Router

The Next.js API router can provide a good start to building a GraphQL API. To build GraphQL API using Apollo Server in Next.js, you can install @apollo/server, @as-integrations/next, and graphql-tag library and provide schema and type definitions. Wire up those tools, and you can start consuming the API right away using the single /api/graphql endpoint.
In this tutorial article, you will learn how to build a Typescript based Apollo GraphQL server that acts as your API endpoint using the Next.js API Router.

Host GraphQL using Vercel Edge Functions

The best thing about Next.js is that your GraphQL endpoint will be served from Edge Functions by Vercel if you host the application on their platform.
You will learn quickly in this article. So read on!

What Will You Learn in this Tutorial?

In this article, you will learn how to build a GraphQL API in your Next.js project that clients can consume.

What Are You Building?

Nowadays, people still read blog articles, just like you're doing now. There are many reasons for this, of course.
A good blog provides mechanisms for the client app to fetch all blogs, get blog details, query blogs by title, and favorite a blog post. Like Mozzlog 😁.
The post contains a title, cover image, categories, last modification timestamp, number of reads, and content.

List of Topics That You Will Cover

You will cover the following topics:
  1. Prerequisites
  1. Setting up the schema
  1. Fake Initial Data
  1. Preparing Resolvers
  1. Setting up the Server
  1. Exposing GraphQL to the World
  1. Use cURL to Test the Live GraphQL Endpoint
  1. Performing Mutations
  1. Sandbox Test
Yes, you will end up with a sandbox test so that you can test the API via the browser without spinning up another GraphQL client application.
😀
A Sandbox Test makes testing GraphQL endpoints easier. Wouldn’t you want to help your client try your endpoint? It can make adoption faster.
Let's get to work. Are you ready to build a blog's GraphQL API?

Prerequisites

This article assumes that you are seasoned or have experience with Next.js. Therefore, you won't need to read about how to set up a Next.js project.
Of course, you'll need a running Next.js project. Just ensure that you have TypeScript set up because you will use the language to build the GraphQL API.
This project will use Apollo GraphQL. To install the dependencies, you can use this command:
npm install @apollo/server @as-integrations/next graphql-tag
You will use @apollo/server to serve your GraphQL resolver and schema, while @as-integrations/next will provide functions to serve your ApolloServer in Next.js. The @graphql/tag role is to write the schema of your GraphQL query.

Setting Up The Schema

First, you need to build a schema for the Blog GraphQL API. The schema should address the questions you want to answer with the API.
  1. Clients want to see a list of blog posts.
  1. Clients want to query a blog by its title.
  1. Clients want to mark a post as a favorite.
  1. Clients want to view the details of a blog post.
You need to define the schema and resolvers in variables. You can start by defining the Post type.

Post Type GraphQL Schema

type Post { id: ID! slug: String! title: String! categories: [String!]! cover: String lastUpdatedAt: Float! isFavorite: Bool content: String! }
The fields you can include in your Post type are id, slug, title, categories, cover, lastUpdatedAt, and content.

Query Type GraphQL Schema

type Query { getPost(id: ID!): Post getPostsByTitle(query: String): [Post!]! getAllPosts: [Post!]! }
The fields you can include in your Query type are getPost, which accepts the id parameter, and getAllPosts, which returns all Post objects.
That's it. Creating a GraphQL type is easy. Now, let's put those types in a variable called schemaDefinitions.

Create schemaDefinitions

import { gql } from 'graphql-tag'; const schemaDefinitions: DocumentNode = gql` type Post { id: ID! slug: String! title: String! categories: [String!]! cover: String date: String! published: Boolean! lastEditedAt: Int! isFavorite: Bool content: String! } type Query { getPost(id: ID!): Post getPostsByTitle(query: String): [Post!]! getAllPosts: [Post!]! } `;
In the above code, the gql function will convert our string into a DocumentNode instance.
You can omit the explicit type annotation from schemaDefinitions if you want. TypeScript will infer the type from the gql return type.

Fake Initial Data

In this project, you won't be reading from a database. That will be covered in another article, where you'll read from databases like Postgres, MongoDB, or Redis.
You also won't be reading from a .json file, as that would be another topic involving serialization, deserialization, and saving to a file in TypeScript. However, if you need that, you can refer to this article.
To simplify the tutorial, you'll create a constant variable that stores your list of posts in memory.
🥸
Yes, you and I like constant variables. Make everything much easier.
Let's generate our posts using the code below:
const posts: Post[] = [ { id: "1", slug: "golang-files-tutorial-beginner", title: "Quick Golang Files Tutorial for Beginner", cover: null, categories: [ "Golang", "Snippet" ], lastEditedAt: 1692584880000, isFavorite: null, content: "golang content" }, { id: "2", slug: "restapi-requests-in-python", title: "Quick REST API Calls using the Requests Library in Python", cover: null, categories: [ "Python", "RestAPI" ], lastEditedAt: 1692656820000, isFavorite: null, content: "python content" }, { id: "3", slug: "react-pdf-module-parse-failed-next-js", title: "How to Resolve the react-pdf Issue: \"Module parse failed: Unexpected character '�' (1:0)\" in Next.js", cover: null, categories: [ "Next.js" ], lastEditedAt: 1692612960000, isFavorite: null, content: "react-pdf content" } ];

Preparing Query Resolvers

In GraphQL, the function that runs when you query data is called a resolver.
To prepare resolvers, you can use this code:
const resolvers = { Query: { getPost: async (parent: any, args: { id: string }) => { const { id } = args; return posts.find((post: Post) => post.id === id) }, getPostsByTitle: async (parent: any, args: { query: string }) => { const { query } = args; return posts.find((post: Post) => post.title.includes(query)) }, getAllPosts: async () => { return posts }, }, };
In the above code, you'll only need a resolver for the Query as it is the schema that exposes functions to get the list of posts.
  1. In getPost, you match posts by comparing their id to the given argument and returning the matched one.
  1. For getPostsByTitle, you find posts with title containing the provided query and return them.
  1. getAllPosts simply returns all post content without any filtering.

Setting Up GraphQL Server

As a prerequisite, you've installed Apollo GraphQL to act as your GraphQL engine. To set up Apollo Server, you can use this code:
import { ApolloServer } from '@apollo/server'; const resolvers = ... // Your resolvers const schemaDefinitions = ... // Your schema definitions const server = new ApolloServer({ resolvers, schemaDefinitions, });

Exposing GraphQL Next.js Endpoint

GraphQL is a mechanism that allows you to define how the response should look, rather than the server. It can save you a lot of data when you need a small amount of information displayed.
To transport your GraphQL query, you can leverage HTTP POST.
In this project, you won't set up the transport yourself. You'll use the @as-integrations/next package you installed earlier.
import { startServerAndCreateNextHandler } from '@as-integrations/next'; const server = ... // Your ApolloServer export default startServerAndCreateNextHandler(server);
Now that everything is in place, you can run the Next.js project using:
npm run dev
When your application is accessible through localhost:3000, you can access the GraphQL endpoint at http://localhost:3000/api/graphql.

Use cURL to Test the Live GraphQL Endpoint

Get All Posts

Now that everything is in place, you can test the GraphQL endpoint. Use this cURL command to get a list of blog posts:
curl -X POST \ -H "Content-Type: application/json" \ -d '{ "query": "query { getAllPosts { id slug title categories } }" }' \ http://localhost:3000/api/graphql
That will give you response like this:
{ "data": { "getAllPosts": [ { "id": "1", "slug": "golang-files-tutorial-beginner", "title": "Quick Golang Files Tutorial for Beginner", "categories": [ "Golang", "Snippet" ] }, { "id": "2", "slug": "restapi-requests-in-python", "title": "Quick REST API Calls using the Requests Library in Python", "categories": [ "Python", "RestAPI" ] }, { "id": "3", "slug": "react-pdf-module-parse-failed-next-js", "title": "How to Resolve the react-pdf Issue: \"Module parse failed: Unexpected character '�' (1:0)\" in Next.js", "categories": [ "Next.js" ] } } }

Get Specific Post by ID

To retrieve a specific Post, you can use getPost from the Query Schema. You need to pass the Post.id to get the information you want.
Use this cURL command to get a specific post:
curl -X POST \ -H "Content-Type: application/json" \ -d '{ "query": "query { getPost(id: \"1\") { id slug title categories cover content } }" }' \ http://localhost:3000/api/graphql
It will result in this response:
{ "data": { "getPost": { "id": "1", "slug": "golang-files-tutorial-beginner", "title": "Quick Golang Files Tutorial for Beginner", "categories": [ "Golang", "Snippet" ], "cover": null, "content": "golang content" } } }
Isn't that awesome?
But how do you update data using GraphQL? Let's say you want to favorite a post. In that case, let's introduce mutations.

Performing Mutations

When you want to favorite a post, you must update the database via mutation.
GraphQL provides a specific schema to explicitly tell the server that a client wants to perform a mutation.

Mutation Schema

To enable clients to perform mutations, you should update the schemaDefinitions to include the mutation.
Add this to your const schemaDefinitions above:
type Mutation { addPostToFavorite(id: ID!): Post }

Discussion (0)

Related Posts