परिचय: REST या GraphQL — एक शाश्वत बहस जिसे हम Rust पर हल करेंगे
\n\nयदि आप Rust पर लिख रहे हैं और अपने API के लिए आर्किटेक्चर चुन रहे हैं, तो आपने निश्चित रूप से सोचा होगा: क्या चुनें — क्लासिक REST या फैशनेबल GraphQL? दोनों दृष्टिकोणों के प्रशंसकों की एक सेना और आलोचकों का एक समूह है। REST पर डेटा की अतिरेकता और क्लाइंट-सर्वर "बकबक" का आरोप लगाया जाता है। GraphQL पर कैशिंग की जटिलता और डेटाबेस पर "भयानक" क्वेरी का आरोप लगाया जाता है।
\n\nलेकिन आइए सच्चाई का सामना करें: Rust JavaScript या Python नहीं है। इसका दर्शन zero-cost abstractions और अधिकतम प्रदर्शन है। क्या इसका मतलब यह है कि एक दृष्टिकोण Rust पारिस्थितिकी तंत्र के लिए बेहतर है? आइए कोड के साथ वास्तविक उदाहरणों पर इसे समझें।
\n\nइस लेख में हम केवल फायदे और नुकसान सूचीबद्ध नहीं करेंगे। हम actix-web (REST) और async-graphql पर दो माइक्रोसर्विसेज लिखेंगे, उनके प्रदर्शन, विकास की जटिलता और रखरखाव की सुविधा की तुलना करेंगे। चलिए शुरू करते हैं!
संक्षिप्त परिचय: 30 सेकंड में REST और GraphQL
\n\nREST (Representational State Transfer) एक आर्किटेक्चरल शैली है जहां प्रत्येक संसाधन (उपयोगकर्ता, लेख, ऑर्डर) का अपना URL होता है। आप GET के माध्यम से डेटा प्राप्त करते हैं, POST के माध्यम से बनाते हैं, PUT/PATCH के माध्यम से अपडेट करते हैं। सब कुछ सरल और पूर्वानुमानित है। लेकिन अक्सर आपको आवश्यकता से अधिक डेटा मिलता है, या संबंधित संस्थाओं को इकट्ठा करने के लिए कई अनुरोध करने पड़ते हैं।
\n\nGraphQL एक क्वेरी भाषा और रनटाइम वातावरण है। क्लाइंट स्वयं तय करता है कि उसे किन फ़ील्ड की आवश्यकता है। एक अनुरोध — और आपको ठीक वही मिलता है जो आपने मांगा था। लेकिन इस लचीलेपन के लिए सर्वर पर कार्यान्वयन की जटिलता और प्रदर्शन की संभावित समस्याओं की कीमत चुकानी पड़ती है।
\n\nRust में, टाइप सिस्टम और एसिंक्रोनसी के कारण दोनों दृष्टिकोण उच्चतम स्तर पर लागू किए गए हैं। लेकिन आइए गहराई में जाएं।
\n\nRust पर REST: actix-web के साथ क्लासिक
\n\nआइए परिचित REST से शुरू करें। उदाहरण के लिए एक सरल ब्लॉग लेते हैं: इसमें उपयोगकर्ता, लेख और टिप्पणियाँ हैं। REST में हमें कई एंडपॉइंट बनाने होंगे।
\n\nuse actix_web::{web, App, HttpServer, Responder, HttpResponse};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Serialize, Deserialize)]\nstruct Article {\n id: i32,\n title: String,\n content: String,\n author_id: i32,\n}\n\nasync fn get_article(path: web::Path<i32>) -> impl Responder {\n let article_id = path.into_inner();\n // मान लीजिए हम DB से लेख निकाल रहे हैं\n let article = Article {\n id: article_id,\n title: "GraphQL vs REST".to_string(),\n content: "विस्तृत तुलना...".to_string(),\n author_id: 1,\n };\n HttpResponse::Ok().json(article)\n}\n\nasync fn get_articles_by_author(path: web::Path<i32>) -> impl Responder {\n let author_id = path.into_inner();\n // लेखक के लेखों की सूची\n let articles = vec![\n Article { id: 1, title: "लेख 1".to_string(), content: "पाठ...".to_string(), author_id },\n Article { id: 2, title: "लेख 2".to_string(), content: "पाठ...".to_string(), author_id },\n ];\n HttpResponse::Ok().json(articles)\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n HttpServer::new(|| {\n App::new()\n .route("/articles/{id}", web::get().to(get_article))\n .route("/authors/{id}/articles", web::get().to(get_articles_by_author))\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\nसब कुछ साफ और समझने योग्य दिखता है। Rust पर REST के लाभ:
\n- \n
- HTTP स्तर पर कैशिंग की सरलता (ETag, Cache-Control)। \n
- पारदर्शी संरचना — प्रत्येक एंडपॉइंट एक काम करता है। \n
- किसी भी क्लाइंट (curl, Postman, ब्राउज़र) के साथ आसान एकीकरण। \n
लेकिन नुकसान भी हैं:
\n- \n
- N+1 क्वेरी समस्या। लेख और लेखक प्राप्त करने के लिए दो अनुरोधों की आवश्यकता है। या JOIN के साथ एक अलग एंडपॉइंट बनाना होगा। \n
- Over-fetching।