Peter Kang
Posted on August 18, 2020
As I broaden my developer skillset, I've discovered that reiterating is a great method of reinforcing what I learned, and writing is one of the best mediums to do so. Thank you for visiting and I hope that you're able to take something away from this as well!
What is GraphQL?
GraphQL is a query language that was created by Facebook to address the data fetching challenges faced when attempting to get data from server to client. Contrary to popular belief, it can be used with many programming languages to implement a graph server.
GraphQL vs REST API
Generally, fetching large amounts of data from REST API's may end up tricky since requests may use many different endpoints, resulting in a unsavory response time.
With GraphQL, we can define and send a query to a GraphQL server. A query looks similar to a JSON object. Let's say we want to get the data of a certain Pokémon. An example query would look like this:
{
pokemon {
name
type
}
}
The response looks similar to the query:
{
"data": {
"pokemon" {
"name": "blastoise"
"type": "water"
}
}
}
As we change the data that we need, we can update query by adding to it. It is nested and issued at once! For example, we can add more fields after type
and there may even be more nested fields after that.
One benefit that came to mind was loading UI components. We can utilize one call to get the data that we need and populate the component accordingly! So neat.
For a more in-depth look (and quite frankly a much better explanation than I can provide at the moment) into REST vs GraphQL, I've found that this video does an excellent job.
Let's Try It! Github API/GraphiQL
To try it out, we'll be using Github's GraphQL API and the GraphiQL interface. This is essentially an in-browser IDE that allows us to make queries to the Github API. We can get started here. We will need to be signed into a Github account, or make one if you don't have one yet. Both can be accomplished here.
Queries
When we build queries, we ask for the values of fields. The most basic field we can start with in the Github GraphQL Explorer is the viewer
field, like so:
{
viewer {
}
}
Within viewer, we can add a subfield of login
by nesting it within viewer
.
{
viewer {
login
}
}
We can hit the button that looks like the "play" symbol and the query will be sent to the server. The response looks very similar to a JSON object. If you have a username set up in your Github settings, it should be returned here. Otherwise, it may return null
.
In addition, you'll notice that there is some auto-complete behavior when entering fields. We can also access all the possible fields by hitting ctrl + space
. Try playing around with all the possible fields we can explore!
Let's get some more information like our bio, id, and profile picture. We can get this data by entering the fields name
, bio
, and avatarURL
.
Arguments
There are fields that can be take arguments. For example repositoryOwner
can take arguments to return data about just that. We can see that it takes login
as an argument. Let's look up Facebook, its id
, its path (the subfield is referred to as resourcePath
), and its url
. Please note that in GraphQL, we must use double quotes.
Some fields require arguments. Such a field is the repository
field. We can see that the name
and owner
arguments are required since those two pieces of information are required to get a single repository. Let's look up GraphQL's GraphiQL repository and get its description
.
Any attempts to make queries without required arguments will result in an error. For example, if we try to query repository
without the owner
argument, we would get the following error:
Schemas
Fields are determined by GraphQL schemas. These schemas provide the object types used in our data, and they specify the types for all the values. An advantage of using the GraphiQL interface is that the schemas are well documented in the browser.
In the Github GraphiQL interface, if we click on Docs
on the right side, we can see the available schemas.
We have two root types, query
and mutations
the latter which we will go over later on.
If we click query
we are met with a list of all the possible fields that we can use.
Let's scroll down and click the repository
field. Once we do, we can see that it has two arguments, name
and owner
. They are specified to have a String
type and the exclamation point denotes that they are required arguments.
Try exploring the query
schema and all the fields we can explore in the Github GraphQL API.
Querying __schema
What if we are outside the GraphiQL interface? We can query __schema
to check out the architecture and all the possible values. Let's do just that. We will query __schema
, and from there we will choose queryType
, which is one of two root types in the schema. In queryType
, we will query name
, description
, and fields
. Finally, within fields
, we will query name
and description
once more. The resulting query and response will look like this:
Note that there is a description of the root query
type. After that, the response lists all the possible fields we can utilize with their names and description. Neat!
Aliases
Let's say that we want to query two repositories. We can utilize aliases to do so. For example we will query for the react-native and create-react-app repositories. In this case, I will give them aliases as reactNativeRepo
and createReactAppRepo
, respectively. Each of them will be followed by a colon, and their respective queries. In these queries, let's look for their respective names, descriptions, and URLs. They will be nested in one big query, like so:
Fragments
Note that in our previous query, we are querying the same three fields. This doesn't seem like very DRY code, so we can utilize fragments. We can utilize fragments to shorten our code a bit and have reusable bits of our queries. The fragment will take this form:
fragment fragmentName on objectType {
fields
}
So, in our case, our fragment will look like this:
fragment repoInfo on Repository {
id
description
homepageUrl
}
Finally, we can include our fragment with a spread operator before it in our query. It will look like this:
Nice! We now have a reusable bit of query that we can use elsewhere without repeating the same fields.
Nested Fields
Let's say we have the following query:
{
viewer {
id
name
location
repositories
}
}
We will get the following response:
edges
indicates a connection to another array of data. The field node
in this case represents a single repository. In addition, you'll notice the error message,
You must provide a
first
orlast
value to properly paginate therepositories
connection.
Here, we must pass in an argument into repositories
so that the server knows which repositories to look for. I'll pass in last: 3
to get the last three repositories, as well as name
in the node
field to get their names.
Check out the other arguments for repositories
for other ways you can query the repos! In addition, explore the repositories
field in the Docs and take note of what you see there.
We can make a fairly complex query with multiple nested fields. The beauty of it is that we can grab large amount of data with just one call!
Operation Names
We can add the word query
at the beginning of our queries. It will function the same way. However, in a codebase of complex queries, it may be hard to keep track of. As a result, we can add the word query
followed by an identifying name.
For example, let's give our previous query a name of getLastRepos
. In addition, I'll duplicate the query and instead get the first three repos. This will be named getFirstRepos
.
As a result, when we hit the play button to make the queries, we are given options to query because of the operation names we gave our queries. This can be deeply useful when we have many queries!
Variables
Let's now explore the organization
field. I have the following query that search Facebooks first three members.
{
organization(login:"facebook") {
id
name
membersWithRole(first: 3) {
edges {
node {
id
name
}
}
}
}
}
However, we can use variables to search other organizations using variables. First, let's reformat our query. First, we'll give our operation a clear name. Next, we'll pass in $login: String!
to our operation which indicates that the login
variable will be a String type and that is required.
Next, in the organization
field, we'll replace "facebook" with login
.
query getFirstThreeMembers($login: String!){
organization(login: $login) {
id
name
membersWithRole(first: 3) {
edges {
node {
id
name
}
}
}
}
}
Now, where do we define these variables? At the bottom of the interface, we notice a section we haven't used yet, Query Variables
. Let's bring it up.
In there, we will define login, and this time we'll set it to "google". As a result, the first three members of Google's organization in Github will return in the response.
Awesome!
Mutations
We've gotten data thus far, but how do we change it? In GraphQL we will utilize mutations. We can think of mutations as similar to PUT or DELETE requests when working with REST APIs. In GraphQL, we can send data as a payload in a mutation. The dataset is changed, and the API defines which mutations can be performed. Check out the Docs in the Github GraphiQL to see which mutations we can perform.
For our demonstration purposes, I will be using a mutation to create an issue in one of my repositories. For these purposes, I've created a repository named graphql-tests. Its issues tab will can be found here.
I will write a query to find this repo and its ID, which we will need to make our mutation. Keep this ID closeby!
Next, we'll write our mutation query. We will start with the mutation type, and give it a name, createIssue
. If we explore the docs for creating a new issue via mutation, we'll see that the payload consists of a clientMutationId
and issue
. We will create an input variable that contains our payload.
Next, we will enter the createIssue
field with input: $input
as arguments. It will contain the aforementioned clientMutationId
and issue
, and within issue
, we'll include id
, body
, and title
.
Excellent! Now all we have to do is define our input variable.
The input payload has two requirements, a unique clientMutationId
which we can set to whatever we'd like, and the repositoryId
which we got from our first query. In addition, we included body
and title
in our mutation query so let's include that as well.
Here is a look at our query, variable, and response:
And finally, if we take a look at the repository on Github, we can see that the issue was created.
Awesome! There are so many different mutations we can perform with this API alone. Each GraphQL API will have its queries and mutations documented so the possibilities are endless!
Conclusion
I hope that this article provided you with some value and a way to get your feet wet with GraphQL. Writing it has been a great way to reinforce what I've learned thus far. Thank you for taking the time to read and explore.
If you'd like to connect, reach me here:
Posted on August 18, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 29, 2024