GraphQL
GraphQL is a query language for APIs and a runtime for executing those queries by using a type system you define for your data. It was developed by Facebook in 2012 and released as an open-source project in 2015. GraphQL provides a more efficient, powerful, and flexible alternative to the traditional REST API.
Fundamental Concepts
- Schema: The contract defining all data types, fields, and operations available in your API.
- Queries: Read operations used to fetch data.
- Mutations: Write operations used to create, update, or delete data.
- Subscriptions: Real-time event streams built over WebSockets.
- Resolvers: Server-side functions responsible for fetching data for each specific field in a schema.
Why use GraphQL Over REST?
| Feature | REST API | GraphQL |
|---|---|---|
| Endpoints | Multiple (/users, /posts/1, /comments) | Single endpoint (/graphql) |
| Data Fetching | Returns pre-defined payload (causes over/under-fetching) | Client requests exact fields needed |
| Network Requests | Requires multiple HTTP round-trips for nested resources | Fetches related resources in a single query |
| Type SafetyRequires external tooling (OpenAPI/Swagger) | Built-in strongly typed schema |
Running a GraphQL Engine via Docker
One of the fastest ways to run a local GraphQL instance is using Hasura GraphQL Engine connected to a PostgreSQL database.
docker-compose.yml:
1 | version: '3.6' |
- Start the containers:
1 | docker-compose up -d |
- Open your browser and navigate to
http://localhost:8080/console. - You will enter the Hasura console, where you can create database tables and immediately execute auto-generated GraphQL queries and mutations.
Understanding Data Storage in GraphQL
One important concept is that GraphQL does not store data itself. Instead, it acts as a layer between the client and the underlying data sources (like databases, REST APIs, or other services). The GraphQL server defines a schema that describes the types of data available and how to fetch them. When a client sends a query, the server resolves the query by fetching data from the appropriate sources and returning it in the requested format.
For Example:
The PostgreSQL database is responsible for storing the actual data. GraphQL is responsible for exposing that data through a strongly typed API.
With Hasura, the architecture looks like:
For example, the client may send:1
2
3
4
5
6query {
users {
id
name
}
}
Hasura translates the GraphQL operation into a database query similar to:1
SELECT id, name FROM users;
The result is then returned to the client as JSON.
Creating the Database Tables
Consider a simple blogging application with two entities:
A user can write many posts.
A post belongs to one user.
The relationship is: One-to-Many (one user can have many posts)
Create the tables in PostgreSQL:1
2
3
4
5
6
7
8
9
10
11
12
13CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
The actual records are stored in PostgreSQL.


After tracking these tables in Hasura, Hasura automatically generates GraphQL queries and mutations for them.
Querying Data and Mutations
A GraphQL query reads data.1
2
3
4
5
6
7query MyQuery {
users(limit: 10, offset: 0, order_by: {name: asc}, where: {}) {
id
email
name
}
}
The response will be:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21{
"data": {
"users": [
{
"id": 1,
"email": "alice@example.com",
"name": "Alice"
},
{
"id": 2,
"email": "bob@example.com",
"name": "Bob"
},
{
"id": 3,
"email": "Marry@example.com",
"name": "Marry"
}
]
}
}
GraphQL uses mutations for operations that change data.
For example, creating a user:1
2
3
4
5
6mutation MyMutation {
insert_users_one(object: {email: "Marry@example.com", name: "Marry"}) {
email
name
}
}
Conceptually, Hasura converts this into something similar to:1
INSERT INTO users (name, email)VALUES ('Marry', 'Marry@example.com');
The response will be:1
2
3
4
5
6
7
8{
"data": {
"insert_users_one": {
"email": "Marry@example.com",
"name": "Marry"
}
}
}
Creating a Post
A post can reference an existing user through author_id.
1 | mutation { |

Querying Relationships
Relationships are one of the most useful features of GraphQL.
After configuring a posts relationship on users, it is possible to query the user and their posts in a single GraphQL operation:1
query { users { id name posts { id title created_at } } }

Conclusion
GraphQL provides a powerful and flexible way to interact with APIs, allowing clients to request exactly the data they need and enabling real-time updates through subscriptions. By understanding the fundamental concepts of GraphQL, developers can build efficient and scalable applications that leverage the benefits of this modern API technology.




