GraphQL APIs बनाने का एक शक्तिशाली और कुशल तरीका है। क्लाइंट API से उसी तरह क्वेरी करता है जैसे वह किसी डेटाबेस से करता है, और वह API केवल वही डेटा लौटाती है जिसकी उसने मांग की है, जिससे अक्सर रिस्पॉन्स पेलोड कम होता है और प्रतिक्रिया समय बेहतर होता है। आज की दुनिया में कम प्रतिक्रिया समय बेहद महत्वपूर्ण है।
जब GraphQL API को MongoDB के साथ जोड़ा जाता है, तो आपको न केवल तेज प्रतिक्रिया समय मिलता है, बल्कि शुरुआत से अंत तक एकसमान डेटा फॉर्मैट भी मिलता है।
कल्पना कीजिए: आपका क्लाइंट एक GraphQL क्वेरी चला रहा है और वह क्वेरी JSON जैसी दिखती है। जब डेटा आपकी एप्लिकेशन तक पहुंचता है—जो मान लीजिए इस उदाहरण में TypeScript है—तो आप अपनी एप्लिकेशन में JSON जैसे डेटा फॉर्मैट के साथ काम कर रहे होते हैं। एक कदम आगे, जब आप MongoDB के साथ काम करते हैं, तो MongoDB से आने-जाने वाला डेटा भी JSON जैसा होगा। तो आपको प्रदर्शन के साथ-साथ एक सुसंगत डेटा अनुभव मिलता है। अपने डेटा को बदलने और फॉर्मैट करने की चिंता करने के बजाय, आप अपनी एप्लिकेशन के यूज़र अनुभव पर ध्यान दे सकते हैं, न कि डेटाबेस और टूलिंग पर।
इस ट्यूटोरियल में, हम देखेंगे कि अपने GraphQL API में MongoDB का उपयोग करना, इस बार TypeScript के साथ, कितना आसान है।
अनिवार्य पूर्व-आवश्यकताएँ
इस विशेष ट्यूटोरियल के लिए, शुरू करने से पहले हमें कुछ चीज़ें तैयार रखनी होंगी:
एक MongoDB Atlas क्लस्टर
Node.js 22+
MongoDB Node.js Driver 6.x
हम इस ट्यूटोरियल में डेटाबेस के नज़रिए से कोई बहुत जटिल काम नहीं करेंगे, इसलिए MongoDB का कोई भी टियर क्लस्टर काम करेगा, यहाँ तक कि फ्री टियर भी। हालांकि, इस ट्यूटोरियल में हम MongoDB Atlas क्लस्टर की प्रोविजनिंग पर चर्चा नहीं करेंगे। अपेक्षा है कि आपके पास यूज़र नियम और नेटवर्क नियम पहले से कॉन्फ़िगर हों। यदि आपको शुरुआत करने में मदद चाहिए, तो इस विषय पर Get Started With Atlas दस्तावेज़ देखें।
आपको एक Node.js एप्लिकेशन बनाया होना चाहिए। यदि आप चाहें, तो आप निम्नलिखित कमांड चला सकते हैं:
mkdir graphql_example
cd graphql_example
npm init -yसंचालित द्वारा
उपरोक्त कमांड एक नया प्रोजेक्ट डायरेक्टरी और एक बेसिक package.json फ़ाइल बनाते हैं। हम इस प्रोजेक्ट में TypeScript, Express Framework, MongoDB, और Apollo का उपयोग करेंगे। इन्हें निम्नलिखित कमांड के साथ इंस्टॉल किया जा सकता है:
npminstall @apollo/server@4 body-parser cors dotenv express@4 graphql mongodb
npminstall @types/cors @types/express@4 @types/node tsx typescript --save-devसंचालित द्वारा
ये कमांड डिपेंडेंसीज़ के साथ-साथ TypeScript में उपयोग के लिए टाइप डेफिनिशन भी इंस्टॉल कर देंगी।
हमारी पूर्व-आवश्यकताओं के अंतिम भाग के रूप में, आपको TypeScript के लिए एक कॉन्फ़िगरेशन फ़ाइल की आवश्यकता होगी। अपने प्रोजेक्ट के रूट पर, निम्न JSON के साथ एक tsconfig.json फ़ाइल बनाएं:
{"compilerOptions":{"target":"ES2020","module":"commonjs","lib":["ES2020"],"outDir":"./dist","rootDir":"./src","strict":true,"esModuleInterop":true,"skipLibCheck":true,"forceConsistentCasingInFileNames":true,"resolveJsonModule":true,"moduleResolution":"node","declaration":true,"declarationMap":true,"sourceMap":true},"include":["src/**/*"],"exclude":["node_modules","dist"]}संचालित द्वारा
यदि किसी भी समय आप पूरे प्रोजेक्ट को देखना चाहें या इसे स्वयं आज़माना चाहें, तो आप इसे GitHub पर देख सकते हैं।
Apollo, Express, और MongoDB डिपेंडेंसीज़ के साथ नींव तैयार करें
प्रोजेक्ट संरचना के नज़रिए से, हम निम्नलिखित का उपयोग करेंगे:
src/database/connection.ts
src/database/userService.ts
src/resolvers/index.ts
src/schema/typeDefs.ts
src/types/index.ts
src/index.ts
.env
src/index.ts फ़ाइल में हमारा सारा Express Framework और Apollo बूटस्ट्रैपिंग होगा। इसमें सर्वर शुरू करना, GraphQL एंडपॉइंट्स परिभाषित करना आदि शामिल है। src/types/index.ts फ़ाइल में हमारी एप्लिकेशन के भीतर हमारे डेटाबेस डेटा मॉडल के साथ काम करने के लिए TypeScript डेफिनिशन होंगे। इसे src/schema/typeDefs.ts फ़ाइल से न मिलाएँ, जो कि भले ही समान लगे, लेकिन GraphQL टाइप डेफिनिशन पर केंद्रित है।
अब हमारे पास database और resolvers डायरेक्टरी की फ़ाइलें बचती हैं। हमारी एप्लिकेशन और डेटाबेस लॉजिक का अधिकांश हिस्सा इन्हीं फ़ाइलों में होगा, जिसे हम जल्द ही देखेंगे।
फिलहाल, src/index.ts फ़ाइल में अपना सर्वर सेटअप करने पर ध्यान दें:
जैसे-जैसे हम आगे बढ़ेंगे, हम ऊपर दी गई फ़ाइल का विस्तार करेंगे।
शुरू करने के लिए, हम अपनी सभी प्रोजेक्ट डिपेंडेंसीज़ इम्पोर्ट कर रहे हैं। अगला कदम है अपने Express Framework सर्वर और Apollo मिडलवेयर को कॉन्फ़िगर करना।
const server =newApolloServer({
typeDefs,
resolvers,});संचालित द्वारा
हमने अभी src/schema/typeDefs.ts और src/resolvers/index.ts फ़ाइलों में कुछ नहीं जोड़ा है, लेकिन इस चरण के हिस्से के रूप में हम सब कुछ तैयार कर रहे हैं। जब तक हम अन्य फ़ाइलों की कमी को पूरा नहीं करते, तब तक सर्वर को बिना त्रुटियों के चलाना सफल नहीं होगा।
यह उल्लेख करना उचित है कि यह विशेष उदाहरण सभी ओरिजिन से अनुरोधों की अनुमति देता है, इसकी वजह निम्न पंक्ति है:
यह विकास परिवेश के लिए तो ठीक है, लेकिन प्रोडक्शन डिप्लॉयमेंट में केवल आवश्यक ओरिजिन जोड़ने पर विचार करें।
TypeScript के साथ Node.js एप्लिकेशन से MongoDB के साथ इंटरैक्ट करना
हालाँकि हमारे पास Express Framework और Apollo सर्वर की नींव मौजूद है, हमने अपनी एप्लिकेशन में MongoDB डेटाबेस को कॉन्फ़िगर नहीं किया है। कोड में जाने से पहले, हमें अपने .env फ़ाइल में कनेक्शन जानकारी जोड़नी होगी:
MONGODB_URI="mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/?appName=devrel-graphql"
DB_NAME="graphql_example"संचालित द्वारा
<USERNAME>, <PASSWORD>, और <HOST> को अपने MongoDB Atlas क्लस्टर की जानकारी से बदलें, जो आपको अपने MongoDB Atlas डैशबोर्ड में मिल जाएगी।
अब, अपनी एप्लिकेशन के लिए डेटाबेस कनेक्शन लॉजिक स्थापित करें। **src/database/connection.ts** फ़ाइल में, निम्न कोड जोड़ें:
import{ MongoClient, Db }from'mongodb';let db: Db |null=null;let client: MongoClient |null=null;exportasyncfunctionconnectToDatabase():Promise<Db>{if(db){return db;}try{constMONGODB_URI= process.env.MONGODB_URI;if(!MONGODB_URI){thrownewError('MONGODB_URI is not set');}constDB_NAME= process.env.DB_NAME||'graphql_example';constAPP_NAME= process.env.APP_NAME||'devrel-graphql';console.log('Connecting to MongoDB...');
client =newMongoClient(MONGODB_URI,{ appName:APP_NAME});await client.connect();
db = client.db(DB_NAME);console.log(Successfully connected to MongoDB database: ${DB_NAME});return db;}catch(error){console.error('MongoDB connection error:', error);throw error;}}exportfunctiongetDatabase(): Db {if(!db){thrownewError('Database not initialized. Call connectToDatabase() first.');}return db;}exportasyncfunctioncloseDatabase():Promise<void>{if(client){await client.close();
db =null;
client =null;console.log('MongoDB connection closed');}}संचालित द्वारा
यहाँ विचार यह है कि हम एक सिंगलटन कनेक्शन बना रहे हैं। आपकी एप्लिकेशन में MongoDB को काम कराने के और भी कई तरीके हैं, लेकिन इस एप्लिकेशन के लिए हम यही तरीका चुन रहे हैं।
connectToDatabase फ़ंक्शन **.env** फ़ाइल से कनेक्शन जानकारी लेगा, कनेक्ट करेगा, और वह डेटाबेस लौटाएगा जिसे आपने परिभाषित किया है। यदि यह विफल होता है, तो त्रुटि पकड़ी जाएगी और आगे फेंकी जाएगी। आपको सर्वर सेटअप करते समय, जैसा कि पिछली फ़ाइल में देखा गया है, केवल connectToDatabase फ़ंक्शन का उपयोग करने की आवश्यकता होगी।
getDatabase फ़ंक्शन का उपयोग तब किया जाएगा जब भी हमारी एप्लिकेशन को कोई अनुरोध प्राप्त होगा। यह हमें हमारे कनेक्शन के वर्तमान इंस्टेंस को प्राप्त करने देगा।
अंत में, यदि हम चीज़ों को साफ़-सुथरा रखना चाहें, तो हमारे पास closeDatabase फ़ंक्शन है, जो हमारे सर्वर के बंद होने पर डेटाबेस से कनेक्शन बंद कर देगा। इसे शामिल करना आपके ऊपर है, लेकिन इसे रखना अच्छा अभ्यास है।
हमारे डेटा ट्रांसफ़र ऑब्जेक्ट्स (DTOs) के लिए TypeScript टाइप्स लेना, डेटाबेस लॉजिक पर जाने से पहले, एक अच्छा विचार होगा:
ऊपर दिए गए इंटरफेस, जो **src/types/index.ts** फ़ाइल में हैं, हमारी API द्वारा मैनेज किए जाते हैं, लेकिन हमारे डेटाबेस लॉजिक को इनके बारे में अवगत होना चाहिए। आप इसे अभी देखेंगे।
यह हमें हमारे वास्तविक डेटाबेस इंटरेक्शन—create, retrieve, update, delete (CRUD)—तक लाता है, और यह src/database/userService.ts फ़ाइल में किया जाता है। विचार यह है कि हमारे GraphQL रिजॉल्वर एप्लिकेशन लॉजिक संभालेंगे और इस सर्विस फ़ाइल में फ़ंक्शंस को कॉल करेंगे, और सर्विस डेटाबेस लॉजिक संभालेगी।
src/database/userService.ts फ़ाइल में हमारे पास निम्न कोड है:
interfaceUserDocument{
_id: ObjectId;
name:string;
email:string;
age?:number;
createdAt: Date;}संचालित द्वारा
यह हमारे User इंटरफेस जैसा दिखता है, मगर बिल्कुल वैसा नहीं है। UserDocument हमारे डेटाबेस के काम करने के तरीके के अधिक सख्त अनुरूप है। हम अपने डेटाबेस में ObjectId के साथ काम कर रहे हैं, लेकिन अपनी एप्लिकेशन में स्ट्रिंग हैश के साथ। MongoDB में id को id के बजाय _id के रूप में दर्शाया जाता है, जैसा कि हम User इंटरफेस में देखते हैं।
अब हम UserService क्लास पर आते हैं।
constructor मेथड के माध्यम से डेटाबेस इंस्टेंस से अपनी कलेक्शन का हैंडल प्राप्त करने के बाद, हमारे पास निम्नलिखित फ़ंक्शंस की श्रृंखला है:
toUser
getAllUsers
getUserById
createUser
updateUser
deleteUser
createIndexes
toUser फ़ंक्शन मूलतः एक हेल्पर है जो User और UserDocument के बीच रूपांतरण करता है। हम डेटाबेस को UserDocument भेजते और उससे प्राप्त करते हैं और हमें इसे रूपांतरित करना होता है ताकि एप्लिकेशन से User भेज सकें और प्राप्त कर सकें।
asynccreateIndexes():Promise<void>{awaitthis.collection.createIndex({ email:1},{ unique:true});awaitthis.collection.createIndex({ createdAt:-1});console.log('Database indexes created');}संचालित द्वारा
createIndexes फ़ंक्शन कुछ उदाहरण इंडेक्स बनाता है जो हमारे लिए उपयोगी हो सकते हैं। डिफ़ॉल्ट रूप से, एक इंडेक्स केवल _id फ़ील्ड पर होता है, जो कि कुछ मुट्ठी भर डॉ큐मेंट वाले डेमो के लिए ठीक है, लेकिन जैसे-जैसे आपकी एप्लिकेशन बढ़ती है, अपने डेटा और क्वेरी आवश्यकताओं के आधार पर उचित इंडेक्स निर्माण को नज़रअंदाज़ न करें। ऊपर दिए गए दो इंडेक्स केवल उदाहरण हैं।
अब हम प्रत्येक सर्विस फ़ंक्शन को देख सकते हैं, getAllUsers फ़ंक्शन से शुरू करते हुए:
asyncgetAllUsers():Promise<User[]>{const users =awaitthis.collection.find().toArray();return users.map(doc =>this.toUser(doc));}संचालित द्वारा
ऊपर दिया गया फ़ंक्शन कलेक्शन में सभी डॉ큐मेंट ढूंढेगा क्योंकि find फ़ंक्शन में कोई फ़िल्टर मानदंड नहीं है। परिणामों को हमारे toUser फ़ंक्शन से बदला जाता है और एप्लिकेशन को लौटा दिया जाता है, जो आगे चलकर हमारे Apollo रिजॉल्वर होंगे।
asyncgetUserById(id:string):Promise<User |null>{try{const doc =awaitthis.collection.findOne({ _id:newObjectId(id)});return doc ?this.toUser(doc):null;}catch(error){returnnull;}}संचालित द्वारा
getByUserId फ़ंक्शन समान है, लेकिन इस बार हम findOne का उपयोग कर रहे हैं और फ़िल्टर मानदंड निर्दिष्ट कर रहे हैं—यहाँ मानदंड यह है कि हम यूनिक _id फ़ील्ड के आधार पर एक ही यूज़र चाहते हैं। क्योंकि User इंटरफेस में id फ़ील्ड एक स्ट्रिंग है, हमें इसे MongoDB के भीतर अपनी क्वेरी के लिए उपयुक्त बनाने हेतु ObjectId में रैप करना होगा।
अब हम createUser फ़ंक्शन के माध्यम से MongoDB के भीतर डेटा बनाते हैं:
asynccreateUser(input: CreateUserInput):Promise<User>{const newUser: Omit<UserDocument,'_id'>={
name: input.name,
email: input.email,
age: input.age,
createdAt:newDate(),};const result =awaitthis.collection.insertOne(newUser as UserDocument);const createdUser =awaitthis.collection.findOne({ _id: result.insertedId });if(!createdUser){thrownewError('Failed to create user');}returnthis.toUser(createdUser);}संचालित द्वारा
हमने insertOne फ़ंक्शन से डेटा जोड़ने के बाद, लौटे हुए insertedId का उपयोग करके उसी डेटा को क्वेरी किया। हम ऐसा इसलिए करते हैं क्योंकि GraphQL API में, जब डेटा बनाया जाता है, तो आम तौर पर अपेक्षा रहती है कि उसी म्यूटेशन में आप उस डेटा को क्वेरी भी कर सकें।
updateUser फ़ंक्शन थोड़ा अलग है:
asyncupdateUser(input: UpdateUserInput):Promise<User |null>{try{const updateFields: Partial<Omit<UserDocument,'_id'>>={};if(input.name !==undefined) updateFields.name = input.name;if(input.email !==undefined) updateFields.email = input.email;if(input.age !==undefined) updateFields.age = input.age;const result =awaitthis.collection.findOneAndUpdate({ _id:newObjectId(input.id)},{ $set: updateFields },{ returnDocument:'after'});return result ?this.toUser(result):null;}catch(error){returnnull;}}संचालित द्वारा
इस एप्लिकेशन में, हम केवल अपने डेटा के name, email, और age फ़ील्ड्स पर अपडेट की अनुमति दे रहे हैं। ये सभी फ़ील्ड वैकल्पिक हैं, इसलिए यदि ये मौजूद हों तो हमें इन्हें अपने अपडेट मानदंड में सेट करना होगा।
यह हमें findOneAndUpdate फ़ंक्शन तक लाता है।
इस फ़ंक्शन का पहला ऑब्जेक्ट पैरामीटर फ़िल्टर मानदंड है। हम केवल वहाँ अपडेट करने में रुचि रखते हैं जहाँ _id मेल खाता हो। किसी भी मेल के लिए, हम $set ऑपरेटर का उपयोग करते हैं ताकि अपने updateFields ऑब्जेक्ट में मौजूद फ़ील्ड्स को बदलें या बनाएँ। जो फ़ील्ड इस ऑब्जेक्ट में नहीं हैं, वे बदले नहीं जाएँगे। अंत में, क्योंकि अपेक्षा है कि हम ढूंढ भी रहे हैं और अपडेट भी कर रहे हैं, केवल अपडेट नहीं, तो हम returnDocument को after सेट करते हैं ताकि प्रतिक्रिया में बदला हुआ डॉ큐मेंट मिले, न कि मूल डॉ큐मेंट। यदि हमने updateOne किया होता न कि findOneAndUpdate, तो हमें केवल अपडेट ऑपरेशन के बारे में जानकारी मिलती, डेटा नहीं।
इस API के लिए अंतिम CRUD ऑपरेशन MongoDB से डेटा हटाने का है, और यह deleteUser फ़ंक्शन के माध्यम से किया जाता है:
asyncdeleteUser(id:string):Promise<boolean>{try{const result =awaitthis.collection.deleteOne({ _id:newObjectId(id)});return result.deletedCount >0;}catch(error){returnfalse;}}संचालित द्वारा
ऊपर दिया गया deleteOne फ़ंक्शन हमारे findOne जैसा दिखता है क्योंकि हम _id के आधार पर फ़िल्टर मानदंड का उपयोग कर रहे हैं। अंतर यह है कि कोई भी मेल—इस मामले में अधिकतम एक डॉ큐मेंट—हटा दिया जाएगा।
इस बिंदु पर, डेटाबेस लॉजिक तैयार है। इसे अंतिम रूप देने के लिए, हमें **src/index.ts** फ़ाइल से कनेक्ट करना होगा:
// Previous imports here...import{ connectToDatabase, closeDatabase }from'./database/connection';import{ UserService }from'./database/userService';asyncfunctionstartServer(){try{awaitconnectToDatabase();const userService =newUserService();await userService.createIndexes();// The rest of the file here...}संचालित द्वारा
ऊपर दिए गए स्निपेट में, src/index.ts फ़ाइल का अधिकांश हिस्सा हटाया गया है। उद्देश्य केवल connectToDatabase फ़ंक्शन के उपयोग और इंडेक्स बनाने को दिखाना था। स्पष्ट रूप से कहें, तो अपने startServer फ़ंक्शन के आरंभ में ये तीन पंक्तियाँ जोड़ दें।
अब हम API लॉजिक पर ध्यान केंद्रित कर सकते हैं।
GraphQL टाइप्स, रिजॉल्वर, और कस्टम एप्लिकेशन लॉजिक परिभाषित करें
हमारे पास पहले से ही डेटाबेस के साथ काम करने और अपनी एप्लिकेशन में डेटा पास करने के लिए TypeScript टाइप्स परिभाषित हैं। हालाँकि, हमारे पास GraphQL टाइप डेफिनिशन नहीं हैं—वे चीज़ें जो यह तय करती हैं कि उपयोगकर्ता हमारी API का उपयोग करते समय किन चीज़ों के साथ इंटरैक्ट कर सकता है।
src/schema/typeDefs.ts फ़ाइल में, निम्न जोड़ें:
exportconst typeDefs = #graphql
typeUser{
id:ID!
name: String!
email: String!
age: Int
createdAt: String!}typeQuery{
users:[User!]!user(id:ID!): User
}typeMutation{createUser(name: String!, email: String!, age: Int): User!updateUser(id:ID!, name: String, email: String, age: Int): User
deleteUser(id:ID!): Boolean!};संचालित द्वारा
User टाइप वह है जिसे क्लाइंट किसी भी दिए गए क्वेरी में अनुरोध कर सकता है। इस उदाहरण में यह User इंटरफ़ेस से मेल खाता है, लेकिन इसकी अनिवार्यता नहीं है। उदाहरण के लिए, हो सकता है कि आपके User इंटरफ़ेस में ऐसा डेटा हो जिसे आप कभी क्लाइंट को लौटाना न चाहें, जैसे पासवर्ड।
Query टाइप वह प्रकार परिभाषित करता है जिन क्वेरीज़ को हमारी API के भीतर निष्पादित किया जा सकता है। प्रत्येक क्वेरी एक User या User की एक array लौटाएगी, लेकिन इनके बीच में हम इन क्वेरीज़ में विशिष्ट लॉजिक रख सकते हैं।
Mutation टाइप Query जैसा ही है, लेकिन इनका उद्देश्य डेटा में परिवर्तन करने वाली क्वेरीज़ होना है।
GraphQL टाइप डेफिनिशनों के होने के बाद, हम एप्लिकेशन के रिजॉल्वर लॉजिक पर ध्यान केंद्रित कर सकते हैं। प्रोजेक्ट की src/resolvers/index.ts फ़ाइल में, निम्नलिखित कोड शामिल करें:
import{ UserService }from'../database/userService';import{ User, CreateUserInput, UpdateUserInput }from'../types';exportconst resolvers ={
Query:{
users:async():Promise<User[]>=>{const userService =newUserService();returnawait userService.getAllUsers();},
user:async(_:unknown,{ id }:{ id:string}):Promise<User |null>=>{const userService =newUserService();returnawait userService.getUserById(id);},},
Mutation:{
createUser:async(
_:unknown,{ name, email, age }: CreateUserInput
):Promise<User>=>{const userService =newUserService();returnawait userService.createUser({ name, email, age });},
updateUser:async(
_:unknown,{ id, name, email, age }: UpdateUserInput
):Promise<User |null>=>{const userService =newUserService();returnawait userService.updateUser({ id, name, email, age });},
deleteUser:async(_:unknown,{ id }:{ id:string}):Promise<boolean>=>{const userService =newUserService();returnawait userService.deleteUser(id);},},};संचालित द्वारा
ऊपर दिए गए रिजॉल्वर वही विस्तार हैं जो हमने क्वेरीज़ और म्यूटेशनों के लिए टाइप डेफिनिशन फ़ाइल में देखे थे।
users क्वेरी पर नज़र डालें:
users:async():Promise<User[]>=>{const userService =newUserService();returnawait userService.getAllUsers();},संचालित द्वारा
यह GraphQL क्वेरी हमारे UserService का उपयोग करेगी, जो डेटाबेस लॉजिक का हिस्सा है, सभी यूज़र्स प्राप्त करने के लिए। User[] प्रतिक्रिया यूज़र को भेजी जाएगी, लेकिन केवल वही हिस्से जो यूज़र ने अनुरोधित किए हैं और जो GraphQL टाइप डेफिनिशंस से मेल खाते हैं।
तो उदाहरण के लिए, मान लें कि क्लाइंट ने यह क्वेरी भेजी:
ऊपर के उदाहरण में हमारे पास काम करने के लिए और फ़ील्ड्स हैं, लेकिन क्लाइंट केवल name और email फ़ील्ड चाहता है। इसे उसी GraphQL टाइप डेफिनिशनों के आधार पर संभाला गया जिनके साथ क्लाइंट काम कर रहा है। Apollo यह सब संभव बनाने का जादू संभालता है।
यही नियम हमारी **src/resolvers/index.ts** फ़ाइल के भीतर हर क्वेरी और म्यूटेशन पर लागू होंगे।
createUser:async(
_:unknown,{ name, email, age }: CreateUserInput
):Promise<User>=>{const userService =newUserService();returnawait userService.createUser({ name, email, age });},संचालित द्वारा
createUser टाइप डेफिनिशन के लिए, हमने देखा कि क्लाइंट name, email और age फ़ील्ड पास कर सकता है। createUser रिजॉल्वर फ़ंक्शन में, हम वही कर रहे हैं और अपने डेटाबेस सर्विस से createUser फ़ंक्शन को कॉल कर रहे हैं। प्रतिक्रिया क्लाइंट को उन्हीं फ़ील्ड्स के आधार पर लौटाई जाती है जिन्हें उन्होंने अनुरोध किया है।
GraphQL API को बिल्ड और रन करें
इस बिंदु पर, GraphQL API अच्छी अवस्था में होनी चाहिए। इस एप्लिकेशन को बिल्ड और रन करने के कई तरीके हैं।
उदाहरण के लिए, आप अपने **package.json** फ़ाइल में निम्नलिखित जोड़ सकते हैं:
"scripts":{"build":"tsc","start":"node dist/index.js","dev":"tsx src/index.ts","dev:watch":"tsx watch src/index.ts","watch":"tsc -w"},संचालित द्वारा
यदि आपने यह तरीका चुना है, तो आप प्रोजेक्ट को बिल्ड करने के लिए npm run build चला सकते हैं और प्रोजेक्ट को सर्व करने के लिए npm run start। डिफ़ॉल्ट पोर्ट 3000 है, और इसे cURL या आपकी पसंद के किसी भी टूल से टेस्ट किया जा सकता है।
निष्कर्ष
आपने अभी देखा कि कैसे TypeScript और MongoDB को डेटाबेस के रूप में उपयोग करके एक GraphQL API बनाई जाती है। जबकि यह उदाहरण सरल रखने के लिए बनाया गया था, हमने देखा कि अपनी डेटाबेस पर CRUD ऑपरेशन करने के लिए क्वेरीज़ और म्यूटेशंस कैसे बनाते हैं। GraphQL API में MongoDB एक बेहतरीन मेल है, क्योंकि जिस डेटा के साथ आप काम कर रहे हैं, उसकी संरचना शुरुआत से अंत तक मिलती-जुलती रहती है। उदाहरण के लिए, क्लाइंट ऐसी क्वेरी चलाता है जो JSON जैसी दिखती है। क्वेरी के माध्यम से पास किया गया डेटा बहुत कम फ़ॉर्मैटिंग और समायोजन के साथ उपयोग किया जा सकता है, और डेटाबेस को भेजते समय और वहाँ से प्राप्त करते समय भी यही बात लागू होती है। अनुभव सुचारु रहता है, जिससे आप डेटाबेस की आवश्यकताओं के अनुकूल डेटा हेरफेर की बजाय उपयोगकर्ता अनुभव पर अधिक ध्यान केंद्रित कर सकते हैं।
GraphQL बढ़िया है क्योंकि आप API के विरुद्ध वैसे ही क्वेरी कर सकते हैं जैसे किसी डेटाबेस के साथ करते हैं, और बदले में केवल उतना ही माँगते हैं जितनी आपको आवश्यकता है। इससे क्लाइंट के लिए चीज़ें हल्की और कुशल बनती हैं।
क्या GraphQL के लिए Apollo ही एकमात्र विकल्प है?⌄
Apollo GraphQL API बनाना बहुत आसान बना देता है, लेकिन यह एकमात्र विकल्प नहीं है। हालांकि, अन्य विकल्प इस ट्यूटोरियल के दायरे से बाहर हैं।
GraphQL के साथ MongoDB क्यों उपयोग करें?⌄
दोनों JSON-जैसे डेटा फ़ॉर्मैट्स के साथ काम करते हैं, इसलिए सूचना जब डेटाबेस से API होते हुए क्लाइंट तक बहती है, तब आपको अलग-अलग डेटा संरचनाओं के बीच लगातार रूपांतरण नहीं करना पड़ता।
रिजॉल्वर क्या करता है?⌄
रिजॉल्वर एक फ़ंक्शन है जो GraphQL को बताता है कि आपकी स्कीमा में किसी विशेष फ़ील्ड के लिए डेटा कैसे प्राप्त या संशोधित करना है।
क्वेरी और म्यूटेशन में क्या अंतर है?⌄
क्वेरीज़ डेटा पढ़ने/लाने के लिए होती हैं (जैसे GET अनुरोध), जबकि म्यूटेशंस डेटा बनाने, अपडेट करने या हटाने के लिए होती हैं (जैसे POST, PUT, DELETE)।
लेखक
Nic Raboy
निक रैबॉय MongoDB में डेवलपर रिलेशंस लीड हैं, जहाँ वे Python, Java, C# और PHP डेवलपर्स की एक टीम का नेतृत्व करते हैं जो ऐसा शानदार कंटेंट बनाते हैं जिससे डेवलपर्स अपने प्रोजेक्ट्स में MongoDB को सफलतापूर्वक शामिल कर सकें। उन्हें Golang और JavaScript का अनुभव है और वे प्रायः अपने विकास से जुड़ी अनेक यात्राओं के बारे में लिखते हैं।
GraphQL APIs बनाने का एक शक्तिशाली और कुशल तरीका है। क्लाइंट API से उसी तरह क्वेरी करता है जैसे वह किसी डेटाबेस से करता है, और वह API केवल वही डेटा लौटाती है जिसकी उसने मांग की है, जिससे अक्सर रिस्पॉन्स पेलोड कम होता है और प्रतिक्रिया समय बेहतर होता है। आज की दुनिया में कम प्रतिक्रिया समय बेहद महत्वपूर्ण है।
जब GraphQL API को MongoDB के साथ जोड़ा जाता है, तो आपको न केवल तेज प्रतिक्रिया समय मिलता है, बल्कि शुरुआत से अंत तक एकसमान डेटा फॉर्मैट भी मिलता है।
कल्पना कीजिए: आपका क्लाइंट एक GraphQL क्वेरी चला रहा है और वह क्वेरी JSON जैसी दिखती है। जब डेटा आपकी एप्लिकेशन तक पहुंचता है—जो मान लीजिए इस उदाहरण में TypeScript है—तो आप अपनी एप्लिकेशन में JSON जैसे डेटा फॉर्मैट के साथ काम कर रहे होते हैं। एक कदम आगे, जब आप MongoDB के साथ काम करते हैं, तो MongoDB से आने-जाने वाला डेटा भी JSON जैसा होगा। तो आपको प्रदर्शन के साथ-साथ एक सुसंगत डेटा अनुभव मिलता है। अपने डेटा को बदलने और फॉर्मैट करने की चिंता करने के बजाय, आप अपनी एप्लिकेशन के यूज़र अनुभव पर ध्यान दे सकते हैं, न कि डेटाबेस और टूलिंग पर।
इस ट्यूटोरियल में, हम देखेंगे कि अपने GraphQL API में MongoDB का उपयोग करना, इस बार TypeScript के साथ, कितना आसान है।
अनिवार्य पूर्व-आवश्यकताएँ
इस विशेष ट्यूटोरियल के लिए, शुरू करने से पहले हमें कुछ चीज़ें तैयार रखनी होंगी:
हम इस ट्यूटोरियल में डेटाबेस के नज़रिए से कोई बहुत जटिल काम नहीं करेंगे, इसलिए MongoDB का कोई भी टियर क्लस्टर काम करेगा, यहाँ तक कि फ्री टियर भी। हालांकि, इस ट्यूटोरियल में हम MongoDB Atlas क्लस्टर की प्रोविजनिंग पर चर्चा नहीं करेंगे। अपेक्षा है कि आपके पास यूज़र नियम और नेटवर्क नियम पहले से कॉन्फ़िगर हों। यदि आपको शुरुआत करने में मदद चाहिए, तो इस विषय पर Get Started With Atlas दस्तावेज़ देखें।
आपको एक Node.js एप्लिकेशन बनाया होना चाहिए। यदि आप चाहें, तो आप निम्नलिखित कमांड चला सकते हैं:
उपरोक्त कमांड एक नया प्रोजेक्ट डायरेक्टरी और एक बेसिक package.json फ़ाइल बनाते हैं। हम इस प्रोजेक्ट में TypeScript, Express Framework, MongoDB, और Apollo का उपयोग करेंगे। इन्हें निम्नलिखित कमांड के साथ इंस्टॉल किया जा सकता है:
ये कमांड डिपेंडेंसीज़ के साथ-साथ TypeScript में उपयोग के लिए टाइप डेफिनिशन भी इंस्टॉल कर देंगी।
हमारी पूर्व-आवश्यकताओं के अंतिम भाग के रूप में, आपको TypeScript के लिए एक कॉन्फ़िगरेशन फ़ाइल की आवश्यकता होगी। अपने प्रोजेक्ट के रूट पर, निम्न JSON के साथ एक tsconfig.json फ़ाइल बनाएं:
यदि किसी भी समय आप पूरे प्रोजेक्ट को देखना चाहें या इसे स्वयं आज़माना चाहें, तो आप इसे GitHub पर देख सकते हैं।
Apollo, Express, और MongoDB डिपेंडेंसीज़ के साथ नींव तैयार करें
प्रोजेक्ट संरचना के नज़रिए से, हम निम्नलिखित का उपयोग करेंगे:
src/index.ts फ़ाइल में हमारा सारा Express Framework और Apollo बूटस्ट्रैपिंग होगा। इसमें सर्वर शुरू करना, GraphQL एंडपॉइंट्स परिभाषित करना आदि शामिल है। src/types/index.ts फ़ाइल में हमारी एप्लिकेशन के भीतर हमारे डेटाबेस डेटा मॉडल के साथ काम करने के लिए TypeScript डेफिनिशन होंगे। इसे src/schema/typeDefs.ts फ़ाइल से न मिलाएँ, जो कि भले ही समान लगे, लेकिन GraphQL टाइप डेफिनिशन पर केंद्रित है।
अब हमारे पास database और resolvers डायरेक्टरी की फ़ाइलें बचती हैं। हमारी एप्लिकेशन और डेटाबेस लॉजिक का अधिकांश हिस्सा इन्हीं फ़ाइलों में होगा, जिसे हम जल्द ही देखेंगे।
फिलहाल, src/index.ts फ़ाइल में अपना सर्वर सेटअप करने पर ध्यान दें:
जैसे-जैसे हम आगे बढ़ेंगे, हम ऊपर दी गई फ़ाइल का विस्तार करेंगे।
शुरू करने के लिए, हम अपनी सभी प्रोजेक्ट डिपेंडेंसीज़ इम्पोर्ट कर रहे हैं। अगला कदम है अपने Express Framework सर्वर और Apollo मिडलवेयर को कॉन्फ़िगर करना।
हमने अभी src/schema/typeDefs.ts और src/resolvers/index.ts फ़ाइलों में कुछ नहीं जोड़ा है, लेकिन इस चरण के हिस्से के रूप में हम सब कुछ तैयार कर रहे हैं। जब तक हम अन्य फ़ाइलों की कमी को पूरा नहीं करते, तब तक सर्वर को बिना त्रुटियों के चलाना सफल नहीं होगा।
यह उल्लेख करना उचित है कि यह विशेष उदाहरण सभी ओरिजिन से अनुरोधों की अनुमति देता है, इसकी वजह निम्न पंक्ति है:
यह विकास परिवेश के लिए तो ठीक है, लेकिन प्रोडक्शन डिप्लॉयमेंट में केवल आवश्यक ओरिजिन जोड़ने पर विचार करें।
TypeScript के साथ Node.js एप्लिकेशन से MongoDB के साथ इंटरैक्ट करना
हालाँकि हमारे पास Express Framework और Apollo सर्वर की नींव मौजूद है, हमने अपनी एप्लिकेशन में MongoDB डेटाबेस को कॉन्फ़िगर नहीं किया है। कोड में जाने से पहले, हमें अपने .env फ़ाइल में कनेक्शन जानकारी जोड़नी होगी:
<USERNAME>,<PASSWORD>, और<HOST>को अपने MongoDB Atlas क्लस्टर की जानकारी से बदलें, जो आपको अपने MongoDB Atlas डैशबोर्ड में मिल जाएगी।अब, अपनी एप्लिकेशन के लिए डेटाबेस कनेक्शन लॉजिक स्थापित करें। **src/database/connection.ts** फ़ाइल में, निम्न कोड जोड़ें:
यहाँ विचार यह है कि हम एक सिंगलटन कनेक्शन बना रहे हैं। आपकी एप्लिकेशन में MongoDB को काम कराने के और भी कई तरीके हैं, लेकिन इस एप्लिकेशन के लिए हम यही तरीका चुन रहे हैं।
connectToDatabaseफ़ंक्शन **.env** फ़ाइल से कनेक्शन जानकारी लेगा, कनेक्ट करेगा, और वह डेटाबेस लौटाएगा जिसे आपने परिभाषित किया है। यदि यह विफल होता है, तो त्रुटि पकड़ी जाएगी और आगे फेंकी जाएगी। आपको सर्वर सेटअप करते समय, जैसा कि पिछली फ़ाइल में देखा गया है, केवलconnectToDatabaseफ़ंक्शन का उपयोग करने की आवश्यकता होगी।getDatabaseफ़ंक्शन का उपयोग तब किया जाएगा जब भी हमारी एप्लिकेशन को कोई अनुरोध प्राप्त होगा। यह हमें हमारे कनेक्शन के वर्तमान इंस्टेंस को प्राप्त करने देगा।अंत में, यदि हम चीज़ों को साफ़-सुथरा रखना चाहें, तो हमारे पास
closeDatabaseफ़ंक्शन है, जो हमारे सर्वर के बंद होने पर डेटाबेस से कनेक्शन बंद कर देगा। इसे शामिल करना आपके ऊपर है, लेकिन इसे रखना अच्छा अभ्यास है।हमारे डेटा ट्रांसफ़र ऑब्जेक्ट्स (DTOs) के लिए TypeScript टाइप्स लेना, डेटाबेस लॉजिक पर जाने से पहले, एक अच्छा विचार होगा:
ऊपर दिए गए इंटरफेस, जो **src/types/index.ts** फ़ाइल में हैं, हमारी API द्वारा मैनेज किए जाते हैं, लेकिन हमारे डेटाबेस लॉजिक को इनके बारे में अवगत होना चाहिए। आप इसे अभी देखेंगे।
यह हमें हमारे वास्तविक डेटाबेस इंटरेक्शन—create, retrieve, update, delete (CRUD)—तक लाता है, और यह src/database/userService.ts फ़ाइल में किया जाता है। विचार यह है कि हमारे GraphQL रिजॉल्वर एप्लिकेशन लॉजिक संभालेंगे और इस सर्विस फ़ाइल में फ़ंक्शंस को कॉल करेंगे, और सर्विस डेटाबेस लॉजिक संभालेगी।
src/database/userService.ts फ़ाइल में हमारे पास निम्न कोड है:
ऊपर सबसे पहले आप यह इंटरफेस नोट करेंगे:
यह हमारे
Userइंटरफेस जैसा दिखता है, मगर बिल्कुल वैसा नहीं है।UserDocumentहमारे डेटाबेस के काम करने के तरीके के अधिक सख्त अनुरूप है। हम अपने डेटाबेस मेंObjectIdके साथ काम कर रहे हैं, लेकिन अपनी एप्लिकेशन में स्ट्रिंग हैश के साथ। MongoDB में id कोidके बजाय_idके रूप में दर्शाया जाता है, जैसा कि हमUserइंटरफेस में देखते हैं।अब हम
UserServiceक्लास पर आते हैं।constructorमेथड के माध्यम से डेटाबेस इंस्टेंस से अपनी कलेक्शन का हैंडल प्राप्त करने के बाद, हमारे पास निम्नलिखित फ़ंक्शंस की श्रृंखला है:toUserफ़ंक्शन मूलतः एक हेल्पर है जोUserऔरUserDocumentके बीच रूपांतरण करता है। हम डेटाबेस कोUserDocumentभेजते और उससे प्राप्त करते हैं और हमें इसे रूपांतरित करना होता है ताकि एप्लिकेशन सेUserभेज सकें और प्राप्त कर सकें।createIndexesफ़ंक्शन कुछ उदाहरण इंडेक्स बनाता है जो हमारे लिए उपयोगी हो सकते हैं। डिफ़ॉल्ट रूप से, एक इंडेक्स केवल_idफ़ील्ड पर होता है, जो कि कुछ मुट्ठी भर डॉ큐मेंट वाले डेमो के लिए ठीक है, लेकिन जैसे-जैसे आपकी एप्लिकेशन बढ़ती है, अपने डेटा और क्वेरी आवश्यकताओं के आधार पर उचित इंडेक्स निर्माण को नज़रअंदाज़ न करें। ऊपर दिए गए दो इंडेक्स केवल उदाहरण हैं।अब हम प्रत्येक सर्विस फ़ंक्शन को देख सकते हैं,
getAllUsersफ़ंक्शन से शुरू करते हुए:ऊपर दिया गया फ़ंक्शन कलेक्शन में सभी डॉ큐मेंट ढूंढेगा क्योंकि
findफ़ंक्शन में कोई फ़िल्टर मानदंड नहीं है। परिणामों को हमारेtoUserफ़ंक्शन से बदला जाता है और एप्लिकेशन को लौटा दिया जाता है, जो आगे चलकर हमारे Apollo रिजॉल्वर होंगे।getByUserIdफ़ंक्शन समान है, लेकिन इस बार हमfindOneका उपयोग कर रहे हैं और फ़िल्टर मानदंड निर्दिष्ट कर रहे हैं—यहाँ मानदंड यह है कि हम यूनिक_idफ़ील्ड के आधार पर एक ही यूज़र चाहते हैं। क्योंकिUserइंटरफेस मेंidफ़ील्ड एक स्ट्रिंग है, हमें इसे MongoDB के भीतर अपनी क्वेरी के लिए उपयुक्त बनाने हेतुObjectIdमें रैप करना होगा।अब हम
createUserफ़ंक्शन के माध्यम से MongoDB के भीतर डेटा बनाते हैं:हमने
insertOneफ़ंक्शन से डेटा जोड़ने के बाद, लौटे हुएinsertedIdका उपयोग करके उसी डेटा को क्वेरी किया। हम ऐसा इसलिए करते हैं क्योंकि GraphQL API में, जब डेटा बनाया जाता है, तो आम तौर पर अपेक्षा रहती है कि उसी म्यूटेशन में आप उस डेटा को क्वेरी भी कर सकें।updateUserफ़ंक्शन थोड़ा अलग है:इस एप्लिकेशन में, हम केवल अपने डेटा के
name,email, औरageफ़ील्ड्स पर अपडेट की अनुमति दे रहे हैं। ये सभी फ़ील्ड वैकल्पिक हैं, इसलिए यदि ये मौजूद हों तो हमें इन्हें अपने अपडेट मानदंड में सेट करना होगा।यह हमें
findOneAndUpdateफ़ंक्शन तक लाता है।इस फ़ंक्शन का पहला ऑब्जेक्ट पैरामीटर फ़िल्टर मानदंड है। हम केवल वहाँ अपडेट करने में रुचि रखते हैं जहाँ
_idमेल खाता हो। किसी भी मेल के लिए, हम$setऑपरेटर का उपयोग करते हैं ताकि अपनेupdateFieldsऑब्जेक्ट में मौजूद फ़ील्ड्स को बदलें या बनाएँ। जो फ़ील्ड इस ऑब्जेक्ट में नहीं हैं, वे बदले नहीं जाएँगे। अंत में, क्योंकि अपेक्षा है कि हम ढूंढ भी रहे हैं और अपडेट भी कर रहे हैं, केवल अपडेट नहीं, तो हमreturnDocumentकोafterसेट करते हैं ताकि प्रतिक्रिया में बदला हुआ डॉ큐मेंट मिले, न कि मूल डॉ큐मेंट। यदि हमनेupdateOneकिया होता न किfindOneAndUpdate, तो हमें केवल अपडेट ऑपरेशन के बारे में जानकारी मिलती, डेटा नहीं।इस API के लिए अंतिम CRUD ऑपरेशन MongoDB से डेटा हटाने का है, और यह
deleteUserफ़ंक्शन के माध्यम से किया जाता है:ऊपर दिया गया
deleteOneफ़ंक्शन हमारेfindOneजैसा दिखता है क्योंकि हम_idके आधार पर फ़िल्टर मानदंड का उपयोग कर रहे हैं। अंतर यह है कि कोई भी मेल—इस मामले में अधिकतम एक डॉ큐मेंट—हटा दिया जाएगा।इस बिंदु पर, डेटाबेस लॉजिक तैयार है। इसे अंतिम रूप देने के लिए, हमें **src/index.ts** फ़ाइल से कनेक्ट करना होगा:
ऊपर दिए गए स्निपेट में, src/index.ts फ़ाइल का अधिकांश हिस्सा हटाया गया है। उद्देश्य केवल
connectToDatabaseफ़ंक्शन के उपयोग और इंडेक्स बनाने को दिखाना था। स्पष्ट रूप से कहें, तो अपनेstartServerफ़ंक्शन के आरंभ में ये तीन पंक्तियाँ जोड़ दें।अब हम API लॉजिक पर ध्यान केंद्रित कर सकते हैं।
GraphQL टाइप्स, रिजॉल्वर, और कस्टम एप्लिकेशन लॉजिक परिभाषित करें
हमारे पास पहले से ही डेटाबेस के साथ काम करने और अपनी एप्लिकेशन में डेटा पास करने के लिए TypeScript टाइप्स परिभाषित हैं। हालाँकि, हमारे पास GraphQL टाइप डेफिनिशन नहीं हैं—वे चीज़ें जो यह तय करती हैं कि उपयोगकर्ता हमारी API का उपयोग करते समय किन चीज़ों के साथ इंटरैक्ट कर सकता है।
src/schema/typeDefs.ts फ़ाइल में, निम्न जोड़ें:
Userटाइप वह है जिसे क्लाइंट किसी भी दिए गए क्वेरी में अनुरोध कर सकता है। इस उदाहरण में यहUserइंटरफ़ेस से मेल खाता है, लेकिन इसकी अनिवार्यता नहीं है। उदाहरण के लिए, हो सकता है कि आपकेUserइंटरफ़ेस में ऐसा डेटा हो जिसे आप कभी क्लाइंट को लौटाना न चाहें, जैसे पासवर्ड।Queryटाइप वह प्रकार परिभाषित करता है जिन क्वेरीज़ को हमारी API के भीतर निष्पादित किया जा सकता है। प्रत्येक क्वेरी एकUserयाUserकी एक array लौटाएगी, लेकिन इनके बीच में हम इन क्वेरीज़ में विशिष्ट लॉजिक रख सकते हैं।MutationटाइपQueryजैसा ही है, लेकिन इनका उद्देश्य डेटा में परिवर्तन करने वाली क्वेरीज़ होना है।GraphQL टाइप डेफिनिशनों के होने के बाद, हम एप्लिकेशन के रिजॉल्वर लॉजिक पर ध्यान केंद्रित कर सकते हैं। प्रोजेक्ट की src/resolvers/index.ts फ़ाइल में, निम्नलिखित कोड शामिल करें:
ऊपर दिए गए रिजॉल्वर वही विस्तार हैं जो हमने क्वेरीज़ और म्यूटेशनों के लिए टाइप डेफिनिशन फ़ाइल में देखे थे।
usersक्वेरी पर नज़र डालें:यह GraphQL क्वेरी हमारे
UserServiceका उपयोग करेगी, जो डेटाबेस लॉजिक का हिस्सा है, सभी यूज़र्स प्राप्त करने के लिए।User[]प्रतिक्रिया यूज़र को भेजी जाएगी, लेकिन केवल वही हिस्से जो यूज़र ने अनुरोधित किए हैं और जो GraphQL टाइप डेफिनिशंस से मेल खाते हैं।तो उदाहरण के लिए, मान लें कि क्लाइंट ने यह क्वेरी भेजी:
ऊपर के उदाहरण में हमारे पास काम करने के लिए और फ़ील्ड्स हैं, लेकिन क्लाइंट केवल
nameऔरemailफ़ील्ड चाहता है। इसे उसी GraphQL टाइप डेफिनिशनों के आधार पर संभाला गया जिनके साथ क्लाइंट काम कर रहा है। Apollo यह सब संभव बनाने का जादू संभालता है।यही नियम हमारी **src/resolvers/index.ts** फ़ाइल के भीतर हर क्वेरी और म्यूटेशन पर लागू होंगे।
createUserटाइप डेफिनिशन के लिए, हमने देखा कि क्लाइंटname,emailऔरageफ़ील्ड पास कर सकता है।createUserरिजॉल्वर फ़ंक्शन में, हम वही कर रहे हैं और अपने डेटाबेस सर्विस सेcreateUserफ़ंक्शन को कॉल कर रहे हैं। प्रतिक्रिया क्लाइंट को उन्हीं फ़ील्ड्स के आधार पर लौटाई जाती है जिन्हें उन्होंने अनुरोध किया है।GraphQL API को बिल्ड और रन करें
इस बिंदु पर, GraphQL API अच्छी अवस्था में होनी चाहिए। इस एप्लिकेशन को बिल्ड और रन करने के कई तरीके हैं।
उदाहरण के लिए, आप अपने **package.json** फ़ाइल में निम्नलिखित जोड़ सकते हैं:
यदि आपने यह तरीका चुना है, तो आप प्रोजेक्ट को बिल्ड करने के लिए
npm run buildचला सकते हैं और प्रोजेक्ट को सर्व करने के लिएnpm run start। डिफ़ॉल्ट पोर्ट 3000 है, और इसे cURL या आपकी पसंद के किसी भी टूल से टेस्ट किया जा सकता है।निष्कर्ष
आपने अभी देखा कि कैसे TypeScript और MongoDB को डेटाबेस के रूप में उपयोग करके एक GraphQL API बनाई जाती है। जबकि यह उदाहरण सरल रखने के लिए बनाया गया था, हमने देखा कि अपनी डेटाबेस पर CRUD ऑपरेशन करने के लिए क्वेरीज़ और म्यूटेशंस कैसे बनाते हैं। GraphQL API में MongoDB एक बेहतरीन मेल है, क्योंकि जिस डेटा के साथ आप काम कर रहे हैं, उसकी संरचना शुरुआत से अंत तक मिलती-जुलती रहती है। उदाहरण के लिए, क्लाइंट ऐसी क्वेरी चलाता है जो JSON जैसी दिखती है। क्वेरी के माध्यम से पास किया गया डेटा बहुत कम फ़ॉर्मैटिंग और समायोजन के साथ उपयोग किया जा सकता है, और डेटाबेस को भेजते समय और वहाँ से प्राप्त करते समय भी यही बात लागू होती है। अनुभव सुचारु रहता है, जिससे आप डेटाबेस की आवश्यकताओं के अनुकूल डेटा हेरफेर की बजाय उपयोगकर्ता अनुभव पर अधिक ध्यान केंद्रित कर सकते हैं।
यदि आप इस ट्यूटोरियल में किसी भी बिंदु पर अटक गए थे, तो GitHub पर तैयार प्रोजेक्ट ज़रूर देखें।