Wrapping a REST API in GraphQL
Wrapping a REST API in GraphQL
GraphQL has been, for the last couple of years, been one of the ‘hottest stack’ in the tech scene and it has continued to be adopted by many companies for the benefits it brings. Some have claimed that GraphQL will be the REST killer of which, I think, isn’t entirely true in my opinion.
One thing I can attest to is the benefits that GraphQL brings to the table when you are building web and mobile applications. I am not going to talk about the benefits in this post but you can learn about them here and about the similarities and differences here
Instead, I am going to show you how you can start using GraphQL without changing your current architecture and with the least investment possible. Let’s get right to it.
What we are going to build
We are going to build a Star Wars GraphQL API from a REST API that will let you query for characters using the People
field — which will have a PersonType
and it will expose the following fields
- Name
- Gender
- Vehicles
- Films
- Species
- Starships
The above fields will each have a GraphQL<type>
depending on the shape of the returned value. I will explain expound on GraphQLTypes
in the next section.
GraphQL Schema, Object types and Fields
Let’s have a look at our schema and the fields we want to expose to our API.
The most basic components of a GraphQL schema are object types, which just represent a kind of object you can fetch from your service, and what fields it has.
For instance, in our API we will define a PersonType
which will be of type GraphQLObjectType
and will have a couple of properties attached to it as follows;
- name: This is the name property that we will use to query with.
- description: Is an optional description and acts as some sort of documentation for other devs in your team who will be consuming the API
- fields: property is a function that returns an object with other fields attached to the root property. In our case, a
PersonType
will have the following fields;name, gender, vehicles, species, films, starships
all of which will be of either of typeGraphQLString
meaning it’s value will be astring
orGraphQLList(GraphQLString)
meaning that it returns an array containingstrings
. - resolve: which is a function that returns a value attached to the field name property. The fact that this is a function that can return any value is huge for it opens up so many possibilities. It means we can return a
<Promise>
from some API among other things. This means you can do something like;
....gender: {type: GraphQLString,description: 'A star wars gender',resolve: () => fetch(`${BASE_URL}/people/${args.id}`).then(response => response.json()).then(person => person.gender)}...
See the simplified schema below of the PersonType that we will use so as you have an idea.
const PersonType = new GraphQLObjectType({name: 'Person',description: 'A star wars Character',fields: () => ({name: {type: GraphQLString,description: 'A character\'s name',resolve: (person) => person.name},
gender: {type: GraphQLString,description: 'A character\'s gender',resolve: (person) => person.gender},})});
As for our REST API, we will use the Star Wars API . This can be any REST API that you currently have setup and the same principles and concepts should work.
The code and how to run it
At this point I assume that you have node installed. If not, download and install it here.
Follow the steps and commands below;
- Download the source code or run the command below
git clone git@github.com:joeynimu/graphql-user-api.git
- Change directory and install dependancies by running
cd graphql-user-api && npm install
- Start the application by running
npm start
. At this point you should see something like this on your terminal
- Visit http://localhost:5000
What you see is called graphiql; an in browser IDEA which lets you explore a GraphQL API. On the left hand side is where you write the query that you would like to execute, the middle is where your results will appear and on the right is a documentation that allows you to see the available fields to query.
On the query side, clear everything and copy paste the below query and click the play
button at the top;
{
People {
name
gender
vehicles
films
species
starships
}
}
You should see the below data on the results pane.
{
"data": {
"People": [
{
"name": "Luke Skywalker",
"gender": "male",
"vehicles": [
"https://swapi.co/api/vehicles/14/",
"https://swapi.co/api/vehicles/30/"
],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/",
"https://swapi.co/api/films/7/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": [
"https://swapi.co/api/starships/12/",
"https://swapi.co/api/starships/22/"
]
},
{
"name": "C-3PO",
"gender": "n/a",
"vehicles": [],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/5/",
"https://swapi.co/api/films/4/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/2/"
],
"starships": []
},
{
"name": "R2-D2",
"gender": "n/a",
"vehicles": [],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/5/",
"https://swapi.co/api/films/4/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/",
"https://swapi.co/api/films/7/"
],
"species": [
"https://swapi.co/api/species/2/"
],
"starships": []
},
{
"name": "Darth Vader",
"gender": "male",
"vehicles": [],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": [
"https://swapi.co/api/starships/13/"
]
},
{
"name": "Leia Organa",
"gender": "female",
"vehicles": [
"https://swapi.co/api/vehicles/30/"
],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/",
"https://swapi.co/api/films/7/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": []
},
{
"name": "Owen Lars",
"gender": "male",
"vehicles": [],
"films": [
"https://swapi.co/api/films/5/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": []
},
{
"name": "Beru Whitesun lars",
"gender": "female",
"vehicles": [],
"films": [
"https://swapi.co/api/films/5/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": []
},
{
"name": "R5-D4",
"gender": "n/a",
"vehicles": [],
"films": [
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/2/"
],
"starships": []
},
{
"name": "Biggs Darklighter",
"gender": "male",
"vehicles": [],
"films": [
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": [
"https://swapi.co/api/starships/12/"
]
},
{
"name": "Obi-Wan Kenobi",
"gender": "male",
"vehicles": [
"https://swapi.co/api/vehicles/38/"
],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/5/",
"https://swapi.co/api/films/4/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": [
"https://swapi.co/api/starships/48/",
"https://swapi.co/api/starships/59/",
"https://swapi.co/api/starships/64/",
"https://swapi.co/api/starships/65/",
"https://swapi.co/api/starships/74/"
]
}
]
}
}
That feels satisfying right! Alright, we have another query of a specific person which we can get by running the below query;
{
Person(id:"1"){
name
gender
vehicles
films
species
starships
}
}
As you can see from the query above, we are passing an id parameter
of 1. The above should give you the below results;
{
"data": {
"Person": {
"name": "Luke Skywalker",
"gender": "male",
"vehicles": [
"https://swapi.co/api/vehicles/14/",
"https://swapi.co/api/vehicles/30/"
],
"films": [
"https://swapi.co/api/films/2/",
"https://swapi.co/api/films/6/",
"https://swapi.co/api/films/3/",
"https://swapi.co/api/films/1/",
"https://swapi.co/api/films/7/"
],
"species": [
"https://swapi.co/api/species/1/"
],
"starships": [
"https://swapi.co/api/starships/12/",
"https://swapi.co/api/starships/22/"
]
}
}
}
Unlike our first query which returns an array of People, this one returns a specific person.
Conclusion
At this point we have created a GraphQL API using an existing REST API without changing its underlying code or infrastructure. I hope you have gotten a basic idea of how you can start using GraphQL with the least investment and risk possible. Have a look at the code and see how you can adopt and implement this pattern on your own API’s and extend it even further by adding more functionality.
We have only used theQuery
operation on this example but graphQL offers two more operations;
- Mutations: For
Creating
Updating
andDeleting
data - Subscriptions: For creating and maintaining realtime connection to the server.
There is also a new advanced pattern called schema stitching which comes in handy if you are using a Micro Service based architecture with multiple GraphQL based API’s. You can create an API gateway that aggregates all of then in one place using schema stitching.