مقدمة: لماذا Rust لواجهات REST API؟
Rust هي لغة برمجة نظامية حديثة تجمع بين أداء C++ وأمان الذاكرة. في السنوات الأخيرة، تم استخدامها بنشاط لبناء خدمات الويب عالية التحميل وواجهات REST API. في هذا الدليل، سنقوم خلال 30 دقيقة بإنشاء REST API كامل باستخدام Rust وإطار العمل Actix-web.
لماذا تختار Rust لواجهات REST API؟
- الأداء: يتم ترجمة Rust إلى كود أصلي ولا يستخدم جامع القمامة، مما يوفر أقصى سرعة في معالجة الطلبات.
- الأمان: نظام الملكية (ownership) والاقتراض (borrowing) يستبعد فئات كاملة من الأخطاء المتعلقة بالذاكرة.
- قابلية التوسع: Actix-web هو أحد أسرع أطر العمل في العالم، قادر على معالجة ملايين الطلبات في الثانية.
بنهاية المقال، سيكون لديك مشروع جاهز مع عدة نقاط نهاية (endpoints)، ومعالجة للأخطاء، وهيكل للتوسع المستقبلي.
الخطوة 1: إعداد المشروع وتثبيت التبعيات
أولاً، سنقوم بإنشاء مشروع Cargo جديد. افتح الطرفية ونفذ:
cargo new rust_rest_api
cd rust_rest_api
الآن، افتح ملف Cargo.toml وأضف التبعيات التالية:
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
دعنا نشرح ما تفعله كل مكتبة:
- actix-web — إطار العمل الرئيسي لبناء خادم HTTP.
- serde / serde_json — تسلسل وإلغاء تسلسل البيانات إلى تنسيق JSON.
- tokio — بيئة تشغيل غير متزامنة، ضرورية لعمل Actix.
- uuid — توليد معرفات فريدة للكيانات الخاصة بنا.
نفذ الأمر cargo build لتحميل جميع التبعيات. قد يستغرق هذا بعض الوقت في التشغيل الأول.
الخطوة 2: إنشاء نموذج البيانات والتخزين
سيدير API الخاص بنا قائمة المهام (تطبيق TODO). لنقم بإنشاء نموذج بسيط. افتح src/main.rs وأضف الكود التالي:
use actix_web::{web, App, HttpServer, HttpResponse, middleware::Logger};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use uuid::Uuid;
// نموذج المهمة
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Task {
id: Uuid,
title: String,
completed: bool,
}
// طلب إنشاء مهمة
#[derive(Debug, Deserialize)]
struct CreateTaskRequest {
title: String,
}
// تخزين المهام (في الذاكرة)
struct AppState {
tasks: Mutex>,
}
نستخدم Mutex للوصول الآمن إلى البيانات في بيئة متعددة الخيوط. في مشروع حقيقي، ستستبدل هذا بقاعدة بيانات، لكن هذا الخيار مناسب للعرض التوضيحي.
الآن، أضف دالة لتهيئة حالة التطبيق:
fn init_tasks() -> Vec {
vec![
Task {
id: Uuid::new_v4(),
title: "تعلم Rust".to_string(),
completed: false,
},
Task {
id: Uuid::new_v4(),
title: "كتابة REST API".to_string(),
completed: true,
},
]
}
الخطوة 3: تنفيذ نقاط النهاية CRUD
الآن، سنقوم بإنشاء المعالجات الأساسية لـ REST API الخاص بنا. أضف الكود التالي بعد تعريف النماذج:
GET /tasks — الحصول على قائمة بجميع المهام
async fn get_tasks(data: web::Data<AppState>) -> HttpResponse {
let tasks = data.tasks.lock().unwrap();
HttpResponse::Ok().json(tasks.clone())
}
POST /tasks — إنشاء مهمة جديدة
async fn create_task(
data: web::Dat