Overview

Part of the GraphQL Series

We now continue our GraphQL journey as we try out Apollo to implement our first GraphQL server. We’ll use Apollo server - an open-source spec-compliant GraphQL server which is production-ready and is compatible with all GraphQL clients.

As with all posts here in Fullstack Developer Tips, all source code is available open-source in Github, and for this post, we use Github Actions for the first time to push it to production. I wanted to deploy this to the cloud, and my choice of cloud provider is AWS. To leverage free hosting, we will be deploying the GraphQL server to a Lambda using Serverless.

I Love Formula 1, pictured above is the new 2021 F1 car design.

What we are building

I love Formula 1, and for this GraphQL server, we will be exposing the Formula 1 results and standings since 1950 when the first race started. I don’t have a database though, instead, we are sourcing our data from Ergast Developer API, and surfacing it with our GraphQL server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// copy the following GraphQL query and use it with the server below
query {
  raceResults(season: "2019", resultsLimit: 3) {
    raceName 
    round
    date
    Circuit {
      circuitName
    }
    Results {
      position
      number
      points
      Driver {
        givenName
        familyName
      }
    }
  }
}

Go on, try it live here!

Step 1: Create your base NodeJS server

Because we are implementing this GraphQL Server using Apollo Server, a NodeJS based implementation, we are going to start the project using npm init. The following image shows this process, where when finished will generate an empty project with a package.json file. We’re well on our way.

Use npm init to create your project

Step 2: Add Apollo Server and other dependencies

1
npm i apollo-server graphql apollo-server-lambda nodemon axios promise dataloader

Following explains why we need the dependencies above:

apollo-server - is the core library for Apollo Server itself, which helps you define the shape of your data and how to fetch it.

graphql - is the library used to build a GraphQL schema and execute queries against it.

apollo-server-lambda - while apollo-server is used for creating a GraphQL server that you can deploy in your own cloud instance, apollo-server-lambda is a drop-in replacement if you want to deploy your server in AWS Lambda.

nodemon - watches for any changes and restarts your server when needed.

axios - our Http client of choice.

promise - library for helping us resolve our http requests.

dataloader - is a port of a library originally developed in Facebook to help in batching and caching requests in the server.

Our base GraphQL server code, really.

Step 3: Add GraphQL schema definitions in typedefs.js

Now we need to work on some GraphQL specific tasks, starting with defining the schema. Schema is simply the shape of our data, both incoming and outgoing. This is what made me like working with GraphQL. Whether you are the server developer or on the other side of the fence as the client developer, it is a pleasure working with it.

1
2
3
4
5
6
7
8
9
10
11
12
13
type Result {
    number: Int
    position: Int
    positionText: String
    points: Float
    Driver: Driver
    Constructor: Constructor
    grid: String
    laps: Int
    status: String
    Time: Time
    FastestLap: FastestLap
}

Have a look at the file typedefs.js - this file contains all the schema that the server uses, in addition to that, GraphQL introspection will also use these for self-documenting the API. The excerpt with type Result above shows the GraphQL SDL (Schema Definition Language), the type system used to express our data types.

GraphQL servers support 3 operations - Query (reads), Mutations (writes), and Subscriptions (pub-sub system). In this sample server, we will only be using Queries, and leave the other types, possibly for another post.

Step 4: Add GraphQL resolvers in resolvers.js

APIs build up data and send back to the client, and it’s no different with GraphQL. Our data sources may be varied - files, databases, web services, REST APIs, and other GraphQL servers themselves. A resolver collects and assembles the data and aggregates it before sending it back to the client.

For example, our server below supports the following 4 queries, however lets focus on the one named raceResults:

1
2
3
4
5
6
type Query {
    results: [Result]
    races: [Race]
    raceResults(season: String!, resultsLimit: Int): [RaceResultV2]
    seasons: [Season]
}

And the following shows the simplicity of building a resolver that fetches data from an API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
raceResults(parent, args) {
    const { season, resultsLimit } = args;
    return axios
        .get(`http://ergast.com/api/f1/${season}/results.json?limit=1000`)
        .then(res => {
            return res.data.MRData.RaceTable.Races.map((race) => {
                return({
                    ...race,
                    Results: race.Results.slice(0, resultsLimit || 1)
                });
            });
        })
        .catch(function (error) {
            console.log(`Error: ${error}`);
        });
}

Step 5: Add Serverless configuration

Serverless makes it super simple to deploy your serverless applications to the cloud. Because its cloud agnostic, it can handle whatever cloud framework you use.

For this project, we will be deploying to AWS Lambda, and take advantage of their very generous free-tier, so we will never likely incur a bill.

AWS Lambda deployment made easy with Serverless.

Just setup your Serverless configuration in your project’s root, and because it has a CLI, you can deploy from your command line, or from your CI/CD of choice, in this case Github Actions, coming up next.

Step 6: Add Github Actions workflow

GraphQL Server complete with CI/CD using Github Actions.

Github recently released Github Actions and ever since then, I have heard so many great things about it. Because this project lives in Github, wouldn’t it be awesome if the CI/CD lives there too? And its forever FREE for public repositories, so how good is that?!

If you have a private repository, you will have to fork out some $, however you still get get 2,000 minutes (33.3 hours) build time per month before you start handing in the dough.

So here’s our Github Actions deployment badge:

Deploy master branch

Profit!!!

There you go, our first GraphQL server built with Apollo Server, NodeJS, Serverless, AWS Lambda and Github Actions, built and deployed on AWS for FREE!

Go on, try it live here!

Source code forever open-source

In our next GraphQL installment we will:

  • create a React client based on Apollo Client
  • refactor our simple resolver to ditch the API call for DynamoDB NoSQL persistence

My Picks

These picks are things that have had a positive impact to me in recent weeks:

  • The Path Less Pedaled - I’m so into bike commuting, and looking into gravel bikes, this is the place to learn all about it.
  • Netflix Series: Drive to Survive - This series is responsible for getting me hooked into Formula 1. This race has a lot to be digested, but once you understand the basics, your are fan forever.

Resources

2023

Back to top ↑

2022

Back to top ↑

2021

Back to top ↑

2020

DynamoDB and Single-Table Design

9 minute read

Follow along as I implement DynamoDB Single-Table Design - find out the tools and methods I use to make the process easier, and finally the light-bulb moment...

Back to top ↑

2019

Website Performance Series - Part 3

5 minute read

Speeding up your site is easy if you know what to focus on. Follow along as I explore the performance optimization maze, and find 3 awesome tips inside (plus...

Back to top ↑