GraphQL Tutorial #4 – GraphQL Operations
In this blog post, we are going to discuss three important GraphQL Operations concepts: queries, mutation, and subscription. GraphQL queries are used to fetch data from a GraphQL server, similar to a GET request. The mutation is used to update data on a GraphQL server and subscription is used to listen for any event on the server.
We will use one public GraphQL API endpoint holding the information of all StarWars series. Open this link on any web browser, it will open one web page like below :
This is ‘GraphiQL’, an user interface tool to run GraphQL queries. You can write your query on the left side and get its output on the right side by hitting the ‘Play’ button.
To check what GraphQL schemas are available, click on the ‘Docs’ button on the top right corner. It will show you one line as “query: Root”. Click on ‘Root’ to get the available schemas. It will show you something like below:
As you can see, we have different types of GraphQL schemas defined. For example, ‘allFilms’ takes four optional parameters ‘after’, ‘first’, ‘before’, and ‘last’ and it returns one ‘FilmsConnection’ object. You can click on this object name to get the list of all available fields. Isn’t it really easy?
Two more buttons are available on GraphiQL: “Prettify” and “history”. The ‘Prettify’ button is for reformatting the code and “history” is for checking the previous queries.
Write one basic query:
Let’s get the list of all peoples using the ‘allPeople’ schema:
1 2 3 4 5 |
allPeople( after: String first: Int before: String last: Int) : PeopleConnection |
It takes four optional parameters and returns one ‘PeopleConnection’ with the following items:
- pageInfo: PageInfo!
- edges: [PeopleEdge]
- totalCount: Int
- people: [Person]
We are not going to fetch all of the items, instead, we will request for only the ‘totalCount’ and ‘people’. ‘totalCount’ is an integer holding the total number of values and ‘people’ is an array holding ‘Person’ objects. You can click on the ‘Person’ object in the document explorer to check its included fields.
Copy paste the following query on the left side and hit the play button:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ allPeople { totalCount people { id name gender } } } |
It will return one output JSON like below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
{ data: { allPeople: { totalCount: 87, people: [ { id: "cGVvcGxlOjE=", name: "Luke Skywalker", gender: "male" }, { id: "cGVvcGxlOjI=", name: "C-3PO", gender: "n/a" }, { id: "cGVvcGxlOjM=", name: "R2-D2", gender: "n/a" }, ... ... ... ] } } } |
As you can see here, we got the ‘totalCount’ value and a list of ‘Person’ with ‘id’, ‘name’ and ‘gender’ for each. ‘totalCount’ is of Scalar type and ‘Person’ is an object type. Total of five scalar types are available in GraphQL: Int, Boolean, Float, String, and ID. Inside each ‘Person’ object, we are accessing only ‘id’, ‘name’ and ‘gender’ fields, but it also holds many other different fields including different objects. This is the main advantage of GraphQL, we can get what we are asking for.
Passing an argument:
We can also pass one argument with a query. For example, for the following schema:
1 2 |
person(id: ID personID: ID): Person |
We can pass one ‘id’ or ‘personID’ to get the required ‘Person’ object. Let’s use the id “cGVvcGxlOjE=” from the above example:
1 2 3 4 5 6 |
{ person(id: "cGVvcGxlOjE=") { name gender } } |
Run this query and it will return the following object:
1 2 3 4 5 6 7 8 |
{ "data": { "person": { "name": "Luke Skywalker", "gender": "male" } } } |
The above queries are known as anonymous queries or queries without any name. We can also set one name for a GraphQL query like below:
1 2 3 4 5 6 |
query GetPerson { person(id: "cGVvcGxlOjE=") { name gender } } |
This query will return the same result as the previous one.
Using variables:
We have learned how to pass one argument to a GraphQL query. But, instead of passing one argument directly to a GraphQL query, we can provide one variable name in the query and execute that query separately. GraphiQL also provides one separate portion to add query variables to a variable query.
The variable name should start with ‘$’ and the variable type should be mentioned in the query. For example, we can rewrite the above ‘GetPerson’ query as below:
1 2 3 4 5 6 |
query GetPerson($id: ID) { person(id: $id) { name gender } } |
Here, we are passing one ‘id’ of type ‘ID’ to the ‘GetPerson’ query. The same ‘id’ is used in the ‘person’ query call inside.
We can execute the above query like below:
{"id": "cGVvcGxlOjE="}
On GraphiQL, you can execute it like below:
As you can see that the output is the same as like the previous query.
Skip or include data based on a variable:
GraphQL provides two directives to include or skip specific fields based on the value of a variable. For example,
1 2 3 4 5 6 |
query GetPerson($includeGender: Boolean!, $id: ID) { person(id: $id) { name gender @include(if: $includeGender) } } |
We have two variables in this query. ‘id’ is of type ‘ID’ and ‘includeGender’ is of type ‘Boolean’. One more line we have changed here :
gender @include(if: $includeGender)
It means that the ‘gender’ field will be included in the output only if ‘includeGender’ is ‘true’. For example,
{"includeGender": false,"id": "cGVvcGxlOjE="}
For these variables, the output will be:
1 2 3 4 5 6 7 |
{ "data": { "person": { "name": "Luke Skywalker" } } } |
As you can see here, the ‘gender’ field is not included in the output.
Similar to ‘@include’ directive, we have one more directive called ‘@skip’. It works just the opposite to ‘@include’, i.e. it will include a field only if the value of ‘@skip’ is false.
We can write the above query as below :
1 2 3 4 5 6 |
query GetPerson($excludeGender: Boolean!, $id: ID) { person(id: $id) { name gender @skip(if: $excludeGender) } } |
Here, ‘excludeGender’ should be ‘false’ to include the ‘gender’ field in the output.
Getting multiple objects:
We can also fetch multiple objects with different values in the same query.
1 2 3 4 5 6 7 8 9 10 |
query GetPerson { person1: person(id: "cGVvcGxlOjE=") { name gender } person2: person(id: "cGVvcGxlOjU=") { name gender } } |
This will fetch two objects for two different ‘id’s.
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "data": { "person1": { "name": "Luke Skywalker", "gender": "male" }, "person2": { "name": "Leia Organa", "gender": "female" } } } |
In this query, we are repeating the inner fields of the query on both ‘person1’ and ‘person2’ i.e. we are writing ‘name’ and ‘gender’ two times. We can extract the inner query part and use it instead. This part is called ‘fragment’ in GraphQL.
1 2 3 4 5 6 7 8 9 10 |
query GetPerson { person1: person(id: "cGVvcGxlOjE=") { ...userInfo } person2: person(id: "cGVvcGxlOjU=") { ...userInfo } } |
1 2 3 4 |
fragment userInfo on Person { name gender } |
Here, we have defined one new fragment ‘userInfo’. ‘on Person’ means that the fragment is defined on ‘Person’ type. This query will fetch the same output as the previous one. Fragment is really useful if you don’t want to repeat the same code.
Using Aliases:
Aliases is used to change the field name of the return data. For the below query,
1 2 3 4 5 |
query GetPerson { person(id: "cGVvcGxlOjE=") { name } } |
It will return the ‘name’ of the person with the provided id.
1 2 3 4 5 6 7 |
{ "data": { "person": { "name": "Luke Skywalker" } } } |
Using aliases, we can change the ‘id’ name of the return data. It is used like ‘aliases name : field name’
1 2 3 4 5 |
query GetPerson { person(id: "cGVvcGxlOjE=") { personName: name } } |
This query will return:
1 2 3 4 5 6 7 |
{ "data": { "person": { "personName": "Luke Skywalker" } } } |
Using aliases, you can make changes to the API output on the client side without changing anything on the server.
Mutation:
We can use mutation to perform any of the following:
– Create a new data
– Update an existing data
– Delete a data
Writing a mutation is almost similar to the queries. The only difference is that we can write queries using an empty curly bracket (anonymous query) or using the ‘query’ keyword and its name. For mutation, we need to use the ‘mutation’ keyword always.
The above GraphQL API doesn’t provide any mutation operation as it is a public API. But if you have your own GraphQL server, you can define one mutation to create a new person like below :
1 2 3 4 5 |
mutation { createPerson(personName: “Luke Skywalker”, gender: “male”) { id } } |
This mutation operation is taking two arguments to create one ‘Person’. Both arguments are of string type. The GraphQL server will create one ‘Person’ with a unique ‘id’ and returns the ‘id’ with its response. Similar to the queries, you can ask for what you want in the response. In this example, the client can store the ‘id’ locally and use it on any delete or update request for the created ‘Person’ object.
Subscription:
Subscription is another powerful feature of GraphQL. Basically, the client can subscribe to an event of the server and whenever the event is executed, the server will notify the client.
For example, if we are developing a chat application, we can use a subscription to listen for any new chat in a chat-room. We can update the UI if any new chat notification is received. Similarly, for any other real-time monitoring application, a subscription can be used.
The ‘subscription’ query is similar to ‘mutation’ :
1 2 3 4 5 |
subscription { newComment { comment } } |
Conclusion:
In this tutorial, we have learned about GraphQL query, mutation and subscription. This Github repo contains a list of public GraphQL APIs. You can try with different API endpoints to get familiar with different types of queries.
Tutorial Index:
- GraphQL Tutorial #1 -Introduction
- GgraphQL Tutorial #2 – Setting Basic Project in GraphQL
- GraphQL Tutorial #3 – GraphQL Components
- GraphQL Tutorial #4 – GraphQL Operations
- GraphQL Tutorial #5 – Introduction to Apollo GraphQL
- GraphQL Tutorial #6 – 51 Most Important GraphQL Interview Q&A