Rust API के साथ काम करने के लिए आदर्श क्यों है?
\n\nयदि आप अब भी सोचते हैं कि Rust केवल सिस्टम प्रोग्रामिंग और C++ के विकल्प के लिए है, तो आप वास्तविकता से बहुत पीछे हैं। Rust ने वेब डेवलपमेंट और बैकएंड सेवाओं की दुनिया में आत्मविश्वास से प्रवेश किया है। और केवल प्रवेश ही नहीं किया, बल्कि उस क्षेत्र में अपनी जगह बनाई है जहाँ गति, विश्वसनीयता और मेमोरी सुरक्षा महत्वपूर्ण हैं।
\n\nलेकिन ईमानदारी से कहें तो: Rust पर API के साथ काम करना केवल "एक तैयार लाइब्रेरी लेना और भूल जाना" नहीं है। यह भाषा की शक्ति और डेवलपमेंट की सुविधा के बीच संतुलन बनाने की कला है। इस लेख में हम तीन मुख्य दृष्टिकोणों पर चर्चा करेंगे: REST, GraphQL और gRPC। इनमें से प्रत्येक अपने तरीके से अच्छा है, और चुनाव आपके कार्य पर निर्भर करता है। चलिए शुरू करते हैं!
\n\nRust पर REST: क्लासिक जो काम करता है
\n\nREST अब भी API की सबसे लोकप्रिय शैली है। यह सरल, सहज और लगभग हर चीज़ द्वारा समर्थित है। Rust के लिए कई बेहतरीन फ्रेमवर्क हैं, लेकिन यहाँ राजा actix-web है। यह तेज़, एसिंक्रोनस और एक उत्कृष्ट इकोसिस्टम के साथ आता है।
actix-web पर एक सरल REST सेवा लिखना
\n\nआइए कार्यों (todo) की सूची प्रबंधित करने के लिए एक मिनी-सेवा बनाएँ। हमें actix-web, सीरियलाइज़ेशन के लिए serde और एसिंक्रोनस रनटाइम के रूप में tokio की आवश्यकता होगी।
// Cargo.toml\n// [dependencies]\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n// serde_json = "1"\n// tokio = { version = "1", features = ["full"] }\n\nuse actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};\nuse serde::{Deserialize, Serialize};\nuse std::sync::Mutex;\n\n#[derive(Serialize, Deserialize, Clone)]\nstruct Task {\n id: u32,\n title: String,\n completed: bool,\n}\n\nstruct AppState {\n tasks: Mutex<Vec<Task>>,\n}\n\n#[get("/tasks")]\nasync fn get_tasks(data: web::Data<AppState>) -> impl Responder {\n let tasks = data.tasks.lock().unwrap();\n HttpResponse::Ok().json(tasks.clone())\n}\n\n#[post("/tasks")]\nasync fn create_task(data: web::Data<AppState>, body: web::Json<Task>) -> impl Responder {\n let mut tasks = data.tasks.lock().unwrap();\n let new_id = tasks.len() as u32 + 1;\n let task = Task {\n id: new_id,\n title: body.title.clone(),\n completed: false,\n };\n tasks.push(task.clone());\n HttpResponse::Created().json(task)\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n let state = web::Data::new(AppState {\n tasks: Mutex::new(vec![]),\n });\n\n HttpServer::new(move || {\n App::new()\n .app_data(state.clone())\n .service(get_tasks)\n .service(create_task)\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\n\nइस कोड की खूबसूरती यह है कि यह मेमोरी-सुरक्षित है और इसे गार्बेज कलेक्टर की आवश्यकता नहीं है। actix-web Rust के एसिंक्रोनस मैकेनिज़्म का उपयोग करके एक थ्रेड पर प्रति सेकंड हजारों अनुरोधों को संसाधित करता है। इसे चलाने का प्रयास करें — आपको आश्चर्य होगा कि यह कमजोर हार्डवेयर पर भी कितना तेज़ है।
REST कब सबसे अच्छा विकल्प नहीं है?
\n\nREST CRUD संचालन के लिए उपयुक्त है, लेकिन यदि आपको लचीले ढंग से डेटा का अनुरोध करने की आवश्यकता है (जैसे, नेस्टेड संसाधन), तो REST को कई एंडपॉइंट की आवश्यकता होने लगती है। यहाँ GraphQL दृश्य में आता है।
\n\nRust पर GraphQL: बिना दर्द के लचीलापन
\n\nGraphQL क्लाइंट को ठीक उसी डेटा का अनुरोध करने की अनुमति देता है जिसकी उन्हें आवश्यकता है। Rust के लिए सबसे अच्छा विकल्प async-graphql है। यह actix-web के साथ निकटता से एकीकृत होता है और स्कीमा का वर्णन करने के लिए एक शक्तिशाली DSL प्रदान करता है।
उदाहरण: पुस्तक पुस्तकालय के लिए API
\n\nमान लीजिए, हम क्लाइंट को पुस्तकों और लेखकों का अनुरोध करने की क्षमता देना चाहते हैं। GraphQL के साथ यह एक ही स्कीमा में किया जाता है।
\n\n// Cargo.toml\n// [dependencies]\n// async-graphql = "7"\n// async-graphql-actix-web = "7"\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n\nuse async_graphql::{Context, EmptyMutatio