Graphql In Action
Exploring Graphql Apis
This is still a work in progress. New content is synced here as it gets ready.

Exploring GraphQL APIs

This chapter covers

  • Using GraphQL’s in-browser IDE to test GraphQL requests

  • Exploring the fundamentals of sending GraphQL data requests

  • Exploring read and write example operations from the GitHub GraphQL API

  • Exploring GraphQL’s introspective features

  • Exploring auto-generated GraphQL APIs

The easiest way to start learning about the powerful features of the GraphQL language is to use its feature-rich interactive in-browser IDE. This IDE leverages GraphQL’s type system to give you features that you can use to explore what you can do with GraphQL and to write and test your GraphQL requests without leaving your browser. Using this IDE, we will continue to explore examples of GraphQL queries and mutations. We’ll look at the fundamental parts of a GraphQL request, we will test examples from the official GitHub GraphQL API, and we will also test a GraphQL backend-as-a-service tool.

1. The GraphiQL editor

When thinking about the requests that you need your client applications to make to servers, you could benefit from a graphical tool that can help you to first come up with these requests and then test them before you commit to them in application code. Such a tool can also help you improve these requests, validate your improvements, and debug any of the requests that are running into problems. In the GraphQL world, this tool is called GraphiQL (with an "i" before the QL and pronounced as Graphical). GraphiQL is an open source web application that it is written entirely with React.js and GraphQL itself, and it can simply be run in a browser.

GraphiQL is one of the reasons why GraphQL is popular. It is very easy to learn and it will be a very helpful tool for you. I guarantee that you will simply LOVE it. It is one of my favorite tools for front-end development and I cannot imagine working in a GraphQL-based project without it.

You can download GraphiQL and run it locally but an easier way to get a feeling of what this tool has to offer is to use it with an existing GraphQL API service like the Star Wars one that we previewed in Chapter 1.

Head over to az.dev/swapi-graphql in your browser. The page that loads up under that URL has the GraphiQL editor, which works with the Star Wars data and is publicly available for you to test. Here is what it looks like:

ch02 fig 01 gqlia
Figure 2. 1. The GraphiQL editor at az.dev/swapi-graphql

This editor is a simple 2-pane application where the left pane is the editor and the right pane is where the result of executing your GraphQL requests will appear.

Go ahead and type the following simple GraphQL query in the editor:

Listing 2. 1. Query for person
{
  person(personID: 4) {
    name
    birthYear
  }
}

This simple GraphQL query asks for the name and birth year of the person whose ID is 4. To execute the query, you can press Ctrl+Enter or press the run button (with the little black triangle). When you do, the result pane will show the data that the query is asking for:

ch02 fig 02 gqlia
Figure 2. 2. Executing queries with GraphiQL

The best thing about this GraphiQL editor is that it provides intelligent type-ahead and auto-completion features that are aware of the GraphQL type schema you are currently exploring. For the previous example, this means that the editor is completely aware that there is a person object that has name and birthYear fields. In addition, the editor has live syntax and validation error highlighting for any text you type.

The awesome features in GraphiQL are all possible because of the documentation GraphQL schema. With one big query to the server, this editor can know about everything that server can offer.

To explore these features, clear the editor pane (you can select the whole text in the editor with Ctrl+A). Then, just type an empty set of curly brackets: {}. Place your cursor within this empty set and hit Ctrl+Space. You get an auto completion list like this:

ch02 fig 03 gqlia
Figure 2. 3. GraphiQL’s type-ahead list

This is nice! You can very quickly start exploring what fields this GraphQL API is offering right there in the editor while you are thinking about your requests. The person field we used before is one of the items in this list.

This list will also be used to auto-complete fields as you type them. Type “p” and notice how the list is now changing to highlight what starts with “p”. Then, continue typing an “e” and see how the list will only highlight the person field. Hit Enter to "pick" the currently highlighted item in the list.

The great thing about this type-ahead list is its context-awareness. It shows you the fields available on the level where you are typing. For example, now that we picked the person field, go ahead and type another empty set of curly brackets after the word "person" and put your cursor within this new set and bring up the type-ahead list with Ctrl+Space. You should see a new list now and this time the list will have all the fields that you can ask for within the context of a person object!

ch02 fig 04 gqlia
Figure 2. 4. GraphiQL’s type-ahead list is context-aware

This is extremely helpful, and I am not talking about the less typing aspect of it but rather the discoverability and validation aspects which enable you to be faster and make less mistakes. This is an example of the power and control I was talking about in the previous Chapter. This is how GraphQL is different.

Before we pick the fields name and birthYear again, note how one of the closing curly brackets has a red underline. This is part of the live error highlighting you also get in this tool. Discard the type-ahead list by pressing Esc and hover your mouse cursor over that underlined curly bracket. You should see an error complaining about some unexpected syntax. This is because the text we have in the editor so far is not valid GraphQL syntax yet. Every time you start a new level of curly brackets, which is known as a "selection set", that selection set needs to have fields of its own.

Go ahead and pick the fields name and birthYear within the person field. The query syntax is now valid (the red underline is gone) but the query is still missing one important piece, and this time, it is not a syntax problem.

You can always execute the query to see what the server has to say about it. If the server rejects the query, it will most likely give you a good reason why it did. For example, executing the query we have right now will return the following:

Listing 2. 2. Example GraphQL error response
{
  "errors": [
    {
      "message": "must provide id or personID",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "person"
      ]
    }
  ],
  "data": {
    "person": null
  }
}

Note how this error response was a normal JSON response (a 200-OK one) and how it is giving us back two top-level properties: one errors property that is an array of error objects and a data property that represents an empty response. A GraphQL server response can represent partial data when that server has errors about other parts of the response. This makes the response more predictable and makes the task of handling errors a bit easier.

The error message here was a helpful one. The path "person" must provide id or personID. Since we are asking the server about ONE person, it needs a way to identify which person’s data to return. Note again that this was not a syntax problem but rather a missing-required-value problem.

To make a path provide a value, we use syntax similar to calling functions. Place the cursor right after the word "person" and type the "(" character. GraphiQL will auto-complete that and show you a new type-ahead list that, this time, is aware of what values can be provided as arguments for the person field.

ch02 fig 05 gqlia
Figure 2. 5. Exploring field arguments with the type-ahead list

Now you can pick the personID argument, give it a value of 4, and get back to the same query that we started with, but this time, you discovered the elements that you needed through the powerful features of the GraphiQL editor.

Besides discovering the structure and types of these elements inline while you type them, you can browse the "Docs" section to see full lists and more details about them. Click the "Docs" link in the top-right corner of the editor. You should see a search box that you can use to find any type within the current GraphQL schema. I typed the word "person" and picked the first result. This is showing the schema type "Person" with its description and fields:

ch02 fig 06 gqlia
Figure 2. 6. GraphiQL shows the documentation schema

Take a moment to explore more of what this GraphiQL editor has to offer. Try more queries and get a feeling of how easy it is to come up with them.

2. The basics of the GraphQL language

To ask any GraphQL server for data, you send it a request written in the GraphQL query language. A GraphQL request is a tree of fields. Let’s explore these two fundamental concepts of the language.

2.1. Requests

At the core of a GraphQL communication is a request object. The source text of a GraphQL request is often referred to as a document. A document contains text that represents a request through operations like queries, mutations, and subscriptions. In addition to the main operations, a GraphQL document text might contain fragments which can be used to compose other operations as we will see in the next chapter.

A GraphQL request might also contain an object to represent values of variables that might be used in the request document text. The request might also include meta information about the operations. For example, if the request document contains more than one operation, a GraphQL request must include information about which operation to execute. If the request document contains only one operation, the GraphQL server will just execute that. You do not even need to label the operation with a name in that case, but naming operations is a good practice to follow.

ch02 fig 07 gqlia
Figure 2. 7. The structure of a GraphQL request

Let’s look at a full GraphQL request. Here is a hypothetical example of that (don’t worry about the new syntax you’ll see here just yet):

Listing 2. 3. Example GraphQL request: Document
query GetEmployees($active: Boolean!) {
  allEmployees(active: $active) {
    ...employeeInfo
  }
}

query FindEmployee {
  employee(id: $employeeId) {
    ...employeeInfo
  }
}

fragment employeeInfo on Employee {
  name
  email
  startDate
}

Since this document uses generic variables (the ones starting with the $ sign), we need a JSON object to represent values specific to a request. For example:

Listing 2. 4. Example GraphQL request: Variables
{
  "active": true,
  "employeeId": 42
}

Also, since the document contains more than one operation (GetEmployees and FindEmployee), the request needs to provide the desired operation to be executed. For example:

Listing 2. 5. Example GraphQL request: Meta Information
operationName="GetEmployees"

If we send all three elements of this request to a GraphQL server, it will parse the whole document, pick the GetEmployees query, fill the variables values, and return the result of that query.

There are three types of operations that can be used in GraphQL:

  • Query operations that represent a read-only fetch

  • Mutation operations that represent a write followed by a fetch

  • Subscription operations that represent a request for real-time data updates

We will see practical examples of these operation in the next section of this chapter.

The example in listing 2.3 represented a query operation. Here is a hypothetical example of a mutation operation:

Listing 2. 6. Example GraphQL mutation operation
mutation {
  addRating(storyId: 123, rating: 5) {
    story {
      averageRating
    }
  }
}

The mutation operation in listing 2.6 will add a new 5-star rating record for a story and it will then retrieve the new average rating of that same story. Note how this is a write followed by a read. All GraphQL mutation operations follow this concept.

The mutation operation in listing 2.6 did not have a name. An anonymous operation is okay if it is the only operation defined in the document. If the anonymous operation is a query, we can also omit the word "query". This is what we did when we started exploring the GraphiQL editor.

Here is a hypothetical example of a subscription operation:

Listing 2. 7. Example GraphQL subscription operation
subscription StoriesRating {
  allStories {
    id
    averageRating
  }
}

The subscription operation in listing 2.7 will instruct the GraphQL server to open a socket connection with the client, send stories' IDs along with their average ratings, and keep doing that when that information changes on the server. This feature is a much better alternative to doing "continuous polling" of data to keep a UI view up-to-date.

2.2. Fields

One of the core elements in the text of a GraphQL request is the field. The most simplified way to think about a GraphQL request is to think about it as a way to select fields on objects.

A field always appears within a selection set (inside a pair of curly brackets). A selection set is primarily composed of fields.

A field in GraphQL describes one discrete piece of information that you can retrieve about an object. It could be describing a scalar value (like the name of a person or their birth year), or it could describe an object (like the home planet of a Star Wars character), or it could describe a list of objects (like the list of films in which a Star Wars character appeared). For the last two cases, their fields will contain another selection set to customize the information needed about the objects that are described by them.

Here is an example GraphQL query that has examples of different types of fields:

Listing 2. 8. GraphQL fields
{
  me {
    email
    birthday {
      month
      year
    }
    friends {
      name
    }
  }
}

The fields email, month, year, and name are all "scalar" fields. Scalar types represent primitive "leaf" values. GraphQL schemas often support 4 major scalar types: Int, String, Float, and Boolean. There is also the built-in custom scalar value ID that can be used to represent identity values. We’ll see an example of that in Chapter 4.

The name "leaf" comes from Graph theory. It means a vertex with no children.

You can also customize a GraphQL schema to support more scalar values with certain formats. For example, a schema can be designed to have a Time scalar value to represent a time value in a standard and parsable format (ISO/UTC). We’ll see an example of that in Chapter 7.

The fields me and birthday are fields that describe objects, and therefore they needed their own nested selection sets. The field friends describes a list of friend objects and therefore it also needed a nested selection set to represent each object in that list.

All GraphQL operations must specify their selections down to fields which return scalar values (leaf values). They cannot, for example, have fields that describe objects without providing further nested selection sets to specify which scalar values to fetch for these objects. The last nested level of fields should always consist of only fields that describe scalar values. For the example in listing 2.8, if you do not specify the nested selection set for the field friends (the { name } part), the GraphQL query would not have been valid because not all of the last nested level fields would be describing scalar values in that case.

The "root fields" in an operation usually represent some information that is globally accessible to your application and its current user.

I’ll use the term root field to refer to the first-level fields in a GraphQL operation.

Some typical examples of root fields include references to a current logged‐in user. For example:

{
  me {
    fullName
  }
}

In this query, the field “me” usually represents the currently logged-in user. Some API services name this root field viewer.

Root fields are also usually used to access certain types of data referenced by a unique identifier. For example:

# Ask for the user whose ID equal to 42
{
  user(id: 42) {
    fullName
  }
}

In this query, the field user represents one of many users in a graph of data. To instruct the server to pick one user, we specify a unique ID value for the user field.

Note how in the previous example the # character was used to write a comment about the query. This is the official character to comment a single line (or remainder of a line) in a GraphQL document. There is no supported way to have multiline comments in GraphQL documents, but you can just have many lines that each start with the # character. The server will just ignore all the comments. It will also ignore any extra spaces, all the line terminators, and all insignificant commas between the fields. All these characters can be used to improve the legibility of source text and emphasize the separation of tokens. They have no significance to the semantic meaning of GraphQL documents.

3. Examples from the GitHub API

Now that we know about requests, documents, queries, and fields, let’s put this knowledge to use and explore some real-world examples of GraphQL requests for which you can ask the GitHub API. GitHub moved from REST APIs to GraphQL APIs in 2017. We can use their GraphQL API explorer at az.dev/github-api, which is an embedded GraphiQL editor that will include the proper authentication headers for the API (you need to be logged in with a GitHub.com account).

You can also use a standalone GraphiQL editor to explore the GitHub API (see az.dev/graphiql-app). You’ll have to manually include an access token in that app. You can use this standalone app with any GraphQL API service.
ch02 fig 08 gqlia
Figure 2. 8. The GraphiQL editor for the GitHub API

Let’s first look at some common queries from this API.

This GitHub API makes use of your real, live, production data at GitHub.com

3.1. Reading data from GitHub

When you first launch the GitHub GraphQL API explorer, it has a default simple query that will display your own login. The currently logged-in user is represented by the field “viewer”. Under this field, you can read all the information that is available about you at GitHub.

For example, here is a query to see information about the last 10 repositories that you own or contribute to:

Listing 2. 9. Query for the last 10 repositories for logged-in user | az.dev/gia
{
  viewer {
    repositories(last: 10) {
      nodes {
        name
        description
      }
    }
  }
}

Here is another query to see all the supported licenses in GitHub along with their URLs:

Listing 2. 10. Query for all GitHub-supported licenses | az.dev/gia
{
  licenses {
    name
    url
  }
}

Here is a more complex query to find the first 10 issues of the "facebook/graphql" repository. It asks for the name of the author and the title that was used for the issue page along with the date that issue was created:

Listing 2. 11. Query for the first 10 issues of a repository | az.dev/gia
{
  repository(owner: "facebook", name: "graphql") {
    issues(first: 10) {
      nodes {
        title
        createdAt
        author {
          login
        }
      }
    }
  }
}

3.2. Updating data at GitHub

Let’s now explore some mutations we can do with the GitHub GraphQL API. The simplest mutation is to "star" a repository. Here is a mutation which, if you execute under your logged-in user, its action would be equivalent to you going to github.com/jscomplete/graphql-in-action and clicking the "star" button:

Listing 2. 12. Mutation to "star" a repository | az.dev/gia
mutation {
  addStar(input: { starrableId: "MDEwOlJlcG9zaXRvcnkxMjU2ODEwMDY=" }) {    (1)
    starrable {
      stargazers {
        totalCount
      }
    }
  }
}
1 Use listing 2.13 to find this starrableId value

The mutation will star the repository and then read the new total number of stargazers after the mutation. The input for this mutation is a simple object that has a starrableId value, which is the node identifier for the "graphql" repository. I was able to find that value using this query:

Listing 2. 13. Query to find an id of a repository | az.dev/gia
{
  repository(name: "graphql-in-action", owner: "jscomplete") {
    id
  }
}

Let’s execute another mutation. This time let’s add a comment to an issue in a repository. I created an issue for you to test this mutation under the repository at github.com/jscomplete/graphql-in-action.

You can see the details of this issue that I am about to comment on for the first time using this query:

Listing 2. 14. Query for the details of one issue under a repository | az.dev/gia
query GetIssueInfo {
  repository(owner: "jscomplete", name: "graphql-in-action") {
    issue(number: 1) {
      id
      title
    }
  }
}

This will give you the value of the id field that is needed to add a comment to the issue using a mutation. Now you need to execute the following mutation that uses the id value you found using the query in listing 2.14.

Listing 2. 15. Mutation to add a comment to a repository issue | az.dev/gia
mutation AddCommentToIssue {
  addComment(input: {
    subjectId: "MDU6SXNzdWUzMDYyMDMwNzk=",
    body: "Hello from California!"  (1)
  }) {
    commentEdge {
      node {
        createdAt
      }
    }
  }
}
1 Tell us where you’re from in your test comment :)

After the mutation in listing 2.14 saves your comment to the special issue, it will report the createdAt date for that comment. Feel free to send as many comments as you wish to this special issue, but only do so through the GraphQL API explorer 😊.

You can see the comments you added and all the other comments on this issue at github.com/jscomplete/graphql-in-action/issues/1.

3.3. Introspective queries

GraphQL APIs support introspective queries that can be used to answer questions about the API schema itself. This introspection support enables GraphQL tools to have powerful features and it is what drives the features we have been using in the GraphiQL editor. For example, the awesome type-ahead list in GraphiQL is sourced with an introspective query.

Introspective queries start with a root field that’s either __type or __schema, which are known as meta-fields. There is also another meta-field named __typename that can be used to retrieve the name of any object type. Fields with names that begin with double underscore characters are reserved for introspection support.

Meta-fields are implicit. They do not appear in the fields list of their types.

The __schema field can be used to read information about the API schema, like what types and directives it supports. We will explore directives in the next chapter.

Let’s ask the GraphQL API schema what types it supports. Here is an introspective query for that:

Listing 2. 16. Example GraphQL introspective query | az.dev/gia
{
  __schema {
    types {
      name
      description
    }
  }
}

This query will return all the types this schema supports and it will also include the descriptions of these types. This is a helpful list to explore the custom types defined in the GitHub GraphQL schema. For example, you should see that the GitHub API schema defines types like Repository, Commit, Project, Issue, PullRequest, and many more.

ch02 fig 09 gqlia
Figure 2. 9. Listing all the supported types under the GitHub API schema

If you need to retrieve information about a single type, you can use the __type meta-field. For example, here is a query to find all the supported fields under the type “Commit” along with any arguments they accept:

Listing 2. 17. Query for supported fields under a Commit object | az.dev/gia
{
  __type(name: "Commit") {
    fields {
      name
      args {
        name
      }
    }
  }
}

Use the GraphiQL type-ahead feature to discover what other information you can ask for under these introspective meta-fields.

4. Summary

  • GraphiQL is an in-browser IDE for writing and testing GraphQL requests. It offers many great features to write, validate, and inspect GraphQL queries and mutations. These features are made possible thanks to GraphQL introspective nature that comes with its mandatory schemas.

  • A GraphQL request comprises a set of operations, an object for variables, and other meta information elements as needed.

  • GraphQL operations use a tree of fields. A field represent a unit of information. The GraphQL language is largely about selecting fields on objects.

  • GitHub has a powerful GraphQL API that you can use to read data about repositories and users, as well as do simple mutations like add a star to a repository, or comment on an issue in a repository.

  • GraphQL introspective queries offer a way for clients to get meta information about the GraphQL API.

In the next chapter, we will learn how to customize and organize GraphQL requests.