Table of Contents
What is GraphQL query language?
GraphQL query language is a specific syntax and set of rules to query data from a GraphQL API. It provides a structured and efficient way to request and retrieve the desired data from the server.
The GraphQL query language allows clients to specify the exact data they need, making it more flexible compared to traditional RESTful APIs where the server defines the response structure. With GraphQL, clients can send a single request to the server and receive only the requested data, eliminating over-fetching or under-fetching of data.
GraphQL query operations
There are three types of operations that you can execute with GraphQL: queries, mutations, and subscriptions
- Query – A read-only operation that retrieves data from the server.
- Mutation – An operation that modifies data on the server.
- Subscription — A long-lived operation that receives updates from the server when data changes. They typically track real-time data, such as stock prices or social media updates.
Syntax
Each operation consists of three parts:
- Operation type – The type of operation, which is either query, mutation, or subscription.
- Operation name – An optional name for the operation.
- Fields – A list of fields that specify the data you want to retrieve, modify, or receive updates for.
Examples:
Query:
query {
user(id: 1234) {
name
age
}
}
Mutation:
mutation {
createUser(name: "John Doe", age: 30) {
id
name
age
}
}
Subscription:
subscription {
newPosts {
id
title
body
}
}
GraphQL Query Elements
Now that you have gained some insight into what GraphQL query operations are, let us see the elements that form these operations. in this post, I am going to talk about fields, arguments, aliases, fragments, variables, and directives. with the knowledge of these elements, you can execute simple to complex query operations to communicate with the GraphQL server.
Fields
Fields represent the specific data elements or properties that clients want to retrieve from the server. Fields can have arguments to filter, sort, or paginate the data.
Field can also have reference to other Objects. When you have such as reference, you can select the field of the referenced Object as well.
For example, the query below uses the Author Object. This query read two fields of the Author object: name and books. name is a string, however, the books
is an Object. It references a Book Object. Therefore, you can access the fields in the Book object as well. Here, the “title” is a field in the Book object.
query Author{
authors {
name
books {
title
}
}}
When you run queries (and mutation, Subscriptions ) you can pass arguments to a field. This is useful in filtering data.
For example, if you want a specific author you can pass as an argument to the “id” field. ( And of course, to work like this with an argument, this query must be defined in the schema definition )
query{
author(id:"A2") {
age
books {
title
}
}
}
You can pass arguments into any field, including the fields of nested Objects. The following example will show only two books written by the author with the id “A2”.
query{
author(id:"A2") {
age
books(limit: 2) {
title
}
}
}
Aliases
Let’s say I want to know about books written by two authors with their IDs “A2” and “A3”. I should run the query as follows:
query{
author(id:"A3") {
age
books {
title
}
}
author(id:"A2") {
age
books {
title
}
}
}
In GraphQL, however, you can not do so. I will produce an execution error below:
"message": "Fields \"author\" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional."
This is because we use two different arguments for the same field, which causes a conflict.
The error also tells us to use aliases. Now, let’s see how to use aliases. Aliases are basically identities that you use for these queries. Since there are only two queries, you can use only one alias to differentiate two queries. But, I prefer to use two aliases to improve readability.
Query | Data requested |
---|---|
query{ Author1:author(id:”A3″) { age books { title } } Author2: author(id:”A2″) { age books { title } } } | { “data”: { “Author1”: { “books”: [ { “title”: “1Q84” }, { “title”: “Norwegian Wood” } ] }, “Author2”: { “books”: [ { “title”: “1Q84” }, { “title”: “Norwegian Wood” } ] } } } |
Fragments
Fragments are reusable components used with queries, mutations, or subscriptions.
Syntax:
fragment FragmentName on TypeName {
field1
field2
# ...
}
FragmentName
is the name you give to the fragment.TypeName
is the name of the type the fragment applies to. The type can be an object, interface, union, or scalar type.field1
,field2
, etc. are the fields you want to include in the fragment’s selection set.
Take the following query for example in the table below.
As you can be noticed in the query on the left side column of the table, the name, age, and books fields repeat in both Author1 and Author2. You can put these repeating fields of the Author object into a fragment and use that fragment instead. The right side column of the table shows how it has been done using fragments.
Note: The spread operator (…) is used to include the fields from the fragment at that location.
With no fragmensts | With Fragments |
---|---|
query{ | query{ |
Variables
When you use GraphQL queries, you can pass dynamic data into these queries. As you might have noticed before, we used arguments with fields. So far, we used static values in these arguments to filter and fetch the data. But, in a real-world application, these arguments hold dynamic values that come from the user input. Therefore, in GraphQL queries, you can replace these static values with variables to hold dynamic values coming from user input or other sources.
In a GraphQL query, variables are defined with the syntax $variableName: VariableType
. The variable name can be any valid name, and the variable type must match the corresponding type defined in the schema.
ex:
query GetAuthor($authorId: ID!) {
author(id: $authorId) {
name
age
}
}
In the above query, $authorId is a variable of type ID! (non-null ID).
When executing the query, you need to provide the values for the variables separately. This can be done through variables input:
{
"authorId": "A1"
}
You can send this JSON object as the variables input when making the GraphQL query.
In many GraphQL playgrounds, there is a separate section that let you add JSON objects so that you can test these GraphQL operations.
You can create complex GraphQL operations using more than one variable and /or using variables inside fragments. This not only makes queries dynamic, but also reusable.
You can also provide default values to variables using the syntax:
$variableName: VariableType = defaultValue
Note, I have provided one for the $limit
variable.
query getAuthor( $authorId_1: ID!, $authorId_2: ID!, $limit:Int = 1 ){
Author1:author(id: $authorId_1 ) {
...authorDetails
}
Author2: author(id: $authorId_2) {
...authorDetails
}
}
fragment authorDetails on Author{
name
age
books(limit: $limit){
title
}
}
The JSON object that you need to pass to run this query.
{
"authorId_1": "A1",
"authorId_2": "A2",
"limit":2
}
Directives
GraphQL allows you to conditionally add or remove a field using directives. There are two main directives you can use in GraphQL query language: @include and @skip.
@include | @skip |
---|---|
conditionally include a field in the response based on a Boolean condition. can specify the condition using a variable or a hardcoded Boolean value. If it is true, the field will be included in the response. If it is false, the field will be omitted from the response | conditionally include a field in the response based on a Boolean condition. can specify the condition using a variable or a hardcoded Boolean value. If it is true, the field will be included in the response. If it is false, the field will be omitted from the response |
Ex:
Take a look at the following sample dataset.
const authors = [
{ id: "A1", name: "J.K. Rowling" },
{ id: "A2", name: "Stephen King",age : 75 },
{ id: "A3", name: "Haruki Murakami",age:74 },
];
Here, the age will be only if the condition is true.
Query with directive | Response |
---|---|
query { | { |
query { | { |
If you use variables, this will be dynamic and reusable. Note, I have also assigned a default value for the $displayAge variable. This can come in handy if the user does not provide a value for $displayAge.
query ( $displayAge : Boolean ! = false) {
authors {
name
age@include( if : $displayAge )
}
}
A sample data in a JSON object
{
"displayAge": true
}
Note: it is crucial to understand that the @include and @skip directives DO NOT check the values of the fields they are applied to. They simply determine whether or not the field should be included in the result. Therefore, even if the “age” is not assigned a value or “age” is not a property of the data source, the directives do not validate this.
Wrapping up
In this post, we explore the basics of GraphQL query language. You can execute three query operations with GraphQL query language: query, mutation, and subscription. These query operations include fields, arguments, aliases, fragments, variables, and directives. Fields represent the specific data elements or properties. Aliases allow you to assign alternative names to fields in a query. Fragments are reusable units that you can use in a query. Variables make your query operations dynamic, and directives allow you to change the structure of a query operation.
Resources
- GraphQL playgrounds to practice GraphQL query operations