Exploring GraphQL
Tags: graphql, tutorial
Published: 2020-08-18 01:29:36

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](https://www.youtube.com/watch?v=PeAOEAmR0D0) 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](https://developer.github.com/v4/explorer/). 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](https://github.com).

# 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`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zf0e1hdxqums7w8mck0s.png)

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!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z7q6awzwxtfuydgaxnfw.png)

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`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/faeurb2mxr4kp8u819wq.png)

# 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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7i697nsgaes4qk502wxf.png)

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`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qqsliuvhu078en08skdd.png)

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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bzr6j4hrnlfd9qo1cbbd.png)

# 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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ikulk0j683prsvn9xfbb.png)

We have two root types, `query` and `mutations` the latter which we will go over later on.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0r9ax7zqowzrr1qdh2lm.png)

If we click `query` we are met with a list of all the possible fields that we can use.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9gw9b3oteud4ebtmpp74.png)

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. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/po4xddbxos0smokfuxvg.png)

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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5pxspowu6t3mo1j0xdn9.png)

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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fixq32avmds8soy2oomy.png)

# 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: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6vj1la7xsosksspbyh26.png)

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:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uolzgpgq5xq5qb8ciyow.png)

`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` or `last` value to properly paginate the `repositories` 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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5dwmbunso8vd8vwun5t9.png)

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`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7w27sifi0655zb30hygw.png)

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!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6n658xu2m98w62yew3xn.png)

# 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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kvoeb9eo9iqgpoc1b6mw.png)

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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s9vy4oaprtgkln3meofu.png)

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](https://github.com/pswk1/graphql-tests/issues).

I will write a query to find this repo and its ID, which we will need to make our mutation. Keep this ID closeby!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lxqbm36638x4orwf0twv.png)

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`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/04mkcvxiim0h7aa7pn36.png)

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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cgt0uvv68fweyo1j8s40.png)

Here is a look at our query, variable, and response:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vgu48gt5zkcc0o10tvp2.png)

And finally, if we take a look at the repository on Github, we can see that the issue was created.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/096jiiyaxoco6eqnp1mv.png)

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:

* [peeterkang@gmail.com](mailto:peeterkang@gmail.com)
* [LinkedIn](https://www.linkedin.com/in/peterswkang/)
* [Portfolio](https://www.pswk1.dev/)
* [Github](https://github.com/pswk1)