GraphQL with the Serverless Framework

Building a dashboard for my garden

Last week I wrote about a problem I have with my garden. I often forget to water my plants and I need a system to help. Part of my solution is a dashboard to track the soil moisture of my plants.

To create this dashboard, I built a web client and backend. I chose to use GraphQL for the backend as I wanted to learn about the technology. After all, the purpose of this project is to learn and have fun. I found that GraphQL + Lambda + React is a powerful technology stack. If you want to build something like this yourself, try this video course that covers GraphQL on Lambda in-depth.

GraphQL Endpoint

In case you are not familiar with it, GraphQL is a data query language created by Facebook. GraphQL allows the client to select ad-hoc data. This differentiates it from REST API’s that expose pre-set data structures. The Apollo Stack blog has a great introduction to GraphQL.

Infrastructure

Selecting your infrastructure is an important step in building any Serverless system. For the GraphQL endpoint I have used three AWS services:

  • API Gateway — API endpoints as a service

  • Lambda — Function as a service

  • DynamoDB — NoSql database as a service

API Gateway handles HTTP requests and responses. A DynamoDB table stores soil moisture levels. The Lambda function is the glue between these services. API Gateway invokes the Lambda function in response to HTTP requests. The Lambda function retrieves data from DynamoDB and returns it to the client via API Gateway.

The interesting part of this is the Lambda function so let’s take a look at the code.

Code

If you are building a Serverless project, it won’t be long before you realise you need a great tool to help. There are many options available.

I have chosen to use the Serverless Framework. If you are not familiar with the framework and you want to build your own endpoint, check out the docs to get started.

To create the GraphQL endpoint I added a function and HTTP event to the Serverless Framework config, serverless.yml. The Serverless Framework will create my API Gateway and Lambda so all I need to worry about is the code.

The code in my Lambda function needs to perform two tasks. The first is processing GraphQL queries. The second is retrieving data from DynamoDB. Luckily, there are two great libraries for doing just this:

  • graphql-js — JavaScript implementation for GraphQL for nodejs

  • vogels — DynamoDB data mapper for nodejs

Update: While Vogels works for me, I am told it is now unsupported. I can’t see a message saying that the project is no longer maintained. But, there are a large number of open issues that seem stale. The alternative suggested to me Dynogels.

The first step was to create the GraphQL schema. The GraphQL schema describes and retrieves the data. The endpoint in this project exposes a Moisture Query. This query allows the client to retrieve the last x hours of moisture readings.

The key piece of code here is the resolve function in the MoistureQuery. This function retrieves data in response to the query. To simplify the code, logic for this has been separated into a different service.

The moisture service above queries the DynamoDB table. The results returned by the query are converted into a usable format. The service uses the vogels table defined below to query DynamoDB.

The end result of all this work is below, a working GraphQL endpoint.

Responses from the GraphQL endpointResponses from the GraphQL endpoint

Some of you may be wondering where the DynamoDB table is. This example uses an existing DynamoDB table. Creating the table and inserting moisture data into the table will be the topic of future post.

React + Redux Client

React is a JavaScript library for building interactive UI’s. Redux is a state container for Javascript applications. These two libraries form the core of the Web client for this project. This article is not a React or Redux tutorial, there are plenty of other articles for that. This article will focus on polling a GraphQL endpoint in a React + Redux app.

Hosting

If you are building a Serverless web application, you need a service to host your web client. I chose to use Firebase Hosting. Firebase Hosting allows you to host static content and route all requests to a single page. The command tool is easy to use and the documentation is great.

Code

To retrieve soil moisture levels I need to request data from the GraphQL endpoint. Thankfully, there are already great libraries for retrieving data from GraphQL endpoints. The Apollo Client and React Apollo help developers integrate GraphQL endpoints into React apps.

The first step was to update the entry point for the React app. I created an Apollo client and replaced the React Provider with the ApolloProvider.

The next step was to integrate the Apollo client with the Redux store. To use the Apollo client with Redux, I added the Apollo client middleware and reducer to the store.

After integrating the Apollo client with Redux, I was then able to start using GraphQL in the UI. Using the React Apollo library I am now able to send a GraphQL query to my endpoint.

The results of the query are then mapped that to props in React components.

Dashboard Time!

The end result of all this code is the dashboard below. The dashboard polls for data every 30 seconds. This allows the user to see moisture levels in real time.

Moisture levels from a test deviceMoisture levels from a test device

While this is only a fun project, working on it has sold me on a GraphQL + Lambda + React stack.

For me, the main advantage of GraphQL is that it puts the client close to the data. Letting the client choose what data to fetch is more efficient and flexible. Facebook has a great post on the advantages of GraphQL.

What’s Next

If you want a look at the code you can find Web Backend and Web Client on Github. I will continue to write about how I created the other pieces of this project over the coming weeks.

If you want to see how I created the rest of the project, follow Serverless Zone and myself on Medium or Twitter.