What’s all the hype about GraphQL?
Wrapping a REST API with GraphQL
3 ways GraphQL can transform your API for better data retrieval
There’s been a lot of hype around GraphQL so we decided to jump on board.
Resources to follow along:
- Node & npm
- Visual Studio Code (or your favorite editor)
- WhereDPump API (This endpoint is open)
Why GraphQL?
- REST does not give us any schema definition for the data returned by any of our API endpoints. GraphQL was built around strongly typed schemas for each endpoint
- We have to constantly change the code on the Backend to return exactly what we need on the frontend, i.e we’re constantly over fetching or under fetching fields.
- We had the classic N+1 problem with REST. We can now make a single request to retrieve the data we need.
Let’s Dive!
Our Pumps endpoint: /pumps
This returns a list of pumps as follows:
There is a ton of information here we don’t need in our mobile app but we get all this data when we make a request to the /pumps
endpoint. Wouldn’t it be nice if we can just specify what we needed? GraphQL to the rescue!
GraphQL Basics
A GraphQL service starts by defining a type and fields. Fields also have a type. Let’s convert our Pumps to a type to clarify.
type Pumps { objectId: ID!
name: String
Details: String,
verified: Boolean,
price: Int,
location: String,
country: String,
flyer: Flyer}
// Omitted some fields for brevity
Here we create a type
and name it Pumps
. Then we specify fields like name, Details, verified, etc and their types like String
, Boolean
and Int
.
Notice objectId: ID!
In GraphQL ID
is a type for a unique identifier (it is a string). The exclamation point means it cannot be null. Lastly, we see flyer: Flyer
. Flyer is our own type that we must define so let’s do that next.
type Flyer { name: String
url: String}
Awesome! In GraphQL we can define our own types as we did here with Flyer
.
Defining the Entry Point for Our GraphQL API
Now we need to provide a Query
type. GraphQL has root types and Query
is one root type used to specify the entry point for every GraphQL query.
type Query { pumps: [Pumps]}
This now sets the entry point for our query as pumps
and we set the type to [Pumps].
The square brackets denote a list so our query is expected to return a list of Pumps
.
To invoke this endpoint we structure a query as follows:
query {
pumps {
objectId
name
views
}
}
The above query will perform a query
on pumps
and return objectId
name
and views
for each object. Notice we are only specifying 3 fields in our query, GraphQL will only return these fields to us. At this point you might be wondering, where does the data come from? We’ll discuss this next
Fetching Data with Resolvers
Each field of a GraphQL query is backed by a function called a resolver
. The resolver function, to be implemented by the developer, is responsible for fetching the data for a Query
field. In our example we have a pumps
field on our Query
type. Let’s implement a resolver for this.
const resolver = {
Query: {
pumps: () => {
return fetch('https://devapi.wheredpump.com/pumps').then(res => res.json()); } }}
When a query is executed on the pumps field this resolver
is called. The resolver can fetch data from any database, a REST API as we have done here or even another GraphQL server. Now we’ll bring all our skills together and setup a server.
Setting up the server
Create a directory calledGraphQL_Server
or any name you prefer and cd into it.
Next run npm init -y
. This will create a package.json
file for us.
In your current directory run npm i graphql-yoga node-fetch
Create a file and name it schema.graphql
Copy and paste the following into that file:
type Query { pumps: [Pumps]}type Pumps { objectId: ID!
name: String
Details: String,
verified: Boolean,
price: Int,
location: String,
country: String,
flyer: Flyer}type Flyer { name: String
url: String}
Create a file and name it index.js
copy and paste the following into that file:
Let’s walk through this code.
Lines 1–2:
Here we import GraphQLServer
from graphql-yoga
, this is to setup our GraphQL server and fetch
from node-fetch. Node-fetch allows us to use the browsers fetch API.
Line 4:
We are creating a variable for our base url for our fetch request.
Lines 6–15:
This is our resolver from earlier. It tells GraphQL where to grab the data when the pumps
field on the Query
type is executed. i.e Our REST API endpoint https://devapi.wheredpump.com/pumps
Lines 17–20:
Here we create a new GraphQL Server and pass in an object with two keys as the parameter:
- typeDefs — which tells the server where to find the schema. Here we provide the path to our
schema.graphql
file. - resolvers — which tells the server where to get the resolvers. We pass in our resolvers object from earlier.
We then save the result of GraphQLServer to a const called server
.
Line 23:
We call start on the server object and pass in console.log statement so we get some output in the command line that our server is running.
Now all that’s left to do is to run node index.js
in your current directory (GraphQL_Server) and visit http://localhost:4000
in your browser. If you followed everything correctly you should see this in your browser:
Hooray! We’ve wrapped our pumps
endpoint with GraphQL. One major advantage for us we didn’t show here is how we solved the N+1 request problem. With our Rest API we first make a request to retrieve pumps then for each pump we make a request to get its location.
With GraphQL we are now able to make a single request like this:
To read more about GraphQL visit this link: How to GraphQL
Happy Coding!