Combining APIs using GraphQL schema stitching: Part 1

20190117 blog graphql tbd 01

APIs and the services behind them have changed how we build software. I like to explain APIs as Lego blocks for developers. They're little building blocks that you can put together to build something bigger. You might have to glue to build a really big model but the individual pieces are necessary for the end-result.

How much do developers love APIs? The answer is: a lot. 50% of apps built today use 2-5 APIs, while 9% of apps use more than 25 APIs* . But as anyone who is a parent would know, when you have a lot of Legos, you will eventually step on one and it hurts.

With that many APIs, you’ll need to understand:

  • Which API holds what data
  • How you authenticate against each API — how to get the necessary access permissions.
  • Which fields in your API responses indicate a reference (a foreign key in database speak) to another API, then how you would find that API and resolve it. This gets complex if you have as many as 25 APIs on a project.

Getting to know everything is a Herculean task. Luckily, GraphQL makes some of that easier. If all your APIs use GraphQL, discovering how APIs work and what data is available becomes much easier. But we still need to know what API holds which data and how it relates to data in other APIs.

What if we could have everything in one API?

Maybe Legos aren’t the right metaphor for APIs. Maybe APIs are more like music. Because music can be mashed up. A mashup is a song that’s created by blending two existing songs together. If you listen to two different songs one after the other, and then proceed to make a mashup and listen to it, you’ll be able to hear the two original songs. But if you listen to the mashup first, it probably won’t cross your mind that it’s made from two different songs.

Let me explain how we can apply this concept to APIs. At Contentful, we have a lot of open source projects. Just our main GitHub organization has over 100 open source repositories. It’s starting to become difficult to keep track of them so what we need is a dashboard to give an overview of what’s happening in our open source ecosystem. I can pull that information on GitHub, store some metadata in Contentful and pull information from other services. For instance, TravisCI, which already knows if a test succeeded for a project and this info does not need to be replicated somewhere else.

A brief overview on GraphQL

Why do developers like to use GraphQL?

  • Unlike a RESTful API where you don’t know what data to get unless you have a specification for it, GraphQL allows you to specify exactly what data you want and get just that data
  • You can also opt to get all the data you want with just one API request, instead of having to make multiple requests
  • It’s also introspectable — so you can reason about an API programmatically, even if it’s one you have never touched before
  • The biggest plus is that it enables frontend-driven data selection — it really empowers people working on the frontend, whether that’s a mobile app or web app, to have more control over the data than ever before
  • Last but not least, it’s composable (the reason for this article) so one could take multiple GraphQL APIs and unify them into one

All those advantages come at an upfront cost of a difficult amount of work involved to get it working reliably. So if you, your team or organization want to start using GraphQL, know that it’s not an easy technology that you can simply hash over your existing API.

Due to how it works and what it enables, GraphQL can be terrifying for backend engineers. Frontend developers, however, think it’s amazing.

In the past years since being developed by Facebook, GraphQL has grown in popularity — many public and private APIs now make use of GraphQL, including GitHub whose API v4 based on GraphQL.

The core of GraphQL: Its schema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type Repository implements Node {
  owner: RepositoryOwner!

  url: URI!

  stargazers(
    first: Int

    after: String

    last: Int

    before: String

    orderBy: StarOrder
  ): StargazerConnection!
}

The core part of every GraphQL API is its schema. The excerpt above is from GitHub’s GraphQL API. It’s a type repository that implements an interface called Node and some of the properties you have on the interface. You see an owner here, which links to another object type called RepositoryOwner. The bang at the end means that it’s never null and always defined. It also has a URL and a connection to the stargazers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
query {
  repository(
    owner: "contentful",
    name: "contentful.js"
  ) {
    url,
    stargazers {
      totalCount
    }
    owner {
      login
    }
  }
}

Next I’m going to write a query. This is a simple query to access the GitHub API. I specify the organization to be contentful, with the name contentful.js which is Contentful’s JavaScript SDK and specify what information I want to retrieve:

  • The URL to access the repository
  • How many stargazers there are
  • The organization in which it exists
1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "data": {
    "repository": {
      "url": "https://github.com/contentful/contentful.js",
      "stargazers": {
        "totalCount": 454
      },
      "owner": {
        "login": "contentful"
      }
    }
  }
}

What I get back is a JSON object. If you look closely, you can see the structure of the JSON object matches that of my query. Even if it’s an API I’ve never touched before that someone else wrote, I can reason about the data that the API will return just by looking at the query, without having to read any documentation. Being able to form an interpretation just by looking at the code is really powerful when dealing with APIs that are unfamiliar to you and is one of the strengths of GraphQL.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const {ApolloServer, gql} = require('apollo-server');

// The GraphQL schema
const typeDefs = gql`
    type Query {
        hello: String
    }
`;

// A map of functions which return data for the schema.
const resolvers = {
  Query: {
    hello: () => 'world'
  }
};

async function startServer() {
  const server = new ApolloServer({ typeDefs, resolvers });

  return await server.listen();
}

startServer().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

How do I write a GraphQL API? Let’s write a Hello World together. First, I’m going to import an ApolloServer.Apollo has released a lot of great tooling around GraphQL which I will use throughout the article. ApolloServer is the very basic machinery to setup a server that responds to GraphQL queries.

We always start by writing a schema. In this case our schema contains just one query with the name hello that will return a string. With a schema, I’ve only defined what’s possible but I actually need to write the code that responds to any incoming GraphQL query as well. Namely, a resolver. For every query and object type, you’ll want to write a resolver function that gets passed to ApolloServer, that returns the data requested by the user.

When it all comes together

In this example, it’s easy since I only have to write a resolver for hello that returns a string, then start ApolloServer. If I access this through a GraphQL client, I can see my schema and introspect it. With a query that simply queries hello and I get the word world back which is a string so it matches the schema. Again, the result matches the structure of the query.

Result matches the structure of the query

First thing I did is store all the data for projects, that GitHub doesn’t know about, in Contentful. I can model my own data there so I’ve modeled a repository, team, group and department. What I’m doing here is maintaining information about which repository is owned by which team in Contentful.

Maintaining information about which repository is owned by which team in Contentful

Much like having two separate music tracks that I want blended into a single mashup, I now have two APIs, GitHub and Contentful, but what I want is a unified version of this data and that’s my stitching proxy.

*Source: Global Development Survey 2017 Vol. 1, Evans Data Corp

Updates in your inbox

Subscribe to receive the most important updates. We send eNewsletters once a month that cover trending topics and feature updates.