গ্রাফকিউএল ক্লায়েন্টদের একটি একক অনুরোধে তাদের প্রয়োজনীয় ডেটার জন্য অনুরোধ করতে দেয় — কোনো ওভার-ফেচিং নয়, কোনো আন্ডার-ফেচিং নয়। সাথে মিলিতঅ্যাপোলো সার্ভার এবং টাইপস্ক্রিপ্ট, এটি নমনীয় API তৈরি করার একটি শক্তিশালী উপায়। এই গাইড স্ক্র্যাচ থেকে একটি সম্পূর্ণ GraphQL API তৈরি করে।
📋 Table of Contents
GraphQL বনাম REST — দ্রুত তুলনা
| দৃষ্টিভঙ্গি | বিশ্রাম | গ্রাফকিউএল |
|---|---|---|
| ডেটা আনা হচ্ছে | একাধিক শেষবিন্দু | একক শেষ বিন্দু, সুনির্দিষ্ট প্রশ্ন |
| ওভার-ফেচিং | সাধারণ | নির্মূল |
| সংস্করণ | URL সংস্করণ (v1, v2) | স্কিমা বিবর্তন |
| জন্য সেরা | সহজ CRUD, ক্যাশিং | জটিল, নেস্টেড, ক্লায়েন্ট-চালিত ডেটা |
প্রকল্প সেটআপ
mkdir graphql-api && cd graphql-api
npm init -y
npm install @apollo/server graphql
npm install -D typescript tsx @types/node
npx tsc --init
স্কিমা সংজ্ঞায়িত করুন
// src/schema.ts
export const typeDefs = `#graphql
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
published: Boolean!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
}
type Mutation {
createUser(name: String!, email: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
publishPost(id: ID!): Post!
}
`;
সমাধানকারী লিখুন
// src/resolvers.ts
import { db } from './db';
export const resolvers = {
Query: {
users: () => db.users.findAll(),
user: (_: any, { id }: { id: string }) => db.users.findById(id),
posts: () => db.posts.findAll(),
},
Mutation: {
createUser: (_: any, { name, email }: { name: string; email: string }) => {
return db.users.create({ name, email });
},
createPost: (_: any, args: { title: string; content: string; authorId: string }) => {
return db.posts.create({ ...args, published: false });
},
publishPost: (_: any, { id }: { id: string }) => {
return db.posts.update(id, { published: true });
},
},
// Field resolvers for relationships
User: {
posts: (parent: { id: string }) => db.posts.findByAuthor(parent.id),
},
Post: {
author: (parent: { authorId: string }) => db.users.findById(parent.authorId),
},
};
সার্ভার তৈরি করুন
// src/index.ts
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
context: async ({ req }) => {
// Extract auth token, attach user to context
const token = req.headers.authorization?.replace('Bearer ', '');
const user = token ? await verifyToken(token) : null;
return { user };
},
});
console.log("GraphQL ready at " + url);
সমাধানকারীদের মধ্যে প্রমাণীকরণ
Mutation: {
createPost: (_: any, args, context) => {
// Require authentication
if (!context.user) {
throw new GraphQLError('Not authenticated', {
extensions: { code: 'UNAUTHENTICATED' },
});
}
return db.posts.create({ ...args, authorId: context.user.id });
},
},
ডেটালোডার দিয়ে N+1 সমস্যা সমাধান করা হচ্ছে
ক্ষেত্র সমাধানকারীরা N+1 প্রশ্নগুলি ট্রিগার করতে পারে (পিতাপিতার প্রতি একটি প্রশ্ন)। DataLoader ব্যাচ এবং তাদের ক্যাশে:
npm install dataloader
import DataLoader from 'dataloader';
// Create a loader that batches user lookups
const userLoader = new DataLoader(async (ids: readonly string[]) => {
const users = await db.users.findByIds(ids);
// Return in the same order as requested ids
return ids.map(id => users.find(u => u.id === id));
});
// Use in resolver — batches all author lookups into one query
Post: {
author: (parent, _, context) => context.userLoader.load(parent.authorId),
},
উদাহরণ প্রশ্ন
# Client requests exactly what it needs
query {
user(id: "1") {
name
posts {
title
published
}
}
}
# Response contains only requested fields:
# { "data": { "user": { "name": "Alice", "posts": [...] } } }
প্রায়শই জিজ্ঞাসিত প্রশ্ন
প্রশ্ন: আমার প্রকল্পের জন্য GraphQL বা REST?
উত্তর: জটিল, নেস্টেড, ক্লায়েন্ট-চালিত ডেটার জন্য গ্রাফকিউএল (মোবাইল অ্যাপস, বিভিন্ন প্রয়োজনের ড্যাশবোর্ড)। সাধারণ CRUD এর জন্য REST এবং যখন HTTP ক্যাশিং সবচেয়ে গুরুত্বপূর্ণ। অনেক দল উভয়ই ব্যবহার করে।
প্রশ্ন: গ্রাফকিউএল-এ আমি কীভাবে ফাইল আপলোডগুলি পরিচালনা করব?
উত্তর: graphql-আপলোড প্যাকেজটি ব্যবহার করুন, অথবা আরও ভাল, একটি পৃথক REST এন্ডপয়েন্ট বা নির্ধারিত URL এর মাধ্যমে অবজেক্ট স্টোরেজ (S3) এ ফাইল আপলোড করুন এবং আপনার GraphQL মিউটেশনে URL পাস করুন৷
প্রশ্ন: GraphQL কি REST এর চেয়ে ক্যাশে করা কঠিন?
উত্তর: হ্যাঁ HTTP স্তরে (একক এন্ডপয়েন্ট, POST অনুরোধ)। ক্লায়েন্টে অ্যাপোলো ক্লায়েন্টের স্বাভাবিক ক্যাশে ব্যবহার করুন এবং ক্ষতিপূরণের জন্য সার্ভারে অব্যাহত প্রশ্ন বা প্রতিক্রিয়া ক্যাশিং ব্যবহার করুন।
প্রশ্ন: আমি কীভাবে ব্যয়বহুল/দূষিত প্রশ্নগুলি প্রতিরোধ করব?
উত্তর: ক্যোয়ারী গভীরতা সীমিত, জটিলতা বিশ্লেষণ, এবং হার সীমিত যোগ করুন। graphql-depth-limit এবং graphql-query-complexity-এর মতো প্যাকেজগুলি গভীরভাবে নেস্ট করা আপত্তিজনক প্রশ্ন থেকে রক্ষা করে৷
প্রশ্ন: আমার কি কোড-প্রথম বা স্কিমা-প্রথম ব্যবহার করা উচিত?
উত্তর: স্কিমা-ফার্স্ট (এসডিএল স্ট্রিং, এখানে দেখানো হয়েছে) স্পষ্ট এবং ভাষা-অজ্ঞেয়বাদী। কোড-প্রথম (নেক্সাস, টাইপগ্রাফকিউএল) আরও ভাল টাইপস্ক্রিপ্ট ইন্টিগ্রেশন দেয়। উভয় কাজ; দলের পছন্দের উপর ভিত্তি করে বাছাই করুন।
উপসংহার
অ্যাপোলো সার্ভারের সাথে গ্রাফকিউএল ক্লায়েন্টদের তাদের আনয়ন করা ডেটার উপর সুনির্দিষ্ট নিয়ন্ত্রণ দেয়, অতিরিক্ত এবং আন্ডার-ফেচিং দূর করে। এখানে সেটআপ — টাইপ করা স্কিমা, সম্পর্কগুলির সাথে সমাধানকারী, প্রসঙ্গ-ভিত্তিক প্রমাণীকরণ এবং N+1 সমস্যার জন্য ডেটালোডার — একটি প্রোডাকশন GraphQL API-এর প্রয়োজনীয়তাগুলিকে কভার করে৷ লাইভে যাওয়ার আগে গভীরতা সীমাবদ্ধতা এবং জটিলতা বিশ্লেষণ যোগ করুন এবং ফ্রন্টএন্ডে একটি স্বাভাবিক ক্যাশের জন্য অ্যাপোলো ক্লায়েন্টের সাথে যুক্ত করুন।
🔗 Share this article
✍️ Leave a Comment