A way to setup a GCP driven application with App Engine, Cloud Firestore and React/GraphQL

Fons Hettema
incentro
Published in
9 min readJan 11, 2022
Showing some of my favourite movies in an application.

Hello everyone, welcome to my first blog article on Medium. In this post I’d like to show you how you can connect Google Cloud Firestore with Apollo/GraphQL by creating an application about managing a movie collection. I like movies so I chose to use it as an example.

Technologies for the web are developing rapidly and there are a lot of options for your tech stack out there nowadays. It can be hard to pick the right stack for a specific project. In this case I will work with the common serverless approach. What is serverless? Serverless is basically letting a cloud provider manage your infrastructure all the way up to the application layer. In this case I am using Google Cloud Firestore for data storage, Google App Engine to build my application and Cloud Build as a CI/CD platform for deployments. If you are quite new to Google Cloud Platform and Apollo/GraphQL you will hopefully gain some insights about how to use it.

Combined with using Google Cloud services I will demonstrate a way to setup a project with GraphQL/Apollo Server as a layer on top of that which covers the back-end. For the front-end i’ll use a Next.js template with Apollo Client to connect with our NodeJS/GraphQL server. You can do it with any preferred framework. You can also do it without a framework, but for this example I’ve used NextJS.

Why did I use this stack?
For several years I have been working as a front-ender developer. In my experience this is the stack that delivers the best developer experience. The HMR (hot module reloading), routing setup and performance and its server side rendering approach for example are state of the art. It is already one the most popular tools in the React ecosystem. I feel confident with this stack and therefore I chose to integrate it within my demo.

Let’s start

Note: For this tutorial I assume that you already have some basic knowledge about Google Cloud Platform, Cloud Firestore, React and Apollo/GraphQL.

Part 1: Setup Cloud Firestore

In order to connect with your Cloud Firestore database you’ll need a service account. What is a service account?

A service account is a special type of Google account intended to represent a non-human user that needs to authenticate and be authorized to access data in Google APIs.” (https://cloud.google.com/iam/docs/understanding-service-accounts)

First you need to create a project in the Google Cloud Console. You can follow these steps on this page to do so. This will also include the steps to create a service account.

When you are done with this you should have a service account on your computer as a JSON format. I will need this file in the following parts. Below is an example of how a service account structure should look like.

service-account.json

A service account JSON file example format.

Please note that this file should not be exposed to the public. If you add this to your public codebase one could steal your credentials and use it for their own purposes. Make sure that you ignore this file in your version control tool of choice whenever you’re committing.

Now that I have the service account in place I can set up the structure of our collection. Find your project in the Google Cloud console and search for Firestore. You should see an option to enable this API. In this module you should be able to create a collection. Create one with movies as a collection id.

You are now ready to fill in some field names. As I mentioned in the beginning I want to display a list of movies and be able to add movies. Therefore I need a movie title, a movie description, cover image and a link to its related imdb page (just because I can). Follow the same structure as below and move on to part 2:

Cloud Firestore movies collection.

Part 2: Create a GraphQL/Apollo server

In my setup I’ve used one folder for the frontend and one for the api which are both spun up on different ports. For this part I am only working in the api folder.

api
- package.json
- package-lock.json
- src
// Our GraphQL resolvers and schema's
- graphql
- resolvers.ts
- typeDefs.ts
// Connection with our Apollo Server
- index.ts

To set up a GraphQL / Apollo server you need to install them as dependencies in our project. I followed the steps from the Apollo Graphql website to get started. After reading and executing these steps you should have some understanding of GraphQL schema’s, type definitions and resolvers and should be able to run the project and see a GraphQL playground like this:

Our GraphQL playground.

For our movies application I need the following type definitions and resolvers that match our fields in the Firestore collection. You could use different names here as long as you pass the correct field names when executing methods that connect to our Firestore collection. For convenience I’ll use the same field names as in our collection.

Below are the type definitions to use for GraphQL:

GraphQL type definitions.

Below you’ll find resolvers I’ve written to fetch and save movies to my Firestore collection:

GraphQL resolvers.

Firestore connection
If you look closely you will see that i’m first establishing a connection with Firestore through our service-account.json and the firebase-admin package as dependencies. In the first part I’ve created this service account file.

Query
To fetch data from our database I need to query them with a resolver. Going further in the code you will see that I’m using the admin.firestore().collection(“movies”).get() method to fetch our movies collection from Firestore through the firebase-admin package.

Mutation
To mutate data from our database I need a GraphQL mutation resolver. The addMovie function below needs the movie parameters (name, description, imdb_url and cover_image) that are used in the firestore.collection.doc().set() method to add a new movie to our collection.

Part 3: Create a NextJS project

To kickstart my NextJS project setup tied with Apollo I’ve used Vercels example which you can find here. Running the npx create-next-app — example with-apollo with-apollo-app command should get you up to speed with a boilerplate. In this example you can see how to use GraphQL queries and mutations with a Apollo provider.

For my movies example project I’ve used the following project structure:

frontend
- package.json
- package-lock.json
- README.md
- src
// React components
- components
- AddMovie
- Header
- ErrorMessage
- MovieList
// React NextJS pages
- pages
- _app.tsx
- addmovie.tsx
- index.tsx
// Lib containing an Apollo client setup function
- lib
- apolloClient.js
// Connection with our Apollo Server
- index.ts

You could use this structure for your own project or choose a different one yourself. Let’s start off by showing the entry page where I render the list of movies to be displayed:

A list of movies displayed on the home page.
The entry file where I initialise and provide the Apollo client.
Query mark up to get all movies.

Up in the code above, within the ALL_MOVIES_QUERY, you can see that I am retrieving the name, description, imdb_url and the cover_image from my Firestore movies collection. The great thing of using GraphQL is that you can select only the data you need. So if I don’t want to have the imdb_url field for example, I could just leave that out. For other use cases you could imagine that doing this can have a huge impact on your performance when used correctly.

The movies list component where I fetch the movies and display them.

Here you can see I import the MovieList from our components folder and show it. Let’s dive deeper and go to the query to retrieve the movies and the presentational movie list component.

I am retrieving and rendering the movies by executing the ALL_MOVIES_QUERY that passes us an array of movies if the request is successful. While executing I conditionally show an error message or a loader element which is supported within the useQuery function from our Apollo client.

For the last part I’ll show how you can execute a mutation with GraphQL. The example below shows some code of a form with required fields to add for our Firestore database.

Form to add a movie to our Firestore collection.
Add movie mutation from our mutations.ts file.
Add movie form component.

Part 4: Deploy to App Engine using Cloud Build

Since this blog post is about creating a Google Cloud driven application I chose to run my application using App Engine and Cloud Build. I could write down all the steps for you to make this happen. But we all know that this post will be outdated at some point in time and so will the instructions. Therefore I chose to do some research for you and hook you up with some links to achieve the same but with even clearer steps. But here you can see how to do it step by step according to Google Cloud’s own documentation.

How I did it
I’ve already made a Google Cloud Platform project in the beginning of this post. In fact all you need to do is enable App Engine, create configuration files and enable and configure Cloud Build to make it possible to deploy your project. In my project I have the api and the frontend separated in two different folders. In order to run them both in App Engine I needed to create a service for each of them. So I’ve configured app.yaml files for both of the projects and set up Cloud Build configuration to deploy the services.

Continuous Deployment
You can make use of automatic deployments to App Engine by creating Cloud Build triggers. You can configure your triggers to build and deploy images whenever you update your source code. Therefore you need to update the configuration file with steps to invoke the gcloud app deploy command.With Cloud Build you can also connect to a public Github repository and choose a branch for running triggers. These triggers will listen to changes in that branch and deploy automatically which is what I’ve done.

Here you can see I coupled my Github repo with Cloud Build.

Secret service account issue
The service account I’ve created in the beginning of this post needs to be in the cloud environment in order to make connection with Firestore for example. If the service account is ignored and won’t be deployed to our service you have to find another way to let our application make use of it. What you could then do is enable the Secret Manager, store the service account credentials in there and retrieve it just before you do a deploy. Please note that you need to make sure that Cloud Build has the correct Secret Manager access rights.

Completed!

Congratulations! You’ve just found a way to set up a cloud driven application using App Engine / Cloud Build, Cloud Firestore, NextJS and GraphQL.

Thanks for reading my article. This was a simple setup to get you started using modern web technologies with the cloud. If you want to look into my project you can check my public repository here: https://github.com/strexx/next-graphql-api.

Are there other ways to do this?

Of course! In this blog post I’ve used App Engine and Cloud Firestore to facilitate data storing and hosting for my application. In my next blog post I will write about another approach of connecting with the cloud. You could for example use Cloud Run to deploy this application combined with BigQuery. I am still thinking about what my next article should be about exactly but I will figure it out over time.

If you have any questions or suggestions regarding this or my next post, or want to have a chat with me please don’t hesitate to send me a message 👋

--

--