In this tutorial, we will learn how to create a serverless Apollo GraphQL server using TypeScript and Next.js. By leveraging the power of Apollo and Next.js, we can build a robust serverless GraphQL API.
Step 1: Set up the Next.js project
First, let’s set up a new Next.js project.
npx create-next-app my-apollo-app
cd my-apollo-app
Step 2: Install Dependencies
Next, let’s install the required dependencies for our project. In the terminal, navigate to the project root directory and run:
npm install @apollo/server
Step 3: Create the Apollo Server
In the project directory, create a new file named startServerAndCreateNextHandler.ts
. This file will contain the code for creating the Apollo server and the Next.js request handler. Copy the following code into the file
import {
ApolloServer,
BaseContext,
ContextFunction,
HeaderMap,
} from "@apollo/server";
import type { WithRequired } from "@apollo/utils.withrequired";
import { NextApiHandler } from "next";
import { parse } from "url";
interface Options<Context extends BaseContext> {
context?: ContextFunction<Parameters<NextApiHandler>, Context>;
}
const defaultContext: ContextFunction<[], any> = async () => ({});
const allowCors =
<A extends Function>(fn: A): NextApiHandler =>
async (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"GET,OPTIONS,PATCH,DELETE,POST,PUT"
);
res.setHeader(
"Access-Control-Allow-Headers",
"X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, authorization"
);
if (req.method === "OPTIONS") {
res.status(200).end();
return;
}
return await fn(req, res);
};
function startServerAndCreateNextHandler(
server: ApolloServer<BaseContext>,
options?: Options<BaseContext>
): NextApiHandler;
function startServerAndCreateNextHandler<Context extends BaseContext>(
server: ApolloServer<Context>,
options: WithRequired<Options<Context>, "context">
): NextApiHandler;
function startServerAndCreateNextHandler<Context extends BaseContext>(
server: ApolloServer<Context>,
options?: Options<Context>
) {
server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();
const contextFunction = options?.context || defaultContext;
const handler: NextApiHandler = async (req, res) => {
const headers = new HeaderMap();
for (const [key, value] of Object.entries(req.headers)) {
if (typeof value === "string") headers.set(key, value);
}
const httpGraphQLResponse = await server.executeHTTPGraphQLRequest({
context: () => contextFunction(req, res),
httpGraphQLRequest: {
body: req.body,
headers,
method: req.method || "POST",
search: req.url ? parse(req.url).search || "" : "",
},
});
for (const [key, value] of httpGraphQLResponse.headers) {
res.setHeader(key, value);
}
res.statusCode = httpGraphQLResponse.status || 200;
if (httpGraphQLResponse.body.kind === "complete") {
res.send(httpGraphQLResponse.body.string);
} else {
for await (const chunk of httpGraphQLResponse.body.asyncIterator) {
res.write(chunk);
}
res.end();
}
};
return allowCors(handler);
}
export { startServerAndCreateNextHandler };
Step 4: Create the GraphQL Endpoint
Next, let’s create the GraphQL endpoint in the api/graphql.ts
file. Create a new file named api/graphql.ts
in the project directory and copy the following code into it:
import { ApolloServer, BaseContext } from "@apollo/server";
import { startServerAndCreateNextHandler } from "./startServerAndCreateNextHandler";
import jwt from "jsonwebtoken";
import { resolvers } from "graphql/resolvers";
import { typeDefs } from "graphql/schema/schema";
export interface ApolloContext extends BaseContext {}
const server = new ApolloServer<ApolloContext>({
resolvers,
typeDefs,
introspection: true,
});
export default startServerAndCreateNextHandler(server, {
context: async (req, res) => ({
req,
res,
}),
});
Step 5: Define GraphQL Schema and Resolvers
Now, let’s define the GraphQL schema and resolvers. Create a new directory named graphql
in the project directory, and inside it, create two files: resolvers.ts
and schema.ts
. In the resolvers.ts
file, define your GraphQL resolvers as per your application’s requirements. In the schema.ts
file, define your GraphQL schema using the GraphQL Schema Definition Language (SDL). Here’s an example of how these files could look:
// graphql/resolvers.ts
const resolvers = {
Query: {
hello: () => "Hello, World!",
},
};
export { resolvers };
// graphql/schema.ts
const typeDefs = `
type Query {
hello: String!
}
`;
export { typeDefs };
Step 6: Start the Development Server
Finally, let’s start the development server and test our serverless Apollo GraphQL API. In the terminal, run the following command from the project root directory:
npm run dev
The Next.js development server will start, and you can access the GraphQL API at http://localhost:3000/api/graphql
.
Conclusion
In this tutorial, we learned how to create a serverless Apollo GraphQL server using Next.js. We set up the Apollo server, defined the GraphQL schema and resolvers, and created the GraphQL endpoint in Next.js.
You can now extend this setup to add authentication and build powerful serverless GraphQL APIs for your applications.
Happy hacking!