GraphQL Server on Cloud Functions for Firebase

The smoothest GraphQL on FaaS DX to date!

James Hegedus
codeburst

--

GraphQL on Cloud Functions for Firebase

What is GraphQL?

GraphQL is a data query language created by Facebook. Queries to the server specify the data they want to fetch while the GraphQL server exposes what is available and knows how to get it. The fundamental difference from REST is that we no longer expose predefined data. Therefore solving the problem of adding endpoints whenever we add new clients and versioning our REST endpoints.

Lee Byron’s blog post describes its use within Facebook and the advantages it offers. Another great resource is this Apollo post.

Why GraphQL with Firebase?

Firebase, although known predominantly for its real-time database, is a collection of services packaged, billed and deployed together. In my opinion, it offers the slickest developer experience of any cloud services available. My favorite features are:

  • Single command deployment which can easily be customized to deploy any combination of your services and can easily integrate into a CI/CD pipeline.
  • Runs on Google Cloud Platform and can easily integrate with the other services available here.
  • No need to configure service-to-service IAM policies! This reduces the barrier to entry in a way the other cloud services cannot.
  • A generous free-tier with PAYG billing.

I could go on.

So the developer experience (DX)is why, not because of anything to do with GraphQL. GraphQL can be hosted anywhere that responds to HTTP requests, so why not on Cloud Functions? Then we can utilize the DX of Firebase AND GraphQL!

Drawbacks of Ephemeral Compute Instances

While they do exist, I would argue that the reasons for not running GraphQL on serverless/FaaS are weak. The main argument for not using FaaS is the Cold Starts problem. The Serverless Framework community has covered this topic well (their blog is great! I recommend following them):

What is cold start in Serverless (FaaS)?

Cold start happens when you execute an inactive (cold) function for the first time. It occurs while your cloud provider provisions your selected runtime container and then runs your function. This process, referred to as cold start, will increase your execution time considerably.

While you’re actually running your function it will stay active (hot), meaning your container stays alive — ready and waiting for execution. But eventually after a period of inactivity, your cloud provider will drop the container and your function will become cold again.

So each request to our GraphQL endpoint would either, use a hot container, or a cold one. Since GraphQL Servers are a single API to your entire data graph, every request to fetch or mutate your data will go through here. Thus, you should have enough traffic to have some hot containers around making the Cold Start time irrelevant. If this does become an issue, you can simply run another Cloud Function to ping the desired Cloud Function and keep it warm.

GraphQL on Cloud Functions for Firebase

There are multiple packages available to leverage GraphQL in a Node.js environment. Facebook (well, the GraphQL team at Facebook) has express-graphql which is a middleware implementation of GraphQL for the ExpressJS server package. As of writing, this is the most popular middleware with ~97,000 downloads in April, 2017 according to npmjs. The other prominent implementation is the Apollo developed graphql-server-express, also a middleware for Express. It has far fewer downloads at ~35,000 downloads in the same period.

The number of downloads is a bad reason to choose between two packages, so let’s dig deeper. Facebook’s implementation seems to be a standard middleware for Express. While Apollo distinctly addresses the difference between the two packages:

The following features distinguish GraphQL Server from express-graphql, Facebook’s reference HTTP server implementation:

- GraphQL Server has a simpler interface and allows fewer ways of sending queries, which makes it a bit easier to reason about what’s going on.

- GraphQL Server serves GraphiQL on a separate route, giving you more flexibility to decide when and how to serve it.

- GraphQL Server supports query batching which can help reduce load on your server.

- GraphQL Server has built-in support for persisted queries, which can make your app faster and your server more secure.

Click here for a deeper dive into the Apollo docs.

Cloud Functions and an Express Server

At this point you may be asking “Why’re we going to run an Express Server on Cloud Functions. Don’t they already expose an HTTPS endpoint?”.

Well, yes, they do already expose an endpoint. However we cannot customize it with the GraphQL middleware like we can Express. Fortunately, Cloud Functions can be used with the Express.js web server framework. For more information about how this works, please read my previous post about Express on Cloud Functions.

So which package should we use?

In this tutorial we’ll be using Apollo’s graphql-server-express package as I lean towards the community built around it. While express-graphql is open-source and well maintained, I find that that GraphQL community around the Apollo tools will enable better integration, support and ultimately more customization.

Add GraphQL Server

In the ./firebaseFunctions directory run:

yarn add express apollo-server-express \
graphql graphql-tools \
body-parser

Our ./firebaseFunctions/package.json should now look like:

Now we have all the requried packages we will implement the Server in ./firebaseFunctions/graphql/server.js:

Export a method that returns an Express server configured with graphqlExpress

And then use that server in ./firebaseFunctions/index.js:

Import the server creator and plug it into our API Cloud Function

Add GraphQL Schema & Resolvers

Before we try and test this server, we will need to implement the GraphQL schema and the resolver methods to fetch the data. Instead of reinventing the wheel, we will use the same example data as the Apollo crew which is the basis for the dev.apollodata.com examples.

Create ./firebaseFunctions/graphql/data/schema.js:

A simple schema to demonstrate

And ./firebaseFunctions/graphql/data/resolvers.js:

We’re just using static data here, but the resolver methods can do whatever you want

Deploy & Test

We can deploy our server by running the now familiar yarn deploy.

Testing the URL <function-name>/api will yield a “Cannot GET null” 404 error, while adding the trailing “/” yields a “Cannot GET /” 404 error. Why does the trailing slash not solve our problem? Well, the Cloud Function is hosted on /api/ but our GraphQL server is hosted at /api/graphql as we defined in our Express server in ./firebaseFunctions/index.js. We must use our defined routes like so:

<function-name>/api/graphql: accepts a GraphQL POST query string.

<function-name>/api/graphiql: runs the GraphiQL browser IDE.

<function-name>/api/schema: returns our schema in pretty-JSON.

And yes, no trailing “/” this time, graphql-server-express knows what’s up!

GraphiQL

To enable independent development of the GraphQL server and schema from the client apps, Facebook developed the GraphiQL in-browser IDE. It let’s you explore the schema by browsing the schema and constructing and executing queries!

Constructing a query
An executed query

Notice the “Documentation Explorer” on the right side of the IDE. Use this to browser the queries, mutations and their parameters and structures.

Each query that is run through GraphiQL simply constructs the appropriate request object and sends a request through to our /api/graphql endpoint. Thus, each time we run a query here it executes an instance (it may be new or use an existing one) of our Cloud Function. Pretty neat! Read more about it here.

Conclusion

There you have it, GraphQL on Cloud Functions. This is only the beginning of my exploration into GraphQL on Firebase, so stay tuned by Following! Next up, GraphQL subscriptions while using GraphQL on Cloud Functions!

Need something else to read?

More by me:

If you found this useful, please recommend and share with your friends & colleagues.

--

--

GCP, Firebase, Sveltejs & Deno fan! @jthegedus on all platforms.