If you’ve used GraphQL for your production application, you may have encountered a scenario where you needed your custom queries to return custom field names. Or, maybe you received two query results in the same server response, causing the field names to clash.
In these situations, we can use GraphQL aliases to improve our queries. In this tutorial, we’ll cover what an alias is, how it works, and when we should use it. We’ll look into several scenarios and expand on this concept with a relevant example. Let’s get started!
Aliases allow us to rename the data that is returned in a query’s results. Aliases don’t change the original schema, instead, they manipulate the structure of the query result that is fetched from your database, displaying it according to your specifications.
Aliases come in handy when you want to improve the efficiency of your queries. For example, let’s say you are trying to fetch the same data by applying various filters. Many developers would be inclined to write separate queries and execute them in independent API calls. In this situation and others, aliases can help you optimize and improve the organization of your queries.
There are several scenarios where you may want to change the name of the field where you receive query results. Let’s take a look at two different examples.
Using aliases, you can combine multiple fetches on the same object in a single GraphQL query.
Let’s say you are building an app that displays a list of posts in a feed. A typical post in your app would look like the code block below:
type Post { id: string parent: string type: string # POST or COMMENT author: string title: string text: string createdAt: string }
For simplicity, we’re limiting ourselves to only the string data type for each field. Ideally, you would use an enum for the type
field and a custom Date scalar for the createdAt
field.
Note that we defined a type
field to accommodate different types of posts in the same table. In our case, we have posts and comments.
A query for getPosts
would look like the following code block:
query getPosts { posts { id parent type author title text createdAt } }
Now, let’s say you have a post and a comment in your database. If you run the query above, you’ll get a response similar to the code block below:
{ "data": { "posts": [ { "id": "s9d8fhsd-fsdf", "parent": null, "type": "POST", "author": "Korg", "title": "Let's start a revolution", "text": "Hey, man. I'm Korg. We're gonna get outta here on that big spaceship. Wanna come?", "createdAt": "11:06 AM IST, Aug 7 2021" }, { "id": "d8g6dffd-jfod", "parent": "s9d8fhsd-fsdf", "type": "COMMENT", "author": "Loki", "title": null, "text": "Well, it seems that you are in dire need of leadership.", "createdAt": "11:09 AM IST, Aug 7 2021" } ] } }
Your database might also contain a long line of posts and comments like in the example above. You might try to write a query that fetches the posts in a separated list of posts and comments:
query getPosts { posts(type: "POST") { id author title text createdAt } posts(type: "COMMENT") { id parent author text createdAt } }
However, you’ll realize that the query doesn’t run at all, and it throws the following error:
{ "errors": [ { "message": "Fields 'posts' 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 } ] } ] }
When executed, the query returns two lists of results for the same field name posts
. Using aliases, we can change the field name to two different keywords, causing the query to run flawlessly:
query getPosts { posts: posts(type: "POST") { id author title text createdAt } comments: posts(type: "COMMENT") { id parent author text createdAt } }
Now, you can easily make multiple fetch calls in the same GraphQL query, saving network usage and decreasing code complexity.
A self-explanatory name makes it easy for any developer to understand your code well. The same is true for database results. You need to ensure that developers handling API responses are well-versed in what the data means. Let’s learn how to add meaning to our query results to help provide useful naming conventions.
Let’s reconsider our earlier example. Our schema looks like the following code block:
type Post { id: string type: string # POST or COMMENT author: string title: string text: string createdAt: string }
The schema contains a parent field that is meant to link a comment to a post, defining which post is the parent of a comment. While this should make sense to a database engineer, it might not be clear to a frontend engineer right away.
In this case, you can structure your traditional query to better describe the parent property:
query getPosts { posts { id parentPost: parent type author title text createdAt } }
You can rename other properties as you wish. In the results returned after executing the query, the original names will be entirely overwritten. A typical response will look like the following code block:
{ "data": { "posts": [ { "id": "s9d8fhsd-fsdf", "parentPost": null, "type": "POST", "author": "Korg", "title": "Let's start a revolution", "text": "Hey, man. I'm Korg. We're gonna get outta here on that big spaceship. Wanna come?", "createdAt": "11:06 AM IST, Aug 7 2021" }, { "id": "d8g6dffd-jfod", "parentPost": "s9d8fhsd-fsdf", "type": "COMMENT", "author": "Loki", "title": null, "text": "Well, it seems that you are in dire need of leadership.", "createdAt": "11:09 AM IST, Aug 7 2021" } ] } }
While implementing an alias in GraphQL is fairly straightforward, improper use can wreak havoc on your application. To optimize the results of the GraphQL alias, be sure to keep the following points in mind.
Because aliases allow you to alter your results’ field names, it is important to ensure that the names you choose make sense with respect to the actual data.
Although it is tempting to choose a convenient, short name that you can easily understand, you must also consider that other developers may work on the project after you. Unless your naming conventions are self-explanatory, they may have a hard time understanding your code, potentially causing errors in your project.
For example, the code below contains an example of a poorly-named alias:
query getPosts { p: posts(type: "POST") { id author title text createdAt } c: posts(type: "COMMENT") { id parent author text createdAt } }
It may seem convenient to name the two intermediate query results p
for posts and c
for comments, however, let’s take a look at the results of the above query:
{ "data": { "p": [ { "id": "s9d8fhsd-fsdf", "author": "Korg", "title": "Let's start a revolution", "text": "Hey, man. I'm Korg. We're gonna get outta here on that big spaceship. Wanna come?", "createdAt": "11:06 AM IST, Aug 7 2021" }, ], "c": [ { "id": "d8g6dffd-jfod", "parent": "s9d8fhsd-fsdf", "author": "Loki", "text": "Well, it seems that you are in dire need of leadership.", "createdAt": "11:09 AM IST, Aug 7 2021" } ] } }
As you can see, without contextual information about the type of the results, it is difficult to understand what p
and c
mean. Therefore, sticking with the full names posts
and comments
would be a better alternative in this scenario.
An alias is just a pseudonym for an existing field, so it might be tempting to use them even when they are not necessarily needed. However, renaming can lead to unnecessary mappings in your code. For example, let’s take our getPosts
query as an example:
query getPosts { posts { id parent type author title text createdAt } }
Each field in the posts
definition is self-explanatory. However, you may want to add an even stronger descriptor for each field, as below:
query getPosts { posts { postId: id parentPost: parent postType: type author title postContent: text createdAt } }
Keep in mind that with each renaming, you’ll need to propagate the new name everywhere in your code. Before adding an alias, you should consider the usefulness of the additional detail. I recommend only using aliases when it solves a recurring problem.
If you find yourself repeatedly renaming the same fields, you may want to consider dropping the alias and renaming the field on the server itself. Similarly, if you have to use aliases frequently on your client, you may need to reduce your database schema.
Aliases are meant to be a handy fix for renaming things quickly, however, you should not rely on them heavily. If you find yourself using aliases often, there may be an issue with your server-side naming conventions. In this case, using aliases will only further complicate the codebase.
Aliases are a great way to reorganize your GraphQL query results. Aliases are especially helpful when your backend data model and frontend data specifications don’t exactly fit together and you need to align them manually.
In cases when you need to fetch multiple query results on the same source at one time, aliases are mandatory. However, it is also essential to use aliases sparingly. While aliases are mostly harmless and only change the data after it is returned, unnecessary use can cause confusion about the data’s schema and even result in bugs.
I hope you enjoyed this tutorial!
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.