Building a Mock Blue Bottle GraphQL API
Tags: graphql, showdev, webdev, tutorial
Published: 2019-06-23 20:32:08

_Cover Photo by Gerson Cifuentes on Unsplash_

## tl;dr
* At Eve Porcello's and Alex Bank’s GraphQL Workshop, I built a mock Blue Bottle GraphQL API using `apollo-server` and `faker`.
* `apollo-server` allows you to add mock resolvers for all of your types in your GraphQL Schema.
* `interface`s in GraphQL help you make your GraphQL API more organized/scalable by creating a relationship between similar GraphQL types. 
* You can play around with my final example in the GraphQL Playground here:
{% codesandbox blue-bottle-blog-post-9xrk7 %}
* Check out my Github repository here:
{% github https://github.com/iwakoscott/mock-blue-bottle-graphql-api %}

## Introduction

I recently had the opportunity to attend a GraphQL Workshop by [Eve Porcello](https://twitter.com/eveporcello) and  [Alex Banks](https://twitter.com/MoonTahoe). In one of the labs, we were tasked with creating our own GraphQL Schema to mock one of our favorite web applications. (If you aren’t familiar with a GraphQL Schema, a schema defines all of the possible operations (mutations and queries,) and types from your GraphQL endpoint. It is pretty much the blueprint for your GraphQL API.) I decided to try to mock one of my favorite e-commerce websites: [bluebottlecoffee.com](bluebottlecoffee.com). 

_Disclaimer: I don’t work for Blue Bottle. I just like their website (and some of their coffees.)_

## My Process 💭

I started by browsing the [coffee](https://bluebottlecoffee.com/store/coffee)  route and got to work:

![blend coffee section on bluebottlecoffee.com](https://thepracticaldev.s3.amazonaws.com/i/fnsqpcmcknkyl4qkjs0c.png)

![single origin section on bluebottlecoffee.com](https://thepracticaldev.s3.amazonaws.com/i/1116u0gbihcy84mi7jsi.png)

I immediately noticed they divided the coffees into two sections:  Blends and Single Origin coffees. (For any non-coffee connoisseurs,  a blend consists of coffees from multiple countries, whereas a single origin coffee comes from a single farm, multiple farms in a similar area, or, from multiple farms from the same country.)  This sounds like a great place to use an `enum` type.  An `enum`  or “enumeration” type is a collection of named values (used in many different programming languages.)  This is how you define an `enum` type in GraphQL:

```graphql
enum SourcingType {
  BLEND
  SINGLE_ORIGIN
}
```

Let’s include the `SourcingType` within our `Coffee` type:

```graphql
type Coffee {
  id: ID!
  sourcingType: SourcingType!
}
```

I’ve also added a unique `id` to each coffee. (The `!` at the end of `ID` and `SourcingType` defines a non-nullable field.) Great, let’s add more properties to a `Coffee` type. Both Single Origin and Blend coffee share common properties that I’ve marked out in the diagrams below:

![a card for a coffee blend.](https://thepracticaldev.s3.amazonaws.com/i/eorovpuyuc6r6c30xgv5.png)

![a card for a single origin coffee.](https://thepracticaldev.s3.amazonaws.com/i/tb34cbw2ebolbxfres71.png)

A. An image URL
B. A sourcing type (Single Origin or a Blend)
C. The name of the coffee
D. Flavor Profiles / Notes
E. Unit Price
F. Unit Weight

Let’s add these to our schema:

```diff
   type Coffee {
     id: ID!
     sourcingType: SourcingType!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
   }
```

* `String` and `Float` are primitive scalars in GraphQL.
* `[String!]!` looks a little spooky 👻 at first, but all this means is that the `flavorNotes` property expects a non-nullable array of non-nullable strings. We expect at a minimum, an empty array.

Our schema looks great but, let’s make it more Robusta (this is not a typo, this is a terrible coffee dad joke.)  We will:

* define a `Coffee` interface and create a `SingleOrigin` and `Blend` type and
* add queries to our Schema.

## The `Coffee` Interface ☕️
Recall - coffees come in two types: Blends and Single Origin coffees. They share exactly the same properties but, what if we wanted to include information about the country of origin for each coffee? A blend will include many different countries, whereas, a single origin coffee will only have one. It would be nice to be able to abstract the `Coffee` type and create two new types - `SingleOrigin` and `Blend`  that use the `Coffee` type as a base.

*  A `SingleOrigin` type will have a property called `country` while, 
* the `Blend` type will include a property - `countries`. 

 `countries` and `country`  will return type `Country` (which we will construct later.)  The only difference is that the `countries` property on a `Blend` will be `[Country!]!`  (an array of countries) and the `country` property on a `SingleOrigin` will be `Country!`  (one country.) 

This all sounds great, but, how do we implement this into our schema? In GraphQL, there is a special `interface` type that defines a base data type to be used to implement other similar types. Let’s use this to create a `Coffee`  base type.

```diff
-  enum SourcingType {
-    BLEND
-    SINGLE_ORIGIN
-  }
-
-  type Coffee {
+  interface Coffee {
     id: ID!
-    sourcingType: SourcingType!
     name: String!
     flavorNotes: [String!]!
     unitPrice: Float!
   }
```

Notice that the `interface` includes all properties from the previous `Coffee` type however, the `sourcingType` is removed. We no longer need this property since we are going to organize our coffees into `Blend` and `SingleOrigin` types so, this property can be inferred. To create `Blend` and `SingleOrigin` we will need to use a special keyword: `implements` to define a relationship between our new types and the base `Coffee` interface.

```graphql
type Blend implements Coffee {
  # ...
}

type SingleOrigin implements Coffee {
  # ...
}
```

Now let’s give our new types some properties!  You might be thinking it would suffice to do this:

```graphql
type Country {
  id: ID!
  name: String!
}

type Blend implements Coffee {
  countries: [Country!]!
}

type SingleOrigin implements Coffee {
  country: Country!
}
```

This is what I initially thought as well. Since we are explicitly defining a relationship between our new types and the base `Coffee`  interface using the `implements` keyword, you might think it is inferred that these new types will inherit everything from the `Coffee` interface. Our Schema, however, needs to be as explicit as possible. This means that we must redefine all properties from the `Coffee` interface to our respective types.

```diff
  type Country {
    id: ID!
    name: String!
  }

   type Blend implements Coffee {
+    id: ID!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
     countries: [Country!]!
   }
 
   type SingleOrigin implements Coffee {
+    id: ID!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
     country: Country!
   }
```
 
## Adding Queries for Coffee! 🌱
Our schema is looking great however, we have not defined any queries in our schema. To do so we will define a `type Query` which will hold all queries from our GraphQL API.

```graphql
type Query {
  allCoffee: [Coffee!]!
  allSingleOrigin: [SingleOrigin!]!
  allBlends: [Blend!]!
}
```

We’ve defined three different queries: 
1. `allCoffee` will return all coffees in our database: `Blend` and `SingleOrigin`,
2. `allSingleOrigin` will return all `SingleOrigin` coffees, and
3. `allBlends` will return all `Blend` coffees.

## Adding our Schema to `apollo-server`  🚀

Let’s start by cloning the repository I’ve created for you by running:

```bash
git clone https://github.com/iwakoscott/mock-blue-bottle-graphql-api.git
```

After cloning my repository, run  `cd mock-blue-bottle-graphql-api` and run `npm install` to download dependencies. Let’s start coding! We will begin by requiring `apollo-server` by writing:

```javascript
const { ApolloServer } = require("apollo-server");
```

In the same file, let’s create another variable - `typeDefs` that will hold on to our Schema we’ve been building as a string template.

```diff
// ...
+const typeDefs = `
+  interface Coffee {
+    id: ID!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
+  }
+
+  type Country {
+    id: ID!
+    name: String!
+  }
+
+  type Blend implements Coffee {
+    id: ID!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
+    countries: [Country!]!
+  }
+
+  type SingleOrigin implements Coffee {
+    id: ID!
+    name: String!
+    flavorNotes: [String!]!
+    unitPrice: Float!
+    unitWeight: Float!
+    imageURL: String!
+    country: Country!
+  }
+
+  type Query {
+    allCoffee: [Coffee!]!
+    allSingleOrigin: [SingleOrigin!]!
+    allBlends: [Blend!]!
+  }
+`;
```

Let’s now create a new instance of `ApolloServer`  and pass in our schema.

```diff
// ...
+  const server = new ApolloServer({
+    typeDefs,
+  });
```

We now have an `ApolloServer` instance with our schema. You might be wondering: “This is great and all but, how are we resolving the queries specified in our schema?” We don’t have any  [resolver functions](https://graphql.org/learn/execution/#root-fields-resolvers) let alone a database or any micro-services to get data from. We definitely can’t get real data but, we can get close!  I want to show you the power of mocked resolvers in  `apollo-server`. 

## Building Mock Resolvers  🦜
Let’s begin by installing my favorite package for creating fake data:  [faker](https://www.npmjs.com/package/faker) 

```bash
npm install --save-dev faker
```

We’ll create an object literal and save it in a new variable called `mocks`:

``` diff
+  const mocks = {
+
+  };
```

Now what we want to do is mock out *all* custom types we’ve defined in our schema:

* `Blend`,
* `SingleOrigin`, and
* `Country`

I will demonstrate how to mock out a `Blend` type (*I leave* `Country` *and* `SingleOrigin` *as an exercise for the curious reader. Check out my  [Github repository](https://github.com/iwakoscott/mock-blue-bottle-graphql-api/tree/master) for my implementation.* )

```diff
+  const faker = require('faker');
+
+  function getRandomPrice() {
+    const randomPrice = Number(faker.finance.amount(12, 22, 2));
+    return Math.round(randomPrice * 10) / 10;
+  }
+
const mocks = {
+  Blend: () => ({
+    id: faker.random.number(),
+    name: faker.commerce.productName(),
+    flavorNotes: [
+      faker.commerce.productAdjective(),
+      faker.commerce.productAdjective()
+    ],
+    unitPrice: getRandomPrice(),
+    unitWeight: faker.random.number({ min: 8, max: 12 }),
+    imageURL: faker.image.imageUrl()
+  })
};
```

* “What about the `Coffee` interface?” The interface is no longer is treated as a `type`, instead `Coffee` defines a relationship between all types that `implements` this interface.
* How about the `Query` type?  The `Query` type doesn’t need to be mocked since all queries: `allCoffee`, `allSingleOrigin`, and `allBlends` will resolve with our custom `types` that we’ve already mocked out.

### Starting our `apollo-server`  ▶️
After mocking out the rest of the custom types, we are now ready to see all of our hard work come to life. Let’s add our `mocks` to our server instance, start our server, and listen to requests for coffee ☕️ :

```diff
 const server = new ApolloServer({
   typeDefs,
+  mocks
 });
+
+  server
+    .listen(4001)
+    .then(({ url }) =>
+      console.log(`Listening for coffee orders on ${url}... ☕️`);
```

Run `npm run start` in your terminal and wait until you see 

> “Listening for coffee orders on http://localhost:4001/... ☕️”

Now open up your favorite browser and navigate to: http://localhost:4001/
You should see the GraphQL Playground.

![GraphQL Playground graphical user interface.](https://thepracticaldev.s3.amazonaws.com/i/4ffemr485r4yyqk1he4u.png)

This is where we will ~~order~~ query our coffee. The left panel is where we will write our queries, and our response will appear on the right panel after clicking the play button. On the very right-hand side of the browser, you might have noticed the two tabs - DOCS and SCHEMA. SCHEMA will show you your raw schema you’ve defined and passed to the Apollo server instance, and the DOCS will present your schema in a nice, human-readable way. 

![GraphQL Playground DOCS tab.](https://thepracticaldev.s3.amazonaws.com/i/0l6tp1mua022uk4cixl4.png)

Let’s write our first query! In the left panel type in the following query and click the “play” button.

```graphql
query {
  allSingleOrigin {
    id
    name
    flavorNotes
    unitPrice
    unitWeight
    imageURL
    country {
      id
      name
    }
  }
}
```

If everything went accordingly, you should see a response in the right panel:

![our first GraphQL query in the playground.](https://thepracticaldev.s3.amazonaws.com/i/jpltklkeczdgduykk3zp.png)

Let’s now try querying for `allCoffee`. This is where things get a little bit more interesting.  Recall that `allCoffee` query will return both `SingleOrigin` and `Blend`.

How would you write a query for `allCoffee`  and include properties that are exclusive to each type of coffee? In our example, `SingleOrigin` has a property `country` while a `Blend` has property `countries`.  Unfortunately, you cannot just include both properties in the query, otherwise, you will get an error:

![GraphQL Error](https://thepracticaldev.s3.amazonaws.com/i/bygfq9a3ko5cicc9sa52.png)

The error gives us a helpful hint, however:

> Did you mean to use an inline fragment on "SingleOrigin"?

An  [inline fragment](https://graphql.org/learn/queries/#inline-fragments)  takes on an interesting syntax that looks similar to the [ES6 Spread Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) :

```graphql
query {
  allCoffee {
    id
    name
    flavorNotes
    unitPrice
    unitWeight
    imageURL
    ... on SingleOrigin {
      country {
        id
        name
      }
    }
    ... on Blend {
      countries {
        id
        name
      }
    }
  }
}
```

We use the `...` and we use the `on` keyword to specify which type the fragment is coming from. We then provide the properties we want from the specific type. Go ahead and run the updated query in the playground!  Since the data is randomly generated, you might get a response back with only  `Blend`,  only  `SingleOrigin` or a mix of both!  Super cool! 😎
 
### One Last Detail
You might have noticed a warning in the console:

> Type "Coffee" is missing a "__resolveType" resolver. Pass
 false into "resolverValidationOptions.requireResolversFo
rResolveType" to disable this warning.

Whenever you are working with an interface, our resolvers need a little bit of assistance identifying which type is what (I don’t know about you but, even a connoisseur like me can’t taste the difference between a blend and a single origin coffee.) We only included mock resolvers,  so, to fix this error we need to create a new object literal called `resolvers`  and add a property `Coffee` on to it, along with this `__resolveType`  function.

```diff
+  const resolvers = {
+    Coffee: {
+      __resolveType: coffee => (coffee.countries ? 'Blend' : 'SingleOrigin')
+    }
+  }
+
 const server = new ApolloServer({
   typeDefs,
   mocks,
+  resolvers
 });
```

The first argument, `coffee` of `__resolveType` refers to the coffee currently being resolved.  If the `coffee` has property `countries` we can assume it is a `Blend` otherwise, it is a `SingleOrigin`. Now if you re-run the server, the warning should be gone! 🚀

## Final Words
Getting a GraphQL server up and running is so simple with `apollo-server`. You don’t even need to have to write resolvers, let alone have a database or micro-services to get data from. You can define a schema and mock all of your data until you are ready to connect to an actual source. Lastly, I want to make a special shout out to  [Eve Porcello](https://twitter.com/eveporcello) and  [Alex Banks](https://twitter.com/MoonTahoe) for giving me an opportunity to attend one of their  [GraphQL Workshops](https://www.graphqlworkshop.com/).  Keep an eye out for any workshops in your area. I highly recommend it! Also, check out their  [Learning GraphQL](http://shop.oreilly.com/product/0636920137269.do) O’Reily book - a great place to start to learn the fundamentals of building Full Stack GraphQL Applications. ✌️