Learn how YOU can build a Serverless GraphQL API on top of a Microservice architecture, part I
Tags: graphql, docker, tutorial, azureapril
Published: 2019-04-13 12:22:00

---
title: Learn how YOU can build a Serverless GraphQL API on top of a Microservice architecture, part I
series: Azure April
published: true
cover_image: https://thepracticaldev.s3.amazonaws.com/i/2yiee1u9l5rxy4y0eumf.jpg
description: This teaches how you can create a GraphQL API from a number of microservices and host it all in a serverless function 
tags: graphql, docker, tutorial, azureapril
canonical_url: https://softchris.github.io/pages/serverless-graphql-one.html
---

Follow me on [Twitter](https://twitter.com/chris_noring), happy to take your suggestions on topics or improvements /Chris


> The idea with this article is to show how we can build microservices, dockerize them and combine them in a GraphQL API and query it from a Serverless function, how's that for a lot of buzzwords in one? ;) *Microservices*, *Docker*, *GraphQL*, *Serverless* 

This is part of series:

- Building Microservices and a GraphQL API, Part I, **we are here**
- [Hosting the GraphQL API in a Serverless app and bring it all to the Cloud, part II](https://dev.to/azure/learn-how-you-can-build-a-serverless-graphql-api-on-top-of-a-microservice-architecture-part-ii-deploy-it-to-the-cloud-26b6)

So, it's quite ambitious to create Microservices, Serverless and deploy to the Cloud in one article so this is a two-parter. This is part one. This part deals with Microservices and GraphQL. In part two we make it serverless and deploy it. 

In this article we will cover:

- **GraphQL and Microservices**, these are two great paradigms that really go quite well together, let's explain how
- **Building** Microservices and Dockerizing them, let's create two micros services, each with their own areas of responsibility and let's Dockerize them
- **Implementing  GraphQl**, we will show how we can define a GraphQL backend with schema and resolver and how to query it, of course, we will also tie in our Micro services here

## Resources

We will throw you in head first using `Docker`, `GraphQL` and some `Serverless` with Azure functions. This article is more of a recipe of what you can do with the above techniques so if you feel you need a primer on the above here is a list of posts I've written:

- [5 part series on Docker](https://dev.to/softchris/5-part-docker-series-beginner-to-master-3m1b), This covers the Basics of Docker, It includes Dockerfiles, containers,  images and Docker Compose
- [3 part series on GraphQL](https://dev.to/azure/3-part-series-on-graphql-1fi1), This covers the basics on GraphQL
- [Free Azure Account](https://azure.microsoft.com/en-gb/free/?wt.mc_id=devto-blog-chnoring) To be able to Deploy your services and host your Serverless function, you will need a free Azure account
- [Tutorial on Azure functions with VS Code](https://dev.to/azure/serverless-from-the-beginning-using-azure-functions-vs-code-part-iii-50j7), This post covers how to create serverless functions using VS Code
- [Github repo with code to create a GraphQL API and a Serverless function](https://github.com/simonaco/serverless-graphql-workshop) This article series is heavily inspired by the workshop created by my colleague [Simona Cotin](https://twitter.com/simona_cotin)
- [Containers in the Cloud](https://docs.microsoft.com/en-gb/azure/containers/?wt.mc_id=devto-blog-chnoring), as we are about to put our containers in the Cloud in the next part in this series it can be a good idea to read up on all the offerings of Containers in the Cloud

## GraphQL and Microservices
A library and paradigm like GraphQL, is the most useful when it is able to combine different data sources into one and serve that up as one unified API. A developer of the Front end app can then query the data they need by using just one request.   

Today it becomes more common to break down a monolithic architecture into microservices, thereby you get many small APIs that works independently. GraphQL and microservices are two paradigms that go really well together. How you wonder? GraphQL is really good at describing schemas but also stitch together different APIs and the end result is something that's really useful for someone building an app as querying for data will be very simple.

Different APIs is exactly what we have when we have a Microservices architecture. Using GraphQL on top of it all means we can reap the benefits from our chosen architecture at the same time as an App can get exactly the data it needs.

How you wonder? Stay with me throughout this article and you will see exactly how. Bring up your code editor cause you will build it with me :)

## The plan
Ok, so what are we building? It's always grateful to use an e-commerce company as the target as it contains so many interesting problems for us to solve. We will zoom in on two topics in particular namely *products* and *reviews*. When it comes to *products* we need a way to keep track of what *products* we sell and all their metadata. For *reviews* we need a way to offer our customer a way to review our products, give it a `grade`, a `comment` and so on and so forth. These two concepts can be seen as two isolated islands that can be maintained and developed independently. If for example, a product gets a new description there is no reason that should affect the review of said product. 

Ok, so we turn these two concepts into `product service` and a `review service`.

### Data structure for the services
What does the data look like for these services? Well they are in their infancy so let's assume the `product service` is a list of products for now with a product looking something like this:

```
[{
  id: 1,
  name: 'Avengers - infinity war',
  description: 'a Blue-ray movie'
}]
```
The review service would also hold data in a list like so:

```
[{
  id: 2,
  title: 'Oh snap what an ending',
  grade: 5,
  comment: 'I need therapy after this...',
  product: 1
}]
```
As you can see from the above data description the review service holds a reference to a product in the product service and it's by querying the product service that you get the *full picture* of both the review and the product involved.

### Dockerizing
Ok, so we understand what the services need to provide in terms of a schema. The services also need to be containerized so we will describe how to build them using `Docker` a `Dockerfile` and Docker Compose. 

### GraphQL
So the GraphQL API serves as this high-level API that is able to combine results from our `product service` as well as `review service`. It's schema should look something like this:

```
type Product {
   id: ID,
   name: String,
   description: String
}

type Review {
  id: ID,
  title: String,
  grade: Int,
  comment: String,
  product: Product
} 

type Query {
  products: [Product]
  reviews: [Review]
 }
```
We assume that when a user of our GraphQL API queries for Reviews they want to see more than just the review but also some extra data on the Product, what's it called, what it is and so on. For that reason, we've added the `product` property on the `Review` type in the above schema so that when we drill down in our query, we are able to get both Review and Product information. 

### Serverless
So where does *Serverless* come into this? We need a way to host our API. We could be using an App Service but because our GraphQL API doesn't need to hold any state of its own and it only does a computation (it assembles a result) it makes more sense to make it a light-weight on-demand Azure Function. So that's what we are going to do :) As stated in the beginning we are saving this for the second part of our series, we don't want to bore you by a too lengthy article :)

## Creating and Dockerizing our Microservices
We opt for making these services as simple as possible so we create REST APIs using Node.js and Express, like so:

```
/products
  app.js
  Dockerfile
  package.json
/reviews
  app.js
  Dockerfile
  package.json
```
The `app.js` file for `/products` looks like this:

```js
// products/app.js

const express = require('express')
const app = express()
const port = process.env.PORT || 3000

app.get('/', (req, res) => res.json([{
  id: "1",
  name: 'Avengers - infinity war',
  description: 'a Blue ray movie'
}]))
app.listen(port, () => console.log(`Example app listening on port port!`))
```
and the `app.js` for `/reviews` looks like this:

```js

// reviews.app.js

const express = require('express')
const app = express()
const port = process.env.PORT  || 3000

app.get('/', (req, res) => res.json([{
  id: "2",
  title: 'Oh snap what an ending',
  grade: 5,
  comment: 'I need therapy after this...',
  product: 1
}]))
app.listen(port, () => console.log(`Example app listening on port port!`))
```

Looks almost the same right? Well, we try to keep things simple for now and return static data but it's quite simple to add database later on.

### Dockerizing
Before we start Dockerizing we need to install our dependency `Express` like so:

```
npm install express
```
This needs to be done for each service.

Ok, we showed you in the directory for each service how there was a `Dockerfile`. It looks like this:

```
// Dockerfile

FROM node:latest
WORKDIR /app
ENV PORT=3000
COPY . .
RUN npm install
EXPOSE $PORT
ENTRYPOINT ["npm", "start"]
```

Let's go up one level and create a `docker-compose.yaml` file, so it's easier to create our images and containers. Your file system should now look like this:

```
docker.compose.yaml
/products
  app.js
  Dockerfile
  package.json
/reviews
  app.js
  Dockerfile
  package.json
```

Your `docker-compose.yaml` should have the following content:

```
version: '3.3'
services: 
  product-service:
    build:
      context: ./products
    ports:
      - "8000:3000"
    networks: 
      - microservices
  review-service:
    build:
      context: ./reviews
    ports:
      - "8001:3000"
    networks:
      - microservices
networks: 
  microservices:
```
We can now get our service up and running with 
```
docker-compose up -d
```
I always feel like I'm starting up a jet engine when I run this command as all of my containers go up at the same time, so here goes, ignition :)

![](https://thepracticaldev.s3.amazonaws.com/i/249uosy83g8lv4soyfhk.gif)

 
You should be able to find the products service at `http://localhost:8000` and the reviews service at `http://localhost:8001`. That covers the microservices for now, let's build our GraphQL API next.

Your products service should look like the following:
![](https://thepracticaldev.s3.amazonaws.com/i/8gdvh8xmjzage2cnkeqs.png)

and your review service should look like this:
![](https://thepracticaldev.s3.amazonaws.com/i/l1cmklaig3j0w6olr9tk.png)


## Implementing GraphQL
There are many ways to build a GraphQL server, we could be using the raw `graphql` NPM library or the `express-graphql`, this will host our server in a Node.js Express server. Or we could be using the one from Apollo and so on. We opt for the first one `graphql` as we will ultimately serve it from a Serverless function. 

So what do we need to do:

1. Define a schema
2. Define services we can use to resolve different parts of our schema
3. Try out the API

### Define a schema
Now, this is an interesting one, we have two options here for defining a schema, either use the helper function `buildSchema()` or use the raw approach and construct our schema using primitives. For this case, we will use the raw approach and the reason for that is I simply couldn't find how to resolve things at depth using `buildSchema()` despite reading through the manual twice. It's strangely enough easily done if we were to use `express-graphql` or `Apollo` so sorry if you feel your eyes bleed a little ;)

Ok, let's define our schema first:

```js
// schema.js

const { 
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLInt,
  GraphQLNonNull,
  GraphQLList,
  GraphQLString
} = require('graphql');

const {
  getProducts,
  getReviews,
  getProduct
} = require('./services');

const reviewType = new GraphQLObjectType({
  name: 'Review',
  description: 'A review',
  fields: () => ({
    id: {
      type: GraphQLNonNull(GraphQLString),
      description: 'The id of Review.',
    },
    title: {
      type: GraphQLString,
      description: 'The title of the Review.',
    },
    comment: {
      type: GraphQLString,
      description: 'The comment of the Review.',
    },
    grade : {
      type: GraphQLInt
    },
    product: {
      type: productType,
      description: 'The product of the Review.',
      resolve: (review) => getProduct(review.product) 
    }
  })
})

const productType = new GraphQLObjectType({
  name: 'Product',
  description: 'A product',
  fields: () => ({
    id: {
      type: GraphQLNonNull(GraphQLString),
      description: 'The id of Product.',
    },
    name: {
      type: GraphQLString,
      description: 'The name of the Product.',
    },
    description: {
      type: GraphQLString,
      description: 'The description of the Product.',
    }
  })
});

const queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    hello: {
      type: GraphQLString,
      resolve: (root) => 'world'
    },
    products: {
      type: new GraphQLList(productType),
      resolve: (root) => getProducts(),
    },
    reviews: {
      type: new GraphQLList(reviewType),
      resolve: (root) => getReviews(),
    }
  }),
});

module.exports = new GraphQLSchema({
  query: queryType,
  types: [reviewType, productType],
});
```

Above we are defining two types `Review` and `Product` and we expose two query fields `products` and `reviews`. 

I want you to pay special attention to the variable `reviewType` and how we resolve the `product` field. Here we are resolving it like so:
```
resolve: (review) => getProduct(review.product) 
```
Why do we do that? Well, it has to do with how data is stored on a Review. Let's revisit that. A Review stores its data like so:

```
{
  title: ''
  comment: '',
  grade: 5
  product: 1
}
```
As you can see above the `product` field is an integer. It's a foreign key pointing to a real product in the product service. So we need to resolve it so the API can be queried like so:
```
{
  reviews {
    product { 
      name
    }
  }
}
``` 
If we don't resolve `product` to a product object instead the above query would error out.

### Create services
In our `schema.js` we called methods like `getProducts()`, `getReviews()` and `getProduct()` and we need those to exist so we create a file `services.js`, like so:

```js
const fetch = require('node-fetch');

const getProducts = async() => {
  const res = await fetch(process.env.PRODUCTS_URL)
  const json = res.json();
  return json;
}

const getProduct = async(product) => {
  const products = await getProducts()
  return products.find(p => p.id == product);
} 

const getReviews = async() => {
  const res = await fetch(process.env.REVIEW_URL)
  const json = res.json();
  return json;
}

module.exports = {
  getProducts,
  getReviews,
  getProduct
}
```

Ok, we can see above that methods `getProducts()` and `getReviews()` makes HTTP requests to URL, at least judging by the names `process.env.PRODUCTS_URL` and `process.env.REVIEW_URL`. For now, we have created a `.env` file in which we create those two env variables like so:

```
PRODUCTS_URL = http://localhost:8000
REVIEW_URL = http://localhost:8001
```
Wait, isn't that? Yes, it is. It is the URLs to `product service` and `review service` after we used `docker-compose` to bring them up. This is a great way to test your Microservice architecture locally but also prepare for deployment to the Cloud. Deploying to the Cloud is almost as simple as switching these env variables to Cloud endpoints, as you will see in the next part of this article series :)

### Trying out our GraphQL API

Ok, so we need to try our code out. To do that let's create an `app.js` file in which we invoke the `graphql()` function and let's provide it our schema and query, like so:

```js
const { graphql } = require('graphql');
const rawSchema = require('./raw-schema');
require('dotenv').config()

const query = `{ hello products { name, description } reviews { title, comment, grade, product { name, description } } }`;

graphql({
  schema: rawSchema,
  source: query
}).then(result => {
  console.log('result', result);
  console.log('reviews', result.data.reviews);
})
``` 

In the above code, we specify a query and we expect the fields `hello`, `products` and `reviews` to come back to us and finally we invoke `graphql()` that on the `then()` callback serves up the result. The result should look like this:

![](https://thepracticaldev.s3.amazonaws.com/i/vdtbebrdrgiobwsxep8q.png)

## Summary
We set out on a journey that would eventually lead us to the cloud. We are not there yet but part two will take us all the way. In this first part, we've managed to create microservices and dockerize them. Furthermore, we've managed to construct a GraphQL API that is able to define a schema that merges our two APIs together and serve that up. 

What remains to do, that will be the job of the second part, is to push our containers to the cloud and create service endpoints. When we have the service endpoints we can replace the value of environment variables to use the Cloud URLs instead of the localhost ones we are using now. 

Lastly, we need to scaffold a serverless function but that's all in the next part so I hope you look forward to that :)