“Incredible change happens in your life when you decide to take control of what you do have power over instead of craving control over what you don’t.”
― Steve Maraboli, Life, the Truth, and Being Free
Introduction
In the previous post, we learned about GraphQL queries for getting the data we need. Now, we will get to know about mutations in GraphQL for sending payloads to the server.
If you stumble upon this post first and don’t really understand, please read from the beginning of the “How to Implement GraphQL in Microservices Using Node.js” series:
And as usual, I will provide the source code at the end of the post.
Let’s get started!
Requirements
- The previous GQL project
It’s recommended to clone this project we created from the previous tutorial, and name it ascli-nodejs-gql-3
. If you want to continue the old one, it’s fine too. - This mock service project
If you prefer to build another REST API on your own, you are free to do so. But, why not save time? If you do, after cloning the project, runnpm i
and explore the endpoints defined inindex.js
to make sure it works well.
Part 3 – GraphQL Mutations
Mutations are queries which require payloads from body to be sent to server. The practice used in mutations are when there are some data-write operations to be done. Pretty similar to HTTP POST
, PATCH
, and DELETE
. In this section, we will create the mutations for creating, updating, and deleting banks
.
HttpConnector.js
First, we need to add some functions in connectors/httpConnector.js
:
// <root>/connectors/httpConnector.js
const axios = require('axios');
const get = async (url) => {...}
const post = async (url, data) => {
try {
const response = await axios.post(url, data);
return response.data;
} catch (error) {
console.error(error);
throw new Error(error);
}
return null;
}
const patch = async (url, data) => {
try {
const response = await axios.patch(url, data);
return response.data;
} catch (error) {
console.error(error);
throw new Error(error);
}
return null;
}
const remove = async (url, data) => {
try {
const response = await axios.delete(url, data);
return response.data;
} catch (error) {
console.error(error);
throw new Error(error);
}
return null;
}
module.exports = {
get,
post,
patch,
remove
}
Other than the get()
we created before, we add post(), patch(), remove()
as part of httpConnector
. The functions are pretty much the same, the only differences are the function called by axios
in each of them.
Before we start adding our mutations, let’s make new directories in _root
:
mutations/index.js
mutations/resolvers.js
mutations/schema.gql
mutations/index.js
is where we import the resolvers and schemas to be imported again later in _root/index.js
. Here is a snippet of the code:
const resolvers = require('./resolvers');
const schemas = require('./schemas.gql');
module.exports = {
resolvers,
schemas
};
Next, we will register the resolvers and schemas imported from _root/mutations/index.js
by modifying our _root/index.js
:
// _root/index.js
const queries = require('./queries');
const mutations = require('./mutations');
const rootSchema = `
schema {
query: Query
mutation: Mutation
}
`;
module.exports = {
resolvers: {
...queries.resolvers,
...mutations.resolvers,
},
schemas: [
queries.schemas,
mutations.schemas,
rootSchema
].reduce((acc, types) => { return acc + types })
}
We add mutations.resolvers
and mutations.schemas
just like the query
part.
And you might have noticed the rootSchema
here. It’s the same schema
from _root/queries/schemas.gql
. Because we need to add the mutation
also, even though it works, it’s not correct structurally if we modify the schemas
in _root/queries
.
By adding rootSchema
here, we need to modify two things. The first is that we have to register it after mutations.schemas
in the same file. Second, we have to remove the schema
part from _root/queries/schemas.gql
. This must be done for a better structure.
The mutations/resolvers.js
and mutations/schema.gql
will be modified later, you should already know what these two files will contain though.
Create a BAnk
First, we will update our _root/mutations/schemas.gql
to add the schema for our new mutation:
module.exports = `
type Mutation {
createBank(name: String!): ID
}
`;
In this case, we call our mutation createBank
because we are creating a new Bank
. After that, define the required data and the type of the return value.
Next, we will modify _root/mutations/resolvers.js
, to resolve what calling the createBank
operation will do:
const { post } = require('../../../connectors/httpConnector');
const baseUrl = 'http://localhost:4001';
const Mutation = {
createBank: async (_, data) => {
return post(`${baseUrl}/banks`, data);
}
}
module.exports = { Mutation };
Just like _root/queries/resolvers.js
, we import axios
and getting baseUrl
.
Then, we import post()
function from httpConnector.js
.
Next, we create a Mutation
object with a createBank()
as the resolver from the schema before. What it does is getting the data to post()
, then return the response.
Lastly, export the Mutation
with module.exports
.
Test the code
Let’s test the code if it works. Run both GraphQL and mock service with npm start
. Then, access the GraphQL Playground. In the query tab, put this:
mutation CreateBank ($name: String!) {
createBank (name: $name)
}
We create a new mutation operation called CreateBank
, which requires a name
data. Then we query createBank
, because we created it in the schema.
Next, in the query variables field, put a JSON object with a property name
:
{
"name": "Bank H"
}
Run the mutation, if it works well, it should show something like this:

If you are not convinced that it works, you can use QueryBank
with the id
returned from the mutation. Just like this screenshot:

Update a bank
Since we covered much in the previous section, we only need to modify _root/mutations/resolvers.js
and _root/mutations/schema.gql
by adding the updating parts.
First, let’s start with _root/mutations/schemas.gql
by adding updateBank
:
module.exports = `
type Mutation {
createBank(name: String!): ID
updateBank(id: ID!, name: String): String
}
`;
Then, we modify _root/mutations/resolvers.js
:
const { post, patch } = require('../../../connectors/httpConnector');
const baseUrl = 'http://localhost:4001';
const Mutation = {
createBank: async (_, data) => {...},
updateBank: async (_, data) => {
return patch(`${baseUrl}/banks/${data.id}`, data);
}
}
module.exports = { Mutation };
Before, we created a generic post()
function. For updateBank()
we import patch()
function because the mock service requires PATCH <url>/banks/<bank_id>
. Then, in the Mutation
object, we add updateBank()
to call patch()
.
Test the code
Run npm start
on both GraphQL service and mock service. Then open the GraphQL Playground. In the query field, add this:
mutation UpdateBank ($id:ID!, $name:String) {
updateBank(id: $id, name: $name)
}
There’s not much difference from createBank
. Next, on the query variables field, add this data as JSON object:
{
"id": "<bank_id>",
"name": "Bank H"
}
Get the “id” from list of inserted banks. Then you can modify the bank name to anything you want.
Execute the mutation and check if the change is successful. It should look like this:

If you want to be surer, you can check on QueryBank
or Banks
to see whether the update really happened.
DELETE a bank
Pretty much the same with the previous section: Update a Bank. You just need to copy the “update” part and change it to “remove” and the “patch” to “delete”.
Just as before, add deleteBank
in _root/mutations/schemas.gql
:
module.exports = `
type Mutation {
createBank(name: String!): ID
updateBank(id: ID!, name: String): String
deleteBank(id: ID!): String
}
`;
Then, add deleteBank()
as the mutation resolver in _root/mutations/resolvers.js
:
const { post, patch, remove } = require('../../../connectors/httpConnector');
const baseUrl = 'http://localhost:4001';
const Mutation = {
createBank: async (_, data) => {...},
updateBank: async (_, data) => {...},
deleteBank: async (_, data) => {
return remove(`${baseUrl}/banks/${data.id}`, data);
}
}
module.exports = { Mutation };
Test the code
Run both services and open the GraphQL Playground. In the query field, write from this snippet:
mutation DeleteBank($id: ID!) {
deleteBank(id: $id)
}
Then, in the query variables field, we add a JSON object with id
only, because the mutation only requires id
:
{
"id":"H161duyov"
}
Run the mutation, and you should see this kind of result if success:

Lastly, just as before, you can check Banks
or QueryBank
to make sure the deleted bank is really deleted.
Practice Time!
You should have understood how to make mutations for Banks
now. The next step is to try creating Users
and Transactions
. You can compare your approach with the source code I provide at the end of the post.
Conclusion
By now, you should have learned about:
- GraphQL mutations
- Create, update, or delete data to another service
And here is the source code for this tutorial complete with Users
and Transactions
also, so you can compare your approach with mine.
I hope this helps you in learning GraphQL mutations. Let me know if there’s something unclear or missed!
Next post in the series:
Part 4 – Authentication
“And that is how change happens. One gesture. One person. One moment at a time.”
― Libba Bray, The Sweet Far Thing