🕸️ GraphQL API Design & Apollo Federation
1️⃣ REST vs GraphQL: The Architecture Shift
Definition: GraphQL Meta (Facebook) dwara develop ki gayi ek strongly-typed query language aur server-side runtime execution engine hai. Yeh clients (Mobile/Web) ko exact data shape specify karne ki azaadi deta hai, jisse single round-trip HTTP request me sabhi nested dependencies fetch ho jaati hain.
| Criteria | RESTful APIs | GraphQL API Engine |
|---|---|---|
| Endpoints | Multiple fixed endpoints (/users, /orders, /products). |
Single Smart Endpoint (Typically POST /graphql). |
| Data Fetching | Over-fetching (unused 50 fields return hona) ya Under-fetching (cascade network roundtrips). | Zero Over/Under Fetching: Client exact fields declare karta hai jo screen par chahiye. |
| Schema & Contract | Loosely enforced; external documentation (Swagger/OpenAPI). | Strict Strongly-Typed SDL: Auto-introspected, self-documenting contract. |
| HTTP Status | Semantics based (200, 201, 400, 404, 500). | Always returns HTTP 200 OK with payload containing data and errors arrays. |
2️⃣ Schema Definition Language (SDL)
SDL ke core scalar types (Int, Float, String, Boolean, ID) aur non-null indicators (!):
# GraphQL Schema Contract (schema.graphql)
enum JobType {
FULL_TIME
REMOTE
CONTRACT
}
type Company {
id: ID!
name: String!
hqLocation: String
}
type JobPosting {
id: ID!
title: String!
salaryLPA: Float!
jobType: JobType!
company: Company! # Nested Object Relationship
}
input CreateJobInput {
title: String!
salaryLPA: Float!
companyId: ID!
jobType: JobType = FULL_TIME
}
3️⃣ The Three Operation Types
| Root Operation | Semantics | Practical Example |
|---|---|---|
| Query | Read-only idempotent operations (REST GET counterpart). | query { getJobs { title salaryLPA } } |
| Mutation | State-modifying operations with side-effects (POST/PUT/DELETE). | mutation { createJob(input: $data) { id } } |
| Subscription | Bi-directional real-time push over WebSockets. | subscription { onJobApplicationReceived { id } } |
4️⃣ Resolvers Architecture & Execution Chain
GraphQL engine incoming query ko ek AST (Abstract Syntax Tree) me parse karta hai aur har requested field ke liye corresponding resolver function invoke karta hai:
resolver(parent, args, context, info)•
parent: Previous parent resolver dwara return kiya gaya object.•
args: Query me pass kiye gaye dynamic parameters (e.g. id: "102").•
context: Global shared session object (Auth tokens, Database connection pool, DataLoaders).•
info: Current query execution tree metadata aur AST field paths.
5️⃣ The Classic N+1 Problem & DataLoader Solution
Agar aap 100 jobs query karte hain aur har job ke liye nested company resolver database query shoot karta hai, toh server 1 initial query + 100 individual sub-queries = 101 queries (N+1 disaster) execute karta hai.
// ❌ NAIVE RESOLVER (Suffers from N+1 DB Hammering)
const resolvers = {
JobPosting: {
company: async (parent, args, context) => {
// Runs 100 times sequentially for 100 job rows!
return await db.query('SELECT * FROM companies WHERE id = $1', [parent.companyId]);
}
}
};
// ✅ OPTIMIZED WITH DATALOADER (Batched & Memoized in 1 Event Loop Tick)
import DataLoader from 'dataloader';
// Batch function receives an array of keys: [10, 12, 10, 15...]
const companyLoader = new DataLoader(async (companyIds) => {
const uniqueIds = [...new Set(companyIds)];
// Executes SINGLE SQL Query: SELECT * FROM companies WHERE id IN (10, 12, 15)
const rows = await db.query('SELECT * FROM companies WHERE id = ANY($1)', [uniqueIds]);
return companyIds.map(id => rows.find(r => r.id === id));
});
const resolvers = {
JobPosting: {
company: (parent, args, { loaders }) => loaders.company.load(parent.companyId)
}
};
6️⃣ Production Security & Query Cost Analysis
Clients koi bhi arbitrary nested query bhej sakte hain, jisse DoS (Denial of Service) attacks ka risk banta hai:
| Vulnerability | Attack Example | Mitigation Defensive Rule |
|---|---|---|
| Circular Depth Attack | author { books { author { books { ... } } } } |
graphql-depth-limit configure karein (Max Depth: 5 levels). |
| Query Complexity DoS | allJobs(first: 5000) { applicants(first: 1000) { resume } } |
Query Cost Analyzer calculate karke limit karein (Max points: 1000 per request). |
| Introspection Leak | __schema { types { name } } public discovery |
Production environments me introspection: false set karein. |
7️⃣ Distributed GraphQL: Apollo Federation
Monolithic GraphQL schema ko maintain karne ke bajay multiple microservices apne-apne Subgraphs expose karti hain, jinko Apollo Router / Gateway dynamically stitch karke single Supergraph banata hai:
# Subgraph 1: Jobs Service
type JobPosting @key(fields: "id") {
id: ID!
title: String!
companyId: ID!
}
# Subgraph 2: Reviews Service (Extends JobPosting without owning it!)
extend type JobPosting @key(fields: "id") {
id: ID! @external
companyReviews: [Review!]!
}
# Apollo Gateway Planner:
# Automatically issues parallel sub-queries to Service 1 & Service 2,
# stitches JSON payloads by 'id', and returns a unified object to client!