“You will never get everything in life but you will get enough.”
― Sanhita Baruah
Introduction
In the previous tutorial, you have learned about setting up a GraphQL server with a structure which enables you to add more types easily. Should you not, please visit this post before continue reading.
I will share about creating queries in a GraphQL server. And we will emulate the environment of microservices with the GraphQL server as the API gateway. Then the GraphQL server will connect to those microservices to do the operations.
If you think there will be lots of code, well it will be. So, I will provide the source code for the other services at the beginning so you can run it to test your GraphQL server code locally. But, the for the GraphQL server code will be shared at the end of the post.
Now, let’s begin.
Requirements
- The previous GQL project
It’s recommended to clone this project we created from the previous tutorial, and name it ascli-nodejs-gql-2
- 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 wish to do so, after cloning the project, runnpm i
and explore the endpoints defined inindex.js
to make sure it works well.
Part 2 – GraphQL Queries
Suppose we have an interbank network system. The system connects all banks in the country, enabling the users to do transactions from and to any banks in real time.
The admin’s task is to manage new and existing users, and the list of banks in the system. This admin is very trustworthy that he has the power to add or deduct the users’ balance. The only thing he cannot do is changing the transactions that has already been done.
We are given the task to create an API which fulfils the admin’s requirements, because we don’t want the admin to be human. He would become too powerful with his privileges.
Install Dependencies
Before we start, we need to install axios
, a promise-based HTTP client for browser and Node.js. Axios
will be used for fetching data from the mock service. You can install axios
by running npm i axios
on the root of the GQL project.
Queries
To put it simply, queries are for getting the data you want using the GraphQL syntax. The usage is similar to HTTP GET
. In this section, we will create some queries for getting a bank or list of banks.
First, we create a new feature called banks
. Set the directories structure similar as the helloworld
we refactored in the section before. In other words, copy the helloworld
directory and rename it as banks
.
Then, on /graphql/index.js
, add banks
feature, just like the snippet below:
// /graphql/index.js
const { gql } = require('apollo-server-express');
const root = require('./_root');
const helloworld = require('./helloworld');
const banks = require('./banks');
const typeDefs = gql`${[
root.schemas,
helloworld.schemas,
banks.schemas
].reduce((acc, types) => { return acc + types })}`;
const resolvers = {
...root.resolvers,
...helloworld.resolvers,
...banks.schemas
};
module.exports = {
typeDefs,
resolvers
};
Get banks
Open _root/queries/schemas.gql
, and add banks
as Array:
module.exports = `
type Query {
helloworld: HelloWorld
banks: [Bank!]
}
schema {
query: Query
}
`;
The banks
query will be returned as an array and it can also be an empty array. But, the contents of the array must be from the Bank
schema which we will add right now.
So, we add more details on Bank
in /banks/queries/schemas.gql
, to define which properties we can fetch from the database. It’s not much, but will do for now:
module.exports = `
type Bank {
id: ID
name: String
}
`;
The Bank
has two properties: id
with the ID
type and name
with String
type. Both properties could be null
.
On /banks/queries/resolvers.js
, there isn’t anything to add, but for structure’s sake, we will add these:
// banks/queries/resolvers.js
const Bank = {};
module.exports = { Bank };
Then, back to the _root
directory, on _root/queries/resolvers.js
, we add the resolver to get banks
by using axios
:
const axios = require('axios');
const baseUrl = 'http://localhost:4001';
const get = async (url) => {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(error);
throw new Error(error);
}
return null;
}
const Query = {
helloworld: () => 'helloworld',
banks: async () => await get(`${baseUrl}/banks`) || []
};
module.exports = { Query };
First, we import the axios
library. Then, set the baseUrl
of the external service we will get the data from. After that, we write the get()
function to fetch data. Using axios
means that the response data will be inside the data
property, so we return response.data
. Remember to add a try-catch also. Lastly, add banks
as a function of Query
, which calls the get()
function with the URL we provide. If somehow the function fails, we can still return an empty array, just as defined in the schema.
Test the code
And now, we test the code. Run both cil-nodejs-gql-2
and cil-nodejs-gql-2-ms
with npm start
each. If you still use the same http://localhost:4000/graphql
, open it and run the GraphQL Playground. We want to get a bank’s list, so input this query:
query {
banks {
id
name
}
}
If everything works well on both services, it should show something like this:

Get A Bank
Open _root/queries/schemas.gql
, and add bank
with a parameter id
, so we know which specific bank to fetch later on:
module.exports = `
type Query {
helloworld: HelloWorld
banks: [Bank!]
bank(id: ID!): Bank
}
schema {
query: Query
}
`;
Next, because there’s not any difference in /banks/queries/schemas.gql
and /banks/queries/resolvers.js
, we will skip them and modify _root/queries/resolvers.js
to add what happens when we fetch bank
in the query:
// _root/queries/resolvers.js
...
const get = async (url) => {...}
const Query = {
...,
banks: async () => await get(`${baseUrl}/banks`) || [],
bank: async (_, params) => await get(`${baseUrl}/banks/${params.id}`) || {}
};
module.exports = { Query };
We add the bank
resolver in the Query
object. As you might have noticed, there are two parameters in the bank
function. The first parameter is root, but we can ignore it for now and we write it as _
. But, what we need is the second parameter params
. We want the id
parameter we requested to get the singular bank. Lastly, we fetch the data using the get()
function we created before.
test the code
What’s left is to test the code. So, run both the GQL and mock services. Then, access the GraphQL Playground. Get an id
from the banks list from the query before, and run this query in a new tab:
query Bank ($id: ID!) {
bank (id: $id){
id
name
}
}
We name the query as Bank
, but it’s OK if you want to name it as you like. And it shows that it needs id
from $id
. The $id
will be obtained from a JSON object defined in the query variables.
So, add a query variable id
in a JSON object (The id value could be anything though):
{
"id": "BJxBKwccP"
}
It should show this kind of result if it fetches succesfully:

Practice TIME!
By now, you should have understood the structure and pattern to add a query operation in GraphQL. As practice, you can try adding Users
and Transactions
using the same pattern as the example sections above.
In the source code provided later, I will also include both Users
and Transactions
, so you can compare both approaches.
Refactor HTTP Module
Just a little bit of refactor for the sake of cleanliness. We will separate the HTTP module from the root resolvers in queries. So, we can load axios
from that HTTP module only, then import them to be used in the query resolvers. And the mutation also later on.
HttpConnector
First, we create the <root>/connectors/httpConnector.js
file as the new HTTP module:
// <root>/connectors/httpConnector.js
const axios = require('axios');
const get = async (url) => {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(error);
throw new Error(error);
}
return null;
}
module.exports = {
get
}
All the functions in the file are taken directly from _root/queries/resolvers.js
. Remember to add the axios
library. Then, export the module at the end of the file.
Resolvers in _root/queries
Because we have created a httpConnector
, the same functions in _root/queries/resolvers.js
can be removed and be imported from httpConnector.js
.
First, we modify _root/queries/resolvers.js
:
const { get } = require('../../../connectors/httpConnector');
const baseUrl = 'http://localhost:4001';
const Query = {
helloworld: () => 'helloworld',
banks: async () => await get(`${baseUrl}/banks`) || [],
bank: async (_, params) => await get(`${baseUrl}/banks/${params.id}`) || {}
};
module.exports = { Query };
We import get()
from httpConnector.js
and remove the existing get()
before. It looks cleaner now, right?
Test the code
Run npm start
on both services and test all the endpoints to make sure everything still works.
Getting Bank Detail From User
If you create the query of User
, you should notice that the User
data only has bankId
. The admin might not know what the related bankId
means, so we have to provide the bankId
with more data such as the bank name
.
Assuming you have created Users
query from the previous practice section, you would have this schema for User
in users/queries/schema.gql
:
module.exports = `
type User {
id: ID!
name: String!
bankId: String!
amount: String!
}
`;
We will change the bankId
to bank
, so humans could understand what bankId
is for. And bank
is the type of Bank
:
module.exports = `
type User {
id: ID!
name: String!
bank: Bank!
amount: String!
}
`;
Next, we modify users/queries/resolvers.js
to resolve how we can get Bank
from bankId
:
const { get } = require('../../../connectors/httpConnector');
const baseUrl = 'http://localhost:4001';
const User = {
bank: async (user) => await get(`${baseUrl}/banks/${user.bankId}`) || {}
};
module.exports = { User };
First, we import get()
from httpConnector
, because we need to get()
the Bank
data from our mock service. Then, in the object User
, we set a bank
function as the resolver.
The function is asynchronous and require a parameter called user
. And this user
has the property of bankId
, if you check the data set from the mock service. Basically, it’s an unmodified user
data obtained from the database. Because what we need is bank
, not bankId
, we will use the user.bankId
to get the data. Lastly, we call the get()
function to get the data from the mock service.
Test the Code
Run both services with npm start
. Then create a new User
query, including bank
:
query User($id: ID!) {
user(id:$id) {
id
name
bank {
id
name
}
amount
}
}
In the query variables field, provide id
as parameter:
{
"id":"<user_id>"
}
Run the query. And you should see something like this:

If you run the Users
(the list one) query, it should be like this:

Practice Time!
The bank
can be changed to bankName
if you want to. You just have to return bank.name
after getting the data from the user
resolver. Try it out.
And now, you should be able to add the query for Transactions
detail for humans usage, like getting the bankName
before.
Conclusion
We have learned much this time also. By now, you should have learned about:
- GraphQL queries
- Connecting a GraphQL server to another service
- Get data from another service
- Create query resolvers
And here is the source code for this tutorial.
Same excuse with the previous post, this got too long so I have to separate the mutations part for another post.
I hope this will help you understand queries in GraphQL. If I missed something, let me know in the comments!
Next post in the series:
Part 3 – Mutations
“Enough will never be enough for some. So be enough for yourself instead.”
― Christine E. Szymanski