Building GraphQL Schema from RESTful API

Many developers get attracted by GraphQL’s benefits over REST, the current API standard. GraphQL shines with the ability to provide only the data fields you specify. While typical RESTful API requires loading from multiple URLs, GraphQL API takes out all the data your app needs in a sole request to just one URL.

Let’s imagine you already have an existing RESTful API, but your task requires using GraphQL either you just want to try it out of curiosity. In this case you would need to wrap your REST in GraphQL Schema and hardcoding all the GraphQL Types is a real pain.

Asking ourselves how to simplify the process we came up with an idea of wrapping mature RESTful APIs in GraphQL with automated GraphQL Types generation. The concept is simple: we pass a JSON response from some RESTful API into the function which determines types of its fields and returns a GraphQL Type that we can further modify and use in our Schema.

What we got is small, but nevertheless useful graphql-compose-json NPM package.

npm install graphql-compose-json

We’d tried to wrap SWAPI RESTful API using this package and found it super convenient.

Our GraphQL SWAPI can source code:

https://github.com/lyskos97/graphql-compose-swapi

and resulting LIVE DEMO here:

https://graphql-compose-swapi.herokuapp.com


Type Creation

Building a GraphQL Schema starts with complex Types declaration. In order to create a Type you have give it a unique name and specify it’s fields list. Each REST endpoint can be referred to as complex Type. Of course, Types may be declared manually, but it’s faster and more convenient to generate them directly from RESTful API response.

The key feature of graphql-compose-json is it’s composeWithJson function which receives JSON as argument and returns a TypeComposer which holds GrahpQLObjectType in its getType() method.

Additionally you can define fields directly in your JSON using arrow functions (see mass and starships_count field):

Arrow functions should return Field Config (type, args and resolve) or a sole type. In fact, you may pass type as a string (‘Int’, ‘Float’, ‘String’, ‘Boolean’, ‘ID’, ‘Date’, ‘JSON’)

or a SDL string (‘ID!’ is equivalent to new GraphQLNonNull(GraphQLID), '[ID!]' is equivalent to new GraphQLList(new GraphQLNonNull(GraphQLID))).

Furthermore, SDL can shorten this:

up to this:

Quite handy, isn’t it?

Data Fetching

As our Types got defined, we need show the Schema how to request data for them. It requires resolve methods to be defined in our Schema. The purpose of these methods is to request data from external service storage and transform it to the form of Type which the resolve method belongs to. Besides that, GraphQL allows to declare arguments of our resolve methods to perform data filtration and sorting.

Valid data request requires three pieces: resolve(data fetching method), args(list of acceptable input arguments) and type(data representation form). GraphQL terms label these three a Field Config (or Resolver).

So graphql-compose-json allows you to define fetch methods yourself and doesn’t force you to use its parental graphql-compose toolkit — you’re free to write with vanilla GraphQL Schema definition:

Fetching several people at once:

Relating Types

Now as we can declare Types, request them, it’s time to link these Types with each other. This is the exact stage where GraphQL enormously simplifies work for clients that request data. Typical scenario of a query to RESTful API: client requests a piece of data, receives it and request other resources according to the first server response it got, while GraphQL implements the same logic on the server’s side and sends back nested data of any depth.

To make such nesting possible you’ve got to link Person and Film Types with each other. For that you need to create films field in your Person Type. This field will return the list of films where the Person was starred in. In previous step we considered Field Config creation, so we now paste it here:

Using vanilla GraphQL

Using graphql-compose

You can use methods of TypeComposer as well. It allows you to pass predefined resolvers of other Types to your response object and create relations between your Types:

Whereas findByUrlList resolver is defined in Film.js:

findByUrlList is can be reused in any other relation to fetch arrays of films.

Building Schema

Now that you’ve got your Types created, linked and taught how to fetch data, it’s time to create your single entry point which is called GraphQLSchema. It has three properties: query, mutation and subscription and at least one of them must have a GraphQLObjectType set. Normally you should create a Type named Query for query property and list there all the fields you want to see at the first level of your Schema available to request. For example, you want clients be able to access a person by ID and a list of films. Here you need to do the same you did when linking two Types:

Vanilla GraphQL

graphql-compose

Reducing requests

It often happens that when we make nested data some documents are requested several times within a single query. We surely do not want our app to re-iterate requests of the same data and show itself down impairing user experience. That’s when Facebook dataloader’s caching feature is of use.

Simply create an instance of Dataloader alongside your express setup. The reason for such placement is the scope of caching: we want dataloader to cache requests within a single GraphQL query only.

Pass the Dataloader instance to the context field of graphqlHTTP to make your loader accessible all across the Schema.

dataloader is really easy to use:

P.S. dataloader also has an awesome function of query batching, we suggest you to check it out.


What we’ve got so far

We’ve started with bare JSON response from RESTful API and ended up building a Schema with the Type generated by graphql-compose-json. Type we got is easily manageable and scalable as well as the resulting Schema: we may tune them with custom fields, custom fetching methods and relations with other Types.