GraphQL Fundamentals: Hands-On
Tags: graphql, beginners, tutorial
Published: 2022-01-17 11:16:52

In this post we will explore some of the fundamental concepts of GraphQL in a hands-on way. The goal of this post is to allow the beginner to gain a familiarity with the basic features of GraphQL. 

## Setting up
**The best way to learn is to do**. So this tutorial will be light on theory and heavy on practical exercises. 

So we'll need a real graphql server to play with. Let's use [Vendure](https://www.vendure.io), an open-source GraphQL e-commerce framework. I chose Vendure because it is really easy to set up - all you need is to make sure you have [Node.js](https://nodejs.org/en/) installed. Plus I built it so I know the API quite well 😉

To install a local instance of Vendure, run: 

```
npx @vendure/create my-shop
```

and follow the prompts. Select SQLite and use the defaults for all other prompts. Installation should take about 5 minutes and then you'll have a full, production-grade GraphQL server pre-populated with sample data ready to play with! 

![Installing the Vendure GraphQL server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlginhsfg9pvuhyq5333.gif)

Once installation is complete, open up [http://localhost:3000/shop-api](http://localhost:3000/shop-api) in your browser. 

*Note: if you are unable to install Vendure locally for any reason (e.g. you are on a mobile device), you can still follow along with this article by using the public demo server at [demo.vendure.io/shop-api](https://demo.vendure.io/shop-api).*

You should see the GraphQL Playground - an interactive interface for working directly with the GraphQL server. This is what we'll be using for all the exercises on this article. 

![GraphQL Playground](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x9mfosupk3zq5lhb5b4w.png)

## Your first query
GraphQL allows us to fetch data by sending *queries*. Queries are similar to GET requests in a REST API. Let's write our first query:

```graphql
query {
  product(id: 1) {
    id
    name
  }
}
```
Copy this into the left pane of the playground and then press the play button. You should see the response in the right pane:

```json
{
  "data": {
    "product": {
      "id": "1",
      "name": "Laptop"
    }
  }
}
```

Congratulations! You executed your first graphql operation! 

What did we do here? Let's analyze each part of this. 

1. `query`: First of all we are declaring that we are making a _query_. This is in contrast to a _mutation_ (which we will cover below). Technically you can omit that `query` keyword, but we'll keep using it just to be more explicit.
2. `product`: Next we are specifying the query we wish to use: _product_. Each GraphQL server defines a set of possible queries. Since Vendure is an e-commerce server, it exposes queries related to products, orders, customers, etc. 
3. `id: 1`: We then pass an argument to our query, specifying the ID of the product we want to return. You can think of this very much like a function call. Just like function calls, GraphQL queries can take zero, one or more arguments. 
4. `{ id, name }`: We finally specify the fields we want to return. Fields are like _properties_ on a JavaScript object. In this case, we want to know just the ID and name of the product. 

## Selecting fields
One of the big benefits of GraphQL over REST APIs is that you can specify the exact data you need, and the server will return those *and only those* fields. This means you can avoid sending too much data over the wire, leading to faster data transfer and lower bandwidth usage. 

Let's try adding some more fields to our query. Add the `slug` and `description` fields to the selection, and press the play button. You should see that these two new fields are added to the result:

```json
{
  "data": {
    "product": {
      "id": "1",
      "name": "Laptop",
      "slug": "laptop",
      "description": "Now equipped with seventh-generation Intel Core processors, ..."
    }
  }
} 
```
Now let's try an experiment: what happens if we add a field to our selection that does not actually exist on our product. Try adding the field `age`, and you'll get the following result:

```json
{
  "error": {
    "errors": [
      {
        "message": "Cannot query field \"age\" on type \"Product\". Did you mean \"name\"?",
        "locations": [
          {
            "line": 7,
            "column": 5
          }
        ]
      }
    ]
  }
} 
```

## Schema & Types

This highlights another important property of GraphQL: it is *statically typed*. That is to say, the exact fields available, and the types of data they can hold (strings, numbers, dates etc.) are explicitly defined in a **schema**. The schema, in fact, defines all available queries and mutations, and the exact type of objects they can return. 

This is an extremely powerful property of GraphQL and allows things like auto-complete and automatic validation of data you send to the server.

You have already seen the auto-complete as you typed the field names above. You can also see _all_ available fields on a given object by pressing `ctrl + space`:

![Autocomplete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x62cshbp26cpdmqlsfsi.gif)

At the bottom of the auto-complete popup, in orange text, you'll see the _type_ of that field. GraphQL types are analogous to [primitives](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) in JavaScript, `String`, `Boolean`, `Int`, `Float` & `ID`. In GraphQL these are known as _scalar types_. 

When a field represents a more complex data type, GraphQL supports _object types_. In fact, we've been working with an object type all along - the `Product` object! That's right, _queries_ themselves have a type. In this case, the `product` query has the type `Product`.

📖 *Reference: [graphql.org Scalar Types](https://graphql.org/learn/schema/#scalar-types), [graphql.org Object Types](https://graphql.org/learn/schema/#object-types-and-fields)*

## Nested Objects
Another of the major benefits of GraphQL is that a single query allows you to fetch an object *plus nested relations*. What would require several individual http requests using a REST API can be achieved in **a single GraphQL query**. 

To illustrate that, let's update our query to select all the variants of our Laptop product:

```graphql
query {
  product(id: 1) {
    id
    name
    slug
    description
    variants {
      name
      sku
      price
    } 
  }
}
```

Now when we run this, we'll get the requested fields on *each* of the laptop variants:

```json
{
  "data": {
    "product": {
      "id": "1",
      "name": "Laptop",
      "slug": "laptop",
      "description": "Now equipped with seventh-generation Intel Core processors, ...",
      "variants": [
        {
          "name": "Laptop 13 inch 8GB",
          "sku": "L2201308",
          "price": 129900
        },
        {
          "name": "Laptop 15 inch 8GB",
          "sku": "L2201508",
          "price": 139900
        },
        {
          "name": "Laptop 13 inch 16GB",
          "sku": "L2201316",
          "price": 219900
        },
        {
          "name": "Laptop 15 inch 16GB",
          "sku": "L2201516",
          "price": 229900
        }
      ]
    }
  }
} 
```

In a REST API, we'd typically need to make 5 separate requests to get all that data - one for the product, and one for each of the 4 variants!

## Hands-on: Queries
Now that we know the fundamental concepts of GraphQL queries, spend some time exploring the Vendure API! Use the `ctrl + space` hotkey to bring up the available queries and their fields.

![Exploring the available queries](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnfq4xdwqwws7mj6fbv0.gif)

## Mutations
Mutations are the counterpart to queries, and as the name suggests, they are used to _mutate_ (change) data. Mutations are similar to POST or PUT requests in a REST API.

Let's execute a mutation. Paste this into the left hand panel of the playground:

```graphql
mutation {
  addItemToOrder(productVariantId:1, quantity: 1) {
    ...on Order {
      id
      state
      totalQuantity
      totalWithTax
    }
    ...on ErrorResult {
      errorCode
      message
    }
  }
}
```

Press the play button and you'll see something like this:

```json
{
  "data": {
    "addItemToOrder": {
      "id": "1",
      "state": "AddingItems",
      "totalQuantity": 1,
      "totalWithTax": 155880
    }
  }
}
```

Let's once again break down each part of the mutation syntax:

1. `mutation`: declares that we are dealing with a mutation as opposed to a query. Unlike with queries, this keyword is *not* optional. 
2. `addItemToOrder`: the name of the mutation as declared by our schema. 
3. `productVariantId: 1`: like queries, mutations can (and usually do) take arguments. 
4. `... on Order`: this is known as an inline fragment. Since things might go wrong when adding an item to an order (e.g. insufficient stock), the mutation will return either an `Order` object, or an `ErrorResult` object. This syntax is like saying *"if it returns an Order, then give me the ID, state, totalQuantity & totalWithTax fields. If it returns an ErrorResult, then give me the errorCode and message fields."* You can try this out by entering `quantity: -1` and observing what happens.

As you can see, mutations share all the same parts as a query. In fact, the only real difference is the `mutation` keyword at the start. Just like with queries, they have arguments and they return a type. In this case the type is a combination of several object types (known in GraphQL as a *union* type, a more advanced topic out of the scope of this tutorial). 

📖 *Reference: [graphql.org Mutations](https://graphql.org/learn/queries/#mutations), [graphql.org Union Types](https://graphql.org/learn/schema/#union-types)*

## Hands-on: Mutations
Now you can explore for yourself how mutations work using the GraphQL playground. With the initial `mutation { }` keyword in place, pressing `ctrl + space` will now bring up auto-complete on all available mutations.

![Exploring mutations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1faoebkt45gmecvd9gps.gif)

**Here's a challenge for you:** see if you are able to successfully execute the `adjustOrderLine` mutation in order to change the quantity of laptops in your order. 

## Wrapping Up
In this post we've covered how to set up a full-featured GraphQL server using Vendure, and then learned the basics of queries and mutations. These two concepts form the basis of everything you'll be doing with GraphQL.

But of course this is more that you can learn - fragments, interfaces, named operations, variables, aliases and more. If you like the style of this tutorial and would like to see a follow-up that takes the next step into these more advanced topics, please leave a comment below!

And if you enjoyed working with Vendure - [check out the GitHub repo](https://github.com/vendure-ecommerce/vendure) and leave a star! 🙏