Behind the Technology

Now is a serverless deployment service. This means deploying your executional code as functions that execute as a result of an HTTP request.

Apollo Server is a server for GraphQL, bundled with some nice SDK like tools for easier development.

What This Means For Our Code

When we're working with serverless we'll have a few constraints & considerations.

Our Serverless Functions should execute once then stop when everything we need to do has completed, and this will allow the invoked instance to sleep and eventually shut down. This means as opposed to a persistent server instance that can maintain a database connection we'll need to close ours after each request completes, otherwise the connection will keep our serverless instance alive which will cost more money, cause new requests to open new connections to our database, and more issues.

Zeit Now Builders

Now uses "Builders" (recently partially rebranded as "Runtimes") to transform our HTTP handler functions into Serverless Functions. This means our default exported function will be transformed to receive some helper objects as arguments from each request. These are your typical req and res when dealing with Node.js.

This means we can build simple server response/request functions without external libraries like Express.js and gain a small performance benefit.

What You'd Typically Do With Apollo

Apollo Server is as the name implies, a stand-alone server all by itself. We could export it alone and it will function just fine.


				import {ApolloServer} from 'apollo-server';

				const typeDefs = `
					# ...
				`;

				const resolvers = {
					// ...
				};

				module.exports = new ApolloServer({typedefs, resolvers});
				

But there's no where here to establish a database connection, make sure Apollo does its thing, and then close our connection or any other cleanup we need.

What We Need To Do With Apollo

With Serverless Functions we need to create a handler for Apollo Server. This will allow us to do the work we need to do before initializing Apollo, and use a returned promise from the handler to do everything we need after Apollo is done.

Fortunately, the package apollo-server-micro provides a method to create just such a handler. Now's Node Builders will transform our Serverless Function into using something that resembles Micro (a small Express.js like library by Zeit) so the apollo-server-micro choice plays well with Now.

Note: In the below example connectToDatabase() is an abstraction. It could be a connection to a MongoDB in your setup.


				import {ApolloServer} from 'apollo-server-micro';
				import connectToDatabase from 'connectToDatabase';

				module.exports = async(req, res) => {

					const client = await connectToDatabase();

					const typeDefs = `
						# ...
					`;

					const resolvers = {
						// ...
					};

					const server = new ApolloServer({typedefs, resolvers});
					const handler = server.createHandler();

					return handler(req, res).then(() => {
						client.close();
					});

				};
				

The Breakdown

We've replaced our import to the new apollo-server-micro package.


				import {ApolloServer} from 'apollo-server-micro';
				

Wrapped the bulk of our logic in an async function that receives the req and res objects from Now's Builders. This will enable us to easily handle possibilities like errors, authentication, and other logic based on the request that may need to happen outside of Apollo.


				module.exports = async(req, res) => {
					// ...
				};
				

Finally, we've created a handler for Apollo using the createHandler() method, a .then() on the handlers returned promise for cleaning up things like open connections, and returned our new handler with our Serverless Function's req, res.


				const server = new ApolloServer({typedefs, resolvers});
				const handler = server.createHandler();

				return handler(req, res).then(() => {
					client.close();
				});
				

The Benefits

Without importing any extraneous server frameworks to handle our HTTP requests and responses we've kept our Apollo Server lean and performant and truly serverless native when destined for the Zeit Now platform.