Anna Collins
Posted on January 16, 2020
I’ve just started at Codegram as a junior developer and my first week has been mostly preparing for the first project I’ll be working on by learning some GraphQL 🙌. My work experience is almost all front end based, so this was a good chance to delve into the back end a bit, which I have been wanting to do for quite some time. The chance to learn new technologies and skills was one of the things which attracted me to Codegram in the first place and I was looking forward to getting stuck in!
So what actually is GraphQL anyway? GraphQL is a language used to query an API for data by stating exactly what data you want to get back. The difference between GraphQL and REST is that with GraphQL, the client asks for the specific data they need, and gets this data (and only this data) back, whereas with REST, this might sometimes require making multiple calls to the API to retrieve all the required data, whilst receiving a lot of unnecessary data at the same time.
Hmm, ok. Still not sure I totally understand the difference, so let’s look at an example. Imagine I have a REST API to interact with data on Burger restaurants in Barcelona. I love burgers and I want to fetch a list of all the restaurants’ names, with all the different burgers they have, and a list of the toppings on each burger. This may mean that I have to perform multiple calls, one to fetch a list of all the restaurants, /restaurants
, then one for each restaurant to fetch a list of their burgers, /<restaurantId>/burgers
, and then one for each burger to fetch its toppings, /<burgerId>/toppings
. That’s quite a lot of calls, and I will surely receive unwanted data along the way, for example when I fetch the restaurants I might receive its address and rating, which I’m not interested in right now.
“So just create a new endpoint fetching the data you need in one call” I hear you say. Yes, this could be a solution, but it’s not really feasible to be pestering the back end folks for a new endpoint every time you need a different set of data, is it?
Let’s see how we could make the same call with GraphQL (getting back only what we ask for).In GraphQL we don’t have different endpoints, we make all calls to the same endpoint, only changing the payload we pass.
query {
restaurants {
name
burgers {
name
toppings {
name
}
}
}
}
So the simplest version of a request is kind of like querying keys on an object. The returned value that we get is in the same shape as the request, so we know exactly what we are expecting in return. The shapes of the objects you’re able to query are defined in the schema, which is defined in the server. To create a GraphQL server, we need to define all the types and operations, and also what are called resolvers, which is how we resolve each operation, normally being interacting with our database.
For example in our case, we have three different entities, restaurants, burgers and toppings, so our schema for these would be defined something like this
type Restaurant {
id: ID
name: String
address: String
rating: Int
burgers: [Burger]
}
type Burger {
id: ID
name: String
rating: Int
toppings: [Topping]
}
type Topping {
id: ID
name: String
}
As you can see, each property on each entity has a type. There are 5 scalar types to choose from:
-
Int
: A 32-bit integer -
Float
: A floating point value -
String
: A UTF-8 character sequence -
Boolean
: true or false -
ID
: A unique identifier
Or it can be one of one of our custom types defined above (or an array of any of these types).
As well as defining the types we have, we must also define the operations that we can perform on our data. With GraphQL we have 3 different types of operation:
-
Query
: A read only fetch. We can think of this as what would be aGET
in REST -
Mutation
: A write followed by a fetch. We can think of this as like aPOST
,PUT
orPATCH
request in REST. -
Subscription
: Allows the client to subscribe to an event and receive real time updates from the server when there are changes. There is no simple REST equivalent to this operation.
For our burger API, we could for example define the following queries
type Query {
restaurants: [Restaurant],
burgers: [Burger],
toppings: [Topping],
restaurant(id: ID): Restaurant,
burger(id: ID): Burger,
topping(id: ID): Topping
}
We would also need to provide resolvers for each of these queries. This would usually involve reading from our database to return the required entry(s). I’m not going to go into detail here as I want to keep this post general and language agnostic.
You can see that the last three operations also take in an argument, being the ID of the entry you want to query. For example, if we wanted to query a specific restaurant, we could query by its ID to retrieve its name and the name of its burgers as follows:
query {
restaurant(id: 1234) {
name
burgers {
name
}
}
}
A new burger restaurant has opened in Barcelona, hurrah! 🎉 We now need to add it to our database. So we need to define a new mutation in our schema as follows:
type Mutation {
createRestaurant(id: ID, name: String, address: String, rating: Int): Restaurant
}
The operation takes an ID
, name
, address
and a rating
as arguments and returns us the created restaurant when done. (Again, we would create a resolver for “createRestaurant” in our server, usually writing an entry to our database.) So let’s go ahead and add it
mutation {
createRestaurant(
Id: "12345",
name: "Anna’s Burger Joint",
address: "Carrer Aragó 191",
rating: 5
){
name
id
}
}
From the returned restaurant entry, we can select whichever values we like from it, in this example I have chosen to receive the name and ID.
As you may have guessed, I’m a huge burger fanatic, so I would love to be notified whenever a new restaurant is added to the database 😍. For this I could use the Subscription operator. I would create a subscription that returns a restaurant to the client listening whenever a new restaurant is added to the database. I’m not going to go into detail in this post about how subscriptions work as they are slightly more complicated than Query and Mutation. Rather than returning data directly, they return an AsyncIterator which is used to send data back to the client.
So after a first peek at GraphQL, I must say, it seems pretty cool! We have way more control over the data we receive when we make a call to our back end, and when we make the call we know the shape of the response we are expecting in return. This can be especially useful for example if you require different data across different devices or if you don’t know the use case. To use REST and simply creating different endpoints for each device is exactly the problem we are avoiding by using GraphQL. I can’t wait to learn more about it and start using it in real life projects ❤️
If you want to learn more about GraphQL, they have great docs so I suggest starting there. And if you can't wait to give it a go and start playing around making queries, you can try here with the Star Wars GraphQL API. Just click on the docs tab on the right and start exploring!
Posted on January 16, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
December 24, 2023