Mar 14th 2018

How to use GraphQL aliases

Author profileDavid Mráz

Introduction

To understand the concept of aliases in GraphQL we need to take a closer look at general query logic and identify what each part of a query is responsible for. All examples in this article can be found in this GitHub repository. If you also want to try these examples out in the GraphiQL tool, just clone the repository with

git clone https://github.com/a7v8x/express-graphql-demo.git -b feature/4-graphql-aliases

and then follow the readme, start the server and move to /graphiql. To illustrate the aliases concept, let’s take this query for retrieving users from the database.

query getUsers {
  users {
    id
    firstName
    lastName
    phone
    username
  }
}

This query consists of different parts

  • operation type (query): the type of action we want to do with the query. In GraphQL specification we have three different operation types -query, mutation and subscription.
  • name(getUsers): name is important for debugging purposes.
  • selection set (id, firstName, lastName, phone, username): this defines what data we would like to retrieve from the server.

There are also parts of the query which are called arguments, variables, fragments and directives. For simplicity’s sake we should leave that alone for now and return to them in future articles. When we execute this query with the proper server setup (check outGithub repository), we should be able to retrieve the data.

{
  "data": {
    "users": [
      {
        "id": "7b838108-3720-4c50-9de3-a7cc04af24f5",
        "firstName": "Berniece",
        "lastName": "Kris",
        "email": null
      },
      {
        "id": "66c9b0fd-7df6-4e2a-80c2-0e4f8cdd89b1",
        "firstName": "Bradly",
        "lastName": "Lind",
        "email": null
      },
      {
        "id": "718590a1-33ac-4e61-9fef-b06916acd76b",
        "firstName": "Leila",
        "lastName": "Schowalter",
        "email": null
      },
      {
        "id": "411df0f3-bb2c-4f5f-870f-3db9c30d754f",
        "firstName": "Laila",
        "lastName": "Breitenberg",
        "email": null
      },
      {
        "id": "e1254480-d205-4be8-abfa-67ad7dcd03fb",
        "firstName": "Joe",
        "lastName": "Crist",
        "email": null
      },
      {
        "id": "d0087200-9621-4787-a3db-cebbede163e6",
        "firstName": "Bettye",
        "lastName": "Bartoletti",
        "email": null
      }
    ]
  }
}

You can see that the data are contained in the users field, which refers to the selected field in the query.

Why aliases?

However, what happens if we want to query the users based on some argument? Let’s say that we have a schema for users, where the role argument is implemented and we want to query the users based on that role argument. Role arguments are used as a filter to retrieve the users. At first glance, the query can look like this:

query getUsers {
  users(role: admin) {
    id
    firstName
    lastName
    phone
    username
  }
  users(role: accountant) {
    id
    firstName
    lastName
    phone
    username
  }
}

This will return an error, because different data are stored in the same selection field. All results cannot be stored, as they have the same name and will be overwritten. For example, graphql-js will throw the error like this:

{
  "errors": [
    {
      "message": "Fields "users" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.",
      "locations": [
        {
          "line": 2,
          "column": 3
        },
        {
          "line": 9,
          "column": 3
        }
      ]
    }
  ]
}

To resolve this issue we can use the aliases. The same query can be then rewritten with aliases like this

query getUsers {
  admins: users(role: admin) {
    id
    firstName
    lastName
    phone
    username
  }
  accountants: users(role: accountant) {
    id
    firstName
    lastName
    phone
    username
  }
}

By executing this query we will retrieve the data filtered by the argument in the following format:

{
  "data": {
    "admins": [
      {
        "id": "7b838108-3720-4c50-9de3-a7cc04af24f5",
        "firstName": "Berniece",
        "lastName": "Kris",
        "phone": "021.807.6991 x10598",
        "username": "Ana_Quigley"
      },
      {
        "id": "66c9b0fd-7df6-4e2a-80c2-0e4f8cdd89b1",
        "firstName": "Bradly",
        "lastName": "Lind",
        "phone": "863.803.0636 x9247",
        "username": "Winona_Kulas12"
      },
      {
        "id": "718590a1-33ac-4e61-9fef-b06916acd76b",
        "firstName": "Leila",
        "lastName": "Schowalter",
        "phone": "1-425-625-3887",
        "username": "Isabell.Kautzer"
      },
      {
        "id": "411df0f3-bb2c-4f5f-870f-3db9c30d754f",
        "firstName": "Laila",
        "lastName": "Breitenberg",
        "phone": "155.714.0635 x741",
        "username": "Christophe.Oberbrunner"
      },
      {
        "id": "e1254480-d205-4be8-abfa-67ad7dcd03fb",
        "firstName": "Joe",
        "lastName": "Crist",
        "phone": "895-077-1248",
        "username": "Dahlia.Gerhold56"
      },
      {
        "id": "d0087200-9621-4787-a3db-cebbede163e6",
        "firstName": "Bettye",
        "lastName": "Bartoletti",
        "phone": "1-610-898-0105",
        "username": "Thad_Mayert"
      }
    ],
    "accountants": [
      {
        "id": "411df0f3-bb2c-4f5f-870f-3db9c30d754f",
        "firstName": "Laila",
        "lastName": "Breitenberg",
        "phone": "155.714.0635 x741",
        "username": "Christophe.Oberbrunner"
      },
      {
        "id": "e1254480-d205-4be8-abfa-67ad7dcd03fb",
        "firstName": "Joe",
        "lastName": "Crist",
        "phone": "895-077-1248",
        "username": "Dahlia.Gerhold56"
      },
      {
        "id": "d0087200-9621-4787-a3db-cebbede163e6",
        "firstName": "Bettye",
        "lastName": "Bartoletti",
        "phone": "1-610-898-0105",
        "username": "Thad_Mayert"
      }
    ]
  }
}

Conclusion

You can see that it is a much cleaner way to retrieve the data. We do not have to filter it on the frontend and we have it prefiltered in the apollo store right away. This is not the best option every time, but it should be considered. When you use aliases, it is extremely important to keep in mind the performance and use of the data loader for batching requests to the database. Also it is appropriate in this case to use persisted queries, as the query is a bit bigger in size. This can be reduced with fragments. Tweaking GraphQL performance will be the topic of the next few articles so be sure to subscribe. To dive deeper into performance, you can also check out the article on writing high performance web with React 16, Next.js and Node.js 8+.

Join thousands of others and be occasionally notified about new articles and our courses

* Signing up for Atheros Intelligence newsletter indicates you agree with Terms and Conditions and Privacy Policy including our Cookie Policy.