Go में GraphQL बनाम REST: दिग्गजों का मुकाबला, या चुनाव में गलती कैसे न करें
\n\nयदि आप कम से कम छह महीने से Go में लिख रहे हैं, तो आपने निश्चित रूप से शाश्वत बहस का सामना किया होगा: REST या GraphQL? एक पुराना, भरोसेमंद "काम का घोड़ा" है, दूसरा ढेर सारे विकल्पों वाला एक फैशनेबल "स्पोर्ट्स कार" है। लेकिन Go की दुनिया में, जहाँ प्रदर्शन और सरलता धर्म है, चुनाव हमेशा स्पष्ट नहीं होता।
\n\nइस लेख में हम केवल फायदे और नुकसान सूचीबद्ध नहीं करेंगे। हम Go में वास्तविक कोड लिखेंगे, निष्पादन समय मापेंगे, और विश्लेषण करेंगे कि GraphQL कब पैर में गोली मारने जैसा है, और कब यह कुशल API की दुनिया में एक धोखेबाज पास है। चलिए शुरू करते हैं!
\n\nGo में REST: स्थिरता और पूर्वानुमान
\n\nREST एक पुराने, सिद्ध हथौड़े की तरह है। यह चमकता नहीं है, लेकिन कीलों को पूरी तरह से ठोकता है। Go में REST API net/http या gin और chi जैसे हल्के फ्रेमवर्क पर लिखे जाते हैं। आइए एक सरल उदाहरण देखें:
package main\n\nimport (\n "encoding/json"\n "net/http"\n)\n\ntype User struct {\n ID int `json:"id"`\n Name string `json:"name"`\n}\n\nfunc getUserHandler(w http.ResponseWriter, r *http.Request) {\n user := User{ID: 1, Name: "एलेक्सी"}\n w.Header().Set("Content-Type", "application/json")\n json.NewEncoder(w).Encode(user)\n}\n\nfunc main() {\n http.HandleFunc("/api/user", getUserHandler)\n http.ListenAndServe(":8080", nil)\n}\n\nसुंदर? हाँ। सरल? बहुत। लेकिन क्या होगा अगर फ्रंटएंड को केवल उपयोगकर्ता नाम चाहिए, और हम पूरा ऑब्जेक्ट ले जा रहे हैं? REST में इसे over-fetching कहा जाता है - डेटा की अधिकता। और Go में, जहाँ हम हर बाइट को नियंत्रित करने के आदी हैं, यह परेशान करने वाला हो सकता है।
\n\nREST में N+1 समस्या
\n\nमान लीजिए, हमारे पास ऑर्डर की एक सूची है, और प्रत्येक के लिए उपयोगकर्ता नाम चाहिए। REST में हम या तो N अनुरोध करते हैं (धीमा), या एक अलग एंडपॉइंट /api/orders-with-users बनाते हैं (बहुत सारे एंडपॉइंट)। Go डेटाबेस में join-क्वेरी के माध्यम से इससे निपटता है, लेकिन API स्तर पर यह अभी भी अनाड़ी लगता है।
Go में GraphQL: शक्ति और लचीलापन
\n\nGraphQL एक स्विस चाकू की तरह है: एक एंडपॉइंट, और क्लाइंट खुद तय करता है कि उसे कौन सा डेटा चाहिए। Go में इसके लिए gqlgen (99designs से) फ्रेमवर्क है - यह स्कीमा से कोड जनरेट करता है, जो Go की भावना के अनुरूप है (कम बॉयलरप्लेट - अधिक काम)।
// schema.graphql\ntype Query {\n user(id: Int!): User\n}\n\ntype User {\n id: Int!\n name: String!\n orders: [Order!]!\n}\n\ntype Order {\n id: Int!\n total: Float!\n}\n\nअब Go में कार्यान्वयन:
\n\npackage graph\n\nimport (\n "context"\n "fmt"\n)\n\ntype Resolver struct{}\n\nfunc (r *Resolver) User(ctx context.Context, args struct{ ID int }) (*User, error) {\n // वास्तव में - DB क्वेरी\n return &User{\n ID: args.ID,\n Name: "मारिया",\n Orders: []*Order{\n {ID: 1, Total: 250.50},\n },\n }, nil\n}\n\nक्लाइंट केवल name का अनुरोध करता है - केवल name प्राप्त करता है। कोई over-fetching नहीं। लेकिन एक बारीक बात है: यदि क्लाइंट 10 उपयोगकर्ताओं के लिए orders का अनुरोध करता है, और प्रत्येक के 50 ऑर्डर हैं - डेटाबेस घुटनों पर आ सकता है। इसे GraphQL में N+1 समस्या कहा जाता है, और Go में इसे DataLoaders के माध्यम से हल किया जाता है।
DataLoader - N+1 से बचाने वाला
\n\nimport "github.com/graph-gophers/dataloader"\n\ntype UserLoader struct {\n *dataloader.Loader\n}\n\nfunc NewUserLoader() *UserLoader {\n return &UserLoader{\n Loader: dataloader.NewBatchedLoader(func(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {\n // DB क्वेरी को बैच करें\n userIDs := make([]int, len(keys))\n for i, key := range keys {\n userIDs[i] = key.Int()\n }\n users := batchFetchUsers(userIDs) // WHERE IN के साथ एक SQL क्वेरी\n results := make([]*dataloader.Result, len(ke