The full-stack guide to the GraphQL query

The full-stack guide to the GraphQL query

GraphQL helps prevent the overloading of data. Unlike Restful API, GraphQL permits to define restricted fields which should be retrieved from the server. That will result in faster queries and less traffic on the network, which will reduce response time considerably. There are two basic types of operations in GraphQL: queries and mutations.

For reading data, you use query, while for modify data, you use mutation. The operation is a simple string that allows the server to parse and respond to the data in both cases.

What is a graphQL query?

Each GraphQL API has a graphQL schema. The schema describes how data looks and which operations are allowed. So if you had a cars object in your schema, you would query for them. The graphQL query would look like this:

1query getCars {
2  cars {
3    brand,
4    color
5  }
6}
7

In the above example, you can see a single graphQL query named getCars. In that graphQL operation, we are querying for two fields of cars type: brand and color. I will show you more details about GraphQL queries in this article, but first, let's see how it's possible to execute queries and consume any GraphQL API.

Prerequisites

In this article, I would like to show you two common things: using GraphQL query on the client-side and writing a basic query using NodeJS.

GraphQL API

For the first case, you don't need your GraphQL API. You can use some public GraphQL APIs to experiment.

A well-built API to start practicing with is the SpaceX API: https://api.spacex.land/graphql/

Graphql server

In case when you want to create your GraphQL API(with queries), you need to create a GraphQL server. I am going to show you the straightforward example built using Node and ExpressJS.

Where do you run a query in GraphQL?

Let's start by consuming SpaceX API to learn fundamentals about graphQL queries. You have at least four options to play with that API:

  • using GraphQL Playground

  • using GraphiQL Explorer

  • using Apollo Studio

  • using Chrome extensions like Altair GraphQL

GraphQL Playground & GraphiQL Explorer

Those are tools that allow you to play with every graphQL API. For example, when you put this URL in the browser: https://api.spacex.land/graphql/, you will see GraphiQL explorer. There you can inspect schema, read the docs, run queries, mutations, and so on. GraphQL playground has pretty the same set of features.

You can set up a playground on the project level or install it for macOS App.

Note: GraphQL Playground and GraphiQL are joining forces. More info here: https://github.com/graphql/graphql-playground/issues/1143

Apollo Studio

In case when you are creating your graphQL server using apollo-server, you will be able to use Apollo Studio to inspect your API.

Altair GraphQL Client

Altair client is a Chrome extension that allows you to inspect graphQL spec, query for all the data, send mutations, use subscriptions, etc.

Today I will use GraphiQL API because the API provides it. Typically, you will use tools that are provided with the project/graphQL servers. If you develop your project, you are comfortable to choose own Playground, but this does not matter because soon both tools will be merged.

Chrome extension is a good choice if you want to check sometimes fast and don't have a chance to use any Playground, but in general, you can, of course, use that extension and don't use playgrounds. All of those technics are good enough.

data graphql

The query for the data

Theory, theory, theory.... let's stop with that and get our hands dirty!

Let's try to get to all users!

1{
2  users {
3    name
4    rocket
5  }
6}
7
8

How simple is that?

In the above example, you can see a simple query. The 'users' objects can be used to request data about all available users – 'users' is an object in GraphQL terms. Objects hold data about an entity. Each object has fields. We used the name and rocket field in our case, but there are more fields for the users' objects. Take a look at the docs:

1id: uuid!
2name: String
3rocketString
4timestamp: timestampt!
5twitter: String
6

Some fields cannot be empty (null), and an exclamation mark determines it at the end. That means that, for example, id cannot be null or undefined. If will be, GraphQL will throw an error.

The results of the following query may look like this:

1{
2  "data": {
3    "users": [
4      {
5        "name": "sherlock holmes",
6        "rocket": "221B Baker Street"
7      },
8      {
9        "name": "sherlock holmes",
10        "rocket": "221B Baker Street"
11      },
12      {
13        "name": "sherlock holmes",
14        "rocket": "221B Baker Street"
15      },
16      {
17        "name": "sherlock holmes",
18        "rocket": "221B Baker Street"
19      },
20      {
21        "name": "User_14211338",
22        "rocket": "Space_101010101"
23      },
24      {
25        "name": "Elanthamil",
26        "rocket": "Elanthamil"
27      }
28    ]
29  }
30}
31

Congratulations! You made your first graphQL query! You are well on your way to becoming a GraphQL master, really!

first query - the road to become a graphQL master

Query with variables

In the previous example, you have seen a straightforward query (anonymous operation). Now we are going to do something more complicated, like a query with variables. When you want to pass a variable to a graphQL query, you can pass them as parameters:

1{
2  users(limit: 10, order_by: {name: asc}) {
3    name
4    rocket
5  }
6}
7
8

That works in Playground, but it's not too valuable because the values of variables are hardcoded. Let's define a named query using (surprising) a query keyword:

1query getUsers($limit: Int, $orderBy: [users_order_by!]) {
2  users(limit: $limit, order_by: $orderBy) {
3    name
4    rocket
5  }
6}
7
8

As you can see here, we have passed two variables: $limit, which is a type of Int, and $orderBy, which is a type of [users_order_by!].

Types can be primitive like String, Int, Float, Boolean, and ID, and also you can declare custom types in the graphQL schema.

An exclamation mark means that this parameter cannot be empty. You have a special place called "Query variables" (at the bottom). It will help if you put a query variable there. Otherwise, the query will throw an error.

You can also specify a default variable in GraphQL. It works only for non-required arguments. Take a look:

1query getUsers($limit: Int = 5, $orderBy: [users_order_by!]) {
2  users(limit: $limit, order_by: $orderBy) {
3    name
4    rocket
5  }
6}
7
8

Nested objects

You can request nested fields in a query (based on graphQL schema):

1query getLaunchesPast($limit: Int = 2) {
2  launchesPast(limit: $limit) {
3    mission_name
4    launch_date_local
5    launch_site {
6      site_name_long
7    }
8    rocket {
9      rocket_name
10      first_stage {
11        cores {
12          flight
13          core {
14            reuse_count
15            status
16          }
17        }
18      }
19    }
20  }
21}
22
23

The results may look like this:

1{
2  "data": {
3    "launchesPast": [
4      {
5        "mission_name": "Starlink-15 (v1.0)",
6        "launch_date_local": "2020-10-24T11:31:00-04:00",
7        "launch_site": {
8          "site_name_long": "Cape Canaveral Air Force Station Space Launch Complex 40"
9        },
10        "rocket": {
11          "rocket_name": "Falcon 9",
12          "first_stage": {
13            "cores": [
14              {
15                "flight": 7,
16                "core": {
17                  "reuse_count": 6,
18                  "status": "unknown"
19                }
20              }
21            ]
22          }
23        }
24      },
25      {
26        "mission_name": "Sentinel-6 Michael Freilich",
27        "launch_date_local": "2020-11-21T09:17:00-08:00",
28        "launch_site": {
29          "site_name_long": "Vandenberg Air Force Base Space Launch Complex 4E"
30        },
31        "rocket": {
32          "rocket_name": "Falcon 9",
33          "first_stage": {
34            "cores": [
35              {
36                "flight": 1,
37                "core": {
38                  "reuse_count": 0,
39                  "status": null
40                }
41              }
42            ]
43          }
44        }
45      }
46    ]
47  }
48}
49
50

Directives

Directives let you perform a conditional query for objects. There are two types of directives: include and skip. You can pass a bool variable to the query and then use this variable in the directive. Take a look at how it works:

1query getLaunchesPast($limit: Int = 2, $withRockets: Boolean = false) {
2  launchesPast(limit: $limit) {
3    mission_name
4    launch_date_local
5    launch_site {
6      site_name_long
7    }
8    rocket @include(if: $withRockets) {
9      rocket_name
10      first_stage {
11        cores {
12          flight
13          core {
14            reuse_count
15            status
16          }
17        }
18      }
19    }
20  }
21}
22
23

Note: Unfortunately, SpaceX API uses an older version of GraphQL tools, and those directives are not supported there.

Note 2: graphQL Server implementations may also add experimental features by defining completely new directives.

How do GraphQL queries work?

When you want to send a query from the frontend, a single request comes to the graphQL server. GraphQL takes a query and looks at what you need, and then a resolver function gets all related data and returns a JSON object.

Theoretically, you can send a request as a simple HTTP request, but a good practice is to use one of the graphQL clients to communicate with a server. Honestly, in real projects, you have to use GraphQL client on the frontend because it brings a lot of advantages like caching, mechanisms for sending queries, mutations, and so on.

type query

How do I create a query in GraphQL?

I showed you how to send a query. Now let's create our graphQL server and define a query.

We are going to use NodeJS and Apollo Server to scaffold an app.

The app is a big word. It will be basic stuff. Let's create a query that returns Hello World. It is a fantastic idea, isn't it?

Set-up a project

Let's init a new project by npm init command. Then please install all necessary dependencies:

1 npm install apollo-server graphql --save
2

Create an index.js file

Create an index.js file in the src directory(create the directory as well).

Put these imports at the beginning of the file:

1const { ApolloServer, gql } = require('apollo-server');
2

Create schema

Let's create our schema. We have to make two types:

  1. The Query type with welcomeMessage query

  2. The Message type is an object that represents our Message. It has only one field: text which cannot be empty.

Put this code to the file:

1const typeDefs = gql`
2  type Query {
3    welcomeMessage: Message!
4  }
5  
6  type Message {
7    text: String!
8  }
9`;
10

Create resolver

It's time to create a resolver function for the welcomeMessage query. In real projects, resolvers communicate with databases or other data and collect data. In our trivial example, we want to return a hardcoded string.

Here you go:

1const resolvers = {
2    Query: {
3        welcomeMessage: () => {
4            return {
5                text: 'Hello World',
6            };
7        },
8    }
9}
10

Initialize server

The last thing is to create a server instance:

1const server = new ApolloServer({
2    typeDefs,
3    resolvers,
4});
5
6server.listen().then(({ url }) => {
7    console.log(`🚀 Server ready at ${url}`);
8});
9
10

You can run that server by typing node ./src/index.js in the console.

Now you can see something like this:

fetch GraphQL API using Apollo Studio

Summary

I hope you enjoyed our quick tour through GraphQL queries. Let me summarize:

  • GraphQL has two basic types of operations: queries and mutations

  • queries read data. Mutations write data

  • there are a few ways to consuming or inspecting GraphQL API like playgrounds and Browser extensions

  • graphQL query can be anonymous or can have a name

  • you can pass variables to a query

  • query variable can have a default value

  • each returned field can have a nested object with other data

  • There are predefined directives like @include and @skip, and also you can write your directives on the server-side.

  • To create your graphQL server, you can use Node and Apollo servers.

  • Of course, you can even use PHP to write an apollo server, but who wants to write code in PHP?

That essential information should help you to understand the basics of graphQL queries.

About the author

Marcin Kwiatkowski

Certified Magento Full Stack Developer, based in Poland. He has 7 years of professional Software engineering experience. Privately, husband, father, and DIY enthusiast.

Read more