GraphQL is a query language for APIs and a runtime for running those queries against your data. Created by Facebook in 2012 and open sourced in 2015, GraphQL is designed to give clients exactly the data they need, nothing more, nothing less.
Unlike traditional REST APIs, which expose multiple endpoints for different resources, GraphQL exposes a single endpoint and allows the client to define exactly the form of the desired response.
๐ What is GraphQL?
GraphQL is a query language for APIs that allows clients to specify exactly what data they want to receive. It was developed by Facebook to overcome the limitations of traditional REST APIs.
- Over-fetching: getting more data than you need.
- Under-fetching: having to make multiple calls to get the complete data.
With GraphQL, you send a query to a single endpoint and get back only the data you requested.
๐ The Fundamentals of a GraphQL API (with examples)
1. Single Endpoint
All operations pass through a single endpoint, for example /graphql
.
In REST:
-
/api/users
,/api/products
, etc. → many endpoints.
In GraphQL:
-
Only one: for example
/graphql
.
๐ก Example (POST to /graphql
):
POST /graphql
Content-Type: application/json
{
"query": "{ listUsers { name age } }"
}
2. Typed Schema
Each API has a typed schema that defines the available data and the allowed operations. The schema defines the types, queries (available data), and mutations available (allowed operations):
type User {
id: Int
name: String
age: Int
}
3. Precise Query
The client decides which fields it wants to receive:
{
listUsers {
name
}
}
Response:
{
"data": {
"listUsers": [
{ "name": "Alice" },
{ "name": "Bob" }
]
}
}
4. Introspection
The schema is self-describing. You can ask for it with a special query:
{
__schema {
types {
name
}
}
}
5. Strong Typing
Each field and argument has a specific type. Errors like this are blocked:
{
getUser(id: "not-a-number") {
name
}
}
๐ซ Error: id
must be an integer.
๐ What are Queries in GraphQL?
In GraphQL, Queries are the equivalent of GET requests in REST APIs. They are used to read data from the server without modifying it.
✨ Query Characteristics:
- They do not cause side effects (they are "safe").
- The client specifies exactly the fields it wants.
- They are the starting point for reading complex relationships between entities.
๐งช Query Example
{
listUsers {
name
age
}
}
Call in Postman:
{
"query": "{ listUsers { name age } }"
}
Answer:
{
"date": {
"listUsers": [
{ "name": "Alice", "age": 30 },
{ "name": "Bob", "age": 25 }
]
}
}
๐ฏ Query with Arguments
{
getUser(id: 2) {
name
age
}
}
Postman:
{
"query": "{ getUser(id: 2) { name age } }"
}
Answer:
{
"date": {
"getUser": {
"name": "Bob",
"age": 25
}
}
}
✏️ What is a Mutation and When Is It Used?
In GraphQL, Mutation is used for edit data: create, update or delete. It is the equivalent of POST, PUT or DELETE in REST APIs.
๐ฆ When is it needed?
Anytime you want to write or modify something on the server.
๐จ Full Example: Mutation
1. Definition in the schema
type Mutation {
createUser(name: String!, age: Int!): User
}
2. Client Call Example
mutation {
createUser(name: "Charlie", age: 40) {
id
name
}
}
๐ฆ Response:
{
"date": {
"createUser": {
"id": 3,
"name": "Charlie"
}
}
}
๐ Difference between Query and Mutation
Type | Purpose | Side effects? | Example |
---|---|---|---|
Query | Read data | ❌ No | getUser, listUsers |
Mutation | Modify data | ✅ Yes | createUser, deleteUser |
๐งช How to Call a GraphQL API with Postman
๐ Query Call
- Method: POST
- URL: http://localhost:4000/graphql
Headers:
Content-Type:application/jsonBody:
{
"query": "{ listUsers { id name age } }"
}
Answer:
{
"date": {
"listUsers": [
{ "id": 1, "name": "Alice", "age": 30 },
{ "id": 2, "name": "Bob", "age": 25 }
]
}
}
✏️Call by Mutation
- Method: POST
- URL: http://localhost:4000/graphql
Headers:
Content-Type:application/jsonBody:
{
"query": "mutation { createUser(name: \"Charlie\", age: 40) { id name age } }"
}
Answer:
{
"date": {
"createUser": {
"id": 3,
"name": "Charlie",
"age": 40
}
}
}
Using Postman allows you to explore GraphQL APIs in a clean and visual way, even if you are used to the REST paradigm. The important thing to remember is that:
-
Everything happens on a single endpoint
-
Query to read, Mutation to write
-
The client decides what to receive: the server responds only with the requested data
๐ ️ Complete Code of a GraphQL Server
Install dependencies:
npm install express express-graphql graphql
Complete code (server.js):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
// Define GraphQL schema
const schema = buildSchema(`
type User {
id: Int
name: String
age: Int
}
type Query {
listUsers: [User]
getUser(id: Int!): User
}
type Mutation {
createUser(name: String!, age: Int!): User
}
`);
// Sample in-memory data
let users = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 }
];
// Root resolver
const root = {
listUsers: () => users,
getUser: ({ id }) => users.find(u => u.id === id),
createUser: ({ name, age }) => {
const newUser = { id: users.length + 1, name, age };
users.push(newUser);
return newUser;
}
};
const app = express();
app.use('/graphql', graphqlHTTP({
scheme,
rootValue: root,
graphiql: true // Enables GraphiQL UI
}));
app.listen(4000, () => console.log('GraphQL API running at http://localhost:4000/graphql'));
Here is the server code with explanation point by point:
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
๐น We import the necessary libraries: Express for the HTTP server, GraphQL and the express-graphql
middleware.
// Define GraphQL schema
const schema = buildSchema(`
type User {
id: Int
name: String
age: Int
}
type Query {
listUsers: [User]
getUser(id: Int!): User
}
type Mutation {
createUser(name: String!, age: Int!): User
}
`);
๐น Here we define the GraphQL schema, which is the contract that describes:
-
the types (
User
) -
the available queries (
listUsers
,getUser
) -
the available mutations (
createUser
)
// Sample in-memory data
let users = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 }
];
๐น A list of users in memory (no database yet). We use this array to simulate real data.
// Root resolver
const root = {
listUsers: () => users,
getUser: ({ id }) => users.find(u => u.id === id),
createUser: ({ name, age }) => {
const newUser = { id: users.length + 1, name, age };
users.push(newUser);
return newUser;
}
};
๐น The resolver is the object that implements the logic for each schema operation:
-
listUsers
: Returns all users. -
getUser
: Search for a user by ID. -
createUser
: Create a new user with incremental ID and add it to the list.
const app = express();
app.use('/graphql', graphqlHTTP({
scheme,
rootValue: root,
graphiql: true // Enables GraphiQL UI
}));
๐น Let's create the Express app and define a single endpoint /graphql
where we handle all requests using the graphqlHTTP
middleware.
The graphiql: true
option activates the integrated graphical interface to test queries from a browser.
app.listen(4000, () => console.log('GraphQL API running at http://localhost:4000/graphql'));
๐น The server starts on port 4000. Opening http://localhost:4000/graphql
you access GraphiQL, a useful UI for testing queries and mutations.
๐น To launch server.js
run the command:
node server.js
✅ Best Practices in API Design GraphQL
-
Clearly define the schema: it is the contract between client and server.
-
Avoid over-fetching and under-fetching: it is one of the major advantages of GraphQL.
-
Authorization and Authentication: Implement middleware to protect sensitive data.
-
Rate Limiting: Useful to avoid expensive queries.
-
Versioning: GraphQL has no API versions. Use field deprecation when needed.
๐งช Useful Tools
-
GraphiQL / Apollo Studio: IDE for exploring APIs.
-
Apollo Server: alternative to
express-graphql
, more complete. -
GraphQL Code Generator: to generate types and queries starting from the schema.
✅ Conclusion
GraphQL offers a modern, flexible and powerful way to build APIs. Its main advantages are:
- ๐ Greater client-side control
- ๐ Avoid over-fetching and under-fetching
- ๐ช Strongly typed schema
- ๐ฅ One endpoint for everything
You can easily test your API with Postman or GraphiQL and quickly develop interactive and performant interfaces.
Follow me #techelopment
Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment