Unifying Data Fetching with GraphQL : The Upgrade Every Developers Need


Picture this: your frontend needs to render a blog post with its author's name and other authored posts. With a RESTful setup, that typically means:
GET /blog/:id
GET /author/:id
GET /author/:id/blogs
That’s three API calls just to render one view. On top of that, those endpoints could be managed by different microservices—each backed by different databases. The result? Overfetching, inconsistent latency, and a frustrating experience for both devs and users.
So how do we clean this up?
Enters GraphQL: Meta's Answer to Fragmented APIs
GraphQL was developed by Meta (Facebook) to streamline and unify how client apps interact with servers. It solves two core issues of REST:
Over-fetching/Under-fetching: REST endpoints often return more or less data than needed.
Multiple Roundtrips: REST requires multiple endpoint hits for relational data.
Instead, GraphQL introduces a single endpoint (/graphql
) with only two HTTP verbs: GET
for queries and POST
for mutations. But here’s the magic—GraphQL knows your data relationships through its schema and lets you request exactly what you need. No more chasing endpoints.
Example: GraphQL Schema for Blog & Author
This schema defines a blog type and a root-level Query
that returns a list of blogs and help us understand the relation between blog and author.
type Blog {
id: String
title: String
content: String
author: Author
}
type Author {
id: String
name: String
email: String
blogs: [Blog]
}
And here's a sample query:
query {
blogs {
id
title
author {
name
blogs {
title
}
}
}
}
With just this, your frontend gets the blog, its author's name, and titles of all their other blogs—in one roundtrip.
Building with Apollo GraphQL
Below example shows schema that defines a Book
type and a root-level Query
that returns a list of books. Schema-first design helps the frontend understand what data can be queried—enabling schema interpolation and IDE auto-completion. Let’s set up a basic GraphQL server using Apollo:
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const typeDefs = `#graphql
type Book {
title: String
subtitle: String
publisher: String
description: String
}
type Query {
books: [Book]
}
`;
const resolvers = {
Query: {
books: () => [
{
title: "Fox in Socks",
subtitle: "My Subtitle",
publisher: "Piyush",
description: "Nice"
}
]
}
};
const server = new ApolloServer({ typeDefs, resolvers });
async function init() {
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });
console.log(`🚀 Server ready at: ${url}`);
}
init();
The resolver in above code connects our GraphQL books
query to an actual data source (hardcoded array) which becomes the bridge between schema definition and real output. Then we start the server on port 4000 using Apollo’s startStandaloneServer
that makes the server up to accept queries and mutations at /graphql
.
Now for a mutation example:
This mutation, addBook
, lets clients insert a new book with a title and author. Mutations are GraphQL’s way of modifying server-side data.
type Mutation {
addBook(title: String, author: String): Book
}
Here's how you can implement the mutation resolver:
const resolvers = {
Query: {
books: () => [
{
title: "Fox in Socks",
subtitle: "My Subtitle",
publisher: "Piyush",
description: "Nice"
}
]
},
Mutation: {
addBook: (_, { title, author }) => {
const newBook = { title, author, subtitle: "", publisher: "", description: "" };
// Here you would typically save the new book to a database
console.log(`Book added: ${title} by ${author}`);
return newBook;
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
async function init() {
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });
console.log(`🚀 Server ready at: ${url}`);
}
init();
With this setup, you can add a new book using the addBook
mutation.
mutation CreateBook {
addBook(title: "Fox in Socks", author: "Dr. Seuss") {
title
author
}
}
Not All Sunshine: GraphQL Tradeoffs
Despite its elegance, GraphQL comes with caveats:
Added Latency: Validation on input/output introduces delays.
Memory Pressure: Data aggregation increases memory consumption.
No Lazy Loading: All requested data loads at once—no partial rendering.
Schema Sync: Backend and frontend must stay aligned on schema definitions.
Meta’s Recommendation: GraphQL as a Proxy Layer?
By using GraphQL as a proxy between frontend and backend, following are the few features that GraphQL supports:
It acts as a validation layer
Enables schema-based interpolation
Acts as a simple, unified API gateway
This setup enhances DX (Developer Experience) but requires conscious schema management and performance optimization.
Conclusion
In my opinion, GraphQL isn’t just a tool—it’s a philosophy of declarative data fetching. If your app juggles relational data across multiple services or calls several endpoints to populate a single view, switching to GraphQL is like going from a tangled web to a structured novel, hence upgrading data fetching experience for developers and users.
Subscribe to my newsletter
Read articles from Kreeti Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
