Rust وAPI: من REST إلى gRPC — نكتب بسرعة وأمان

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا Rust هو المرشح المثالي للعمل مع API؟

\n\n

إذا كنت لا تزال تعتقد أن Rust مخصص فقط للبرمجة النظامية واستبدال لغة C++، فأنت متأخر كثيرًا عن الواقع. لقد اقتحمت Rust عالم تطوير الويب وخدمات الواجهة الخلفية بثقة. ولم تقتحم فقط، بل احتلت مكانة حيث تكون السرعة والموثوقية وأمان الذاكرة مهمة.

\n\n

لكن لنكن صادقين: العمل مع API بلغة Rust ليس مجرد "أخذ مكتبة جاهزة ونسيان الأمر". إنه فن التوازن بين قوة اللغة وسهولة التطوير. في هذه المقالة، سنستعرض ثلاثة مناهج رئيسية: REST وGraphQL وgRPC. كل منها جيد بطريقته، والاختيار يعتمد على مهمتك. هيا بنا!

\n\n

REST بلغة Rust: الكلاسيكية التي تعمل

\n\n

لا يزال REST هو النمط الأكثر شيوعًا لـ API. إنه بسيط وبديهي ومدعوم من قبل الجميع حرفيًا. بالنسبة لـ Rust، هناك العديد من الأطر الممتازة، لكن الملك هنا هو actix-web. إنه سريع وغير متزامن وله نظام بيئي ممتاز.

\n\n

كتابة خدمة REST بسيطة باستخدام actix-web

\n\n

لنقم بإنشاء خدمة مصغرة لإدارة قائمة المهام (todo). سنحتاج إلى actix-web وserde للتسلسل وtokio كبيئة تشغيل غير متزامنة.

\n\n
// 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 غير المتزامنة. جرب تشغيله - ستفاجأ بمدى سرعته حتى على الأجهزة الضعيفة.

\n\n

متى لا يكون REST الخيار الأفضل؟

\n\n

REST مناسب تمامًا لعمليات CRUD، ولكن إذا كنت بحاجة إلى طلب بيانات بمرونة (مثل الموارد المتداخلة)، يبدأ REST في طلب العديد من نقاط النهاية. هنا يظهر GraphQL على المسرح.

\n\n

GraphQL بلغة Rust: مرونة بدون ألم

\n\n

يسمح GraphQL للعميل بطلب البيانات التي يحتاجها بالضبط. بالنسبة لـ Rust، الخيار الأفضل هو async-graphql. إنه يتكامل بشكل وثيق مع actix-web ويوفر DSL قوي لوصف المخططات.

\n\n

مثال: 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                

المدونات

توصيات الكتب