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 GraphQL Playground tool, just clone the repository with
git clone git@github.com:atherosai/graphql-gateway-apollo-express.git
install dependencies with
npm i
and start the server in development with
npm run dev
To illustrate the aliases concept, let’s take this query for retrieving users from the database.
query getUsers {users {idfirstNamelastNamephoneusernamerole}}
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 set-up (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) {idfirstNamelastNamephoneusername}users(role: ACCOUNTANT) {idfirstNamelastNamephoneusername}}
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 aliases. The same query can be then rewritten with aliases like this
query getUsers {admins: users(role: ADMIN) {idfirstNamelastNamephoneusername}accountants: users(role: ACCOUNTANT) {idfirstNamelastNamephoneusername}}
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 pre-filtered 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.
Did you like this post? The repository with the examples and project set-up can be cloned here. Feel free to send any questions about the topic to david@atheros.ai.