GraphQL 101: From Basics to Advanced

Software Engineer | Open Source Enthusiast | Mentor | Learner I love documenting stuff that I come across and find interesting. Hoping that you will love reading it and get to know something new :)
Search for a command to run...

Software Engineer | Open Source Enthusiast | Mentor | Learner I love documenting stuff that I come across and find interesting. Hoping that you will love reading it and get to know something new :)
No comments yet. Be the first to comment.
AI development often presents an illusion of standardization. When engineering structured workflows, JSON Schema is universally relied upon to force Large Language Models into returning predictable, t

Large language models (LLMs) like Llama, Qwen, and DeepSeek are transforming how software interacts with data. However, moving these models from a local experimental script to a highly available, mult

Artificial Intelligence (AI) models, especially large language models (LLMs) like GPT, Claude, or Gemini, have transformed how we interact with computers. Yet, terms like tokens, token limits, quotas, tokenizers, and parameters can seem confusing at ...

JavaScript development involves many concepts and tools that help developers organize, share, and reuse code effectively. For newcomers, terms such as library, framework, UMD, and CDN can seem technical, and understanding their roles is essential for...

Large language models (LLMs) such as GPT, LLaMA, and Falcon have billions of parameters. While these models are powerful, their size makes them challenging to run and adapt for specific use cases. Three key concepts help solve this problem: quantizat...

GraphQL is a query language for APIs and a runtime for executing those queries. It provides a complete and understandable description of the data in your API, empowering clients to request only the data they need and nothing more.
GraphQL was created to solve common issues with REST APIs, such as over-fetching, under-fetching, and multiple network requests. Unlike REST, which requires multiple API calls to obtain related data, GraphQL can fetch exactly what is needed in a single request.
Efficient Data Fetching: Clients can request only the required fields, reducing unnecessary data transfer.
Single Endpoint: Unlike REST APIs, which often have multiple endpoints, GraphQL provides a single endpoint (/graphql).
Strongly Typed Schema: GraphQL APIs are schema-driven, reducing the chances of errors.
Real-time Updates: GraphQL supports subscriptions, allowing real-time data fetching.
Better Developer Experience: The self-documenting schema makes it easier to understand and use APIs.
GraphQL is often compared to REST, but it offers more flexibility. Here's a comparison:
| Feature | GraphQL | REST |
| Data Fetching | Fetches only required data | Often over-fetches or under-fetches |
| Endpoints | Single endpoint (/graphql) | Multiple endpoints per resource |
| Typing | Strongly typed schema | No enforced schema |
| Real-time Support | Built-in subscriptions | Requires WebSockets or polling |
| Performance | Less network overhead | Higher overhead with multiple requests |
Fetching user and their posts:
REST API (Multiple Calls)
GET /user/1 → Fetch user details
GET /user/1/posts → Fetch posts separately
GraphQL (Single Query)
query {
user(id: "1") {
name
posts {
title
content
}
}
}
This makes GraphQL faster and more efficient.
To build a GraphQL server, we need a GraphQL schema and resolvers to handle queries.
Using Apollo Server (Node.js example):
npm install apollo-server graphql
The schema defines the structure of the API.
type Query {
hello: String
}
Resolvers return the data requested in the query.
const resolvers = {
Query: {
hello: () => 'Hello, GraphQL!',
},
};
const { ApolloServer, gql } = require('apollo-server');
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
This starts a GraphQL API that can be queried at http://localhost:4000.
A query is a request to fetch data from a GraphQL server.
query {
user(id: "1") {
name
email
}
}
Schema Definition:
type Query {
user(id: ID!): User
}
type User {
id: ID!
name: String
email: String
}
Resolver:
const resolvers = {
Query: {
user: (_, { id }) => users.find(user => user.id === id),
},
};
This returns only the requested fields, making it efficient.
A mutation is used to modify data (create, update, delete records).
mutation {
createUser(name: "Alice", email: "alice@example.com") {
id
name
}
}
Schema:
type Mutation {
createUser(name: String!, email: String!): User
}
Resolver:
Mutation: {
createUser: (_, { name, email }) => {
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
return newUser;
},
};
This allows clients to modify data easily.
Subscriptions allow real-time updates by pushing data to clients when an event occurs.
subscription {
userCreated {
id
name
}
}
Schema:
type Subscription {
userCreated: User
}
Resolver with PubSub:
const { PubSub } = require('graphql-subscriptions');
const pubsub = new PubSub();
const resolvers = {
Subscription: {
userCreated: {
subscribe: () => pubsub.asyncIterator(['USER_CREATED']),
},
},
Mutation: {
createUser: (_, { name, email }) => {
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
pubsub.publish('USER_CREATED', { userCreated: newUser });
return newUser;
},
},
};
When a new user is created, all subscribed clients get updated automatically.
Directives are special annotations in GraphQL that modify query execution.
type Query {
oldField: String @deprecated(reason: "Use newField instead")
newField: String
}
This warns developers when they use oldField.
GraphQL doesn’t provide built-in caching, but tools like Apollo Server offer caching mechanisms.
const server = new ApolloServer({
typeDefs,
resolvers,
cache: "bounded",
});
This optimizes performance by reducing repeated database queries.
GraphQL responses always return a 200 OK status code at the HTTP level, even for errors. Instead of relying on HTTP status codes for error handling, GraphQL includes a errors field in the response body.
{
"errors": [
{
"message": "User not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["user"]
}
],
"data": {
"user": null
}
}
This approach ensures consistent response formats, making it easier for clients to handle errors.
For handling authentication or other specific cases, middleware can be used to return appropriate HTTP status codes before executing the GraphQL query.
GraphQL Playground is an interactive tool for testing queries.
Auto-completion: Suggests queries based on schema.
Schema Documentation: Helps explore API structure.
Query History: Stores previously executed queries.
Real-time Subscriptions: Allows subscription testing.
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
});
Available at http://localhost:4000.
GraphQL Codegen automates the creation of strongly typed GraphQL code.
npm install @graphql-codegen/cli
schema: "http://localhost:4000/graphql"
generates:
src/generated/graphql.ts:
plugins:
- "typescript"
- "typescript-operations"
- "typescript-resolvers"
npx graphql-codegen
This helps in generating types and queries automatically.
Batching and Caching with DataLoader: DataLoader optimizes queries by batching and caching requests.
Custom Scalars: Define custom types like Date.
Authentication and Authorization: Use middleware to handle authentication.
GraphQL provides unparalleled flexibility and power for building APIs. Developers can build robust, scalable, and efficient applications by understanding their fundamentals and leveraging advanced features. It is a powerful alternative to REST, offering flexibility, efficiency, and real-time capabilities.
Reach out in the comments below or on LinkedIn to let me know what you think of it.
For more updates, do follow me here :)