Connectors

As fun as it may be, your GraphQL API is unlikely to be of much use if it doesn’t connect to other systems, be it databases, third-party APIs or alike.

One of the beauties of the architecture imposed by GraphQL (remember all that single responsibility stuff?) is that introducing third-party connectors is both trivial for the developer (you) and completely transparent for the client.

Since resolvers are responsible for fetching the value of a single field, it is easy to imagine that, within a single query response, values could be coming from multiple storages and third-party APIs at the same time, without the client ever being affected.

Refactor the link type

Connecting Mongo DB

For this project, you’ll use MongoDB as the persistent storage, but by following the exact same approach you can integrate any other third-party system as the underlying provider for your resolvers.

  1. First off, install MongoDB on your computer

  2. Having that done, add MongoDB Java driver

  3. Thanks to the decision to extract the logic for saving and loading links into the LinkRepository class, introduction of MongoDB now has a very localized impact.

  4. Update the allLinks method in the Query class to now call linkRepository.getAllLinks() instead of linkRepository.allLinks().

  5. You’ll also have to update GraphQLEndpoint to connect to MongoDB.

That’s all! Restart Jetty, fire up GraphiQL and give it a spin! Just make sure you create some links before querying them. Everything should still work the same except you won’t lose the saved links if the power goes out.

Performance

You may have noticed that the execution strategy seen so far is somewhat naive. Imagine the link descriptions are stored in a different database. That would mean for a query like this

query links {
  allLinks {
    description
  }
}

the resolver for the description field (invoked once for each link in the result) would query that other database as many times are there were links. This a classic example of the N+1 problem. The solution for this is to batch multiple requests and resolve them in one go. In case of a SQL database, the desired resolver would look like:

SELECT * FROM Descriptions WHERE link_id IN (1,2,3) // fetch descriptions for 3 links at once

DataLoader

In JavaScript and a few other languages, a popular way to implement this strategy is the DataLoader utility. The Java implementation of DataLoader can be found here.

As an alternative, graphql-java offers BatchedExecutionStrategy, which looks for resolvers (DataFetchers in graphql-java lingo) annotated by @Batched. Such resolvers are expected to take a list of source objects and return a list of results. For the example above, that would mean taking a list of links (List<Link>) and returning a list of descriptions (List<String>). Update: graphql-java-tools now supports batched data fetchers as of this commit!

Unlock the next chapter
Where can a GraphQL server store data to and load data from?
Graph databases, like Neo4j, OrientDB, Arango etc
GraphQL servers do not store or load data
Any persistent storage, e.g. MongoDB
Anywhere