توليد Swagger/OpenAPI لـ Rust: Utoipa — أداة حديثة للتوثيق التلقائي
\n\nعند تطوير تطبيقات الويب بلغة Rust، فإن توثيق API ليس رفاهية بل ضرورة. توفر مكتبة Utoipa (اختصار لـ "Utopia") طريقة قوية وأنيقة لتوليد مواصفات OpenAPI مباشرة من الكود. تتكامل مع أطر العمل الشائعة مثل actix-web و axum و rocket و warp، وتسمح بوصف نقاط النهاية ومخططات البيانات والمعاملات باستخدام السمات والماكرو.
الميزات الرئيسية لـ Utoipa
\n- \n
- توليد تلقائي لـ OpenAPI 3.0/3.1 — دون كتابة يدوية لـ YAML/JSON. \n
- دعم أطر عمل متعددة — actix-web, axum, rocket, warp. \n
- التكامل مع Swagger UI — مكون مدمج لعرض التوثيق بشكل مرئي. \n
- وصف عميق للمخططات — دعم الهياكل المتداخلة، التعدادات، الحقول الاختيارية. \n
- ماكرو للوصف السريع —
#[utoipa::path],#[openapi]. \n - التحقق من صحة المواصفات — التأكد من صحة المستند المُنشأ. \n
التثبيت والإعداد
\nأضف التبعيات في ملف Cargo.toml. على سبيل المثال، سنختار إطار العمل actix-web:
[dependencies]\nutoipa = "4"\nutoipa-swagger-ui = { version = "4", features = ["actix-web"] }\nactix-web = "4"\nserde = { version = "1", features = ["derive"] }\n\n\nمثال أساسي: إنشاء API مع التوثيق
\nلننظر إلى CRUD بسيط لكيان "مستخدم". نبدأ بتعريف نموذج البيانات:
\nuse serde::{Deserialize, Serialize};\nuse utoipa::ToSchema;\n\n#[derive(Serialize, Deserialize, ToSchema)]\npub struct User {\n #[schema(example = "1")]\n pub id: i32,\n #[schema(example = "john_doe")]\n pub username: String,\n #[schema(example = "john@example.com")]\n pub email: String,\n}\n\nالآن نصف نقطة نهاية الحصول على قائمة المستخدمين باستخدام الماكرو #[utoipa::path]:
use actix_web::{get, web, HttpResponse, Responder};\nuse utoipa::OpenApi;\n\n#[utoipa::path(\n get,\n path = "/users",\n responses(\n (status = 200, description = "قائمة المستخدمين", body = Vec<User>)\n )\n)]\n#[get("/users")]\nasync fn get_users() -> impl Responder {\n let users = vec![\n User { id: 1, username: "alice".into(), email: "alice@example.com".into() },\n User { id: 2, username: "bob".into(), email: "bob@example.com".into() },\n ];\n HttpResponse::Ok().json(users)\n}\n\n\nبناء مستند OpenAPI و Swagger UI
\nننشئ هيكلًا لوصف API بالكامل:
\n#[derive(OpenApi)]\n#[openapi(\n paths(get_users),\n components(schemas(User))\n)]\npub struct ApiDoc;\n\n// في الدالة main نقوم بإعداد Swagger UI\nuse utoipa_swagger_ui::SwaggerUi;\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n use actix_web::App;\n\n HttpServer::new(|| {\n App::new()\n .service(get_users)\n .service(\n SwaggerUi::new("/swagger-ui/{_:.*}")\n .url("/api-docs/openapi.json", ApiDoc::openapi())\n )\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\nبعد تشغيل التطبيق، سيكون التوثيق متاحًا على الرابط http://localhost:8080/swagger-ui/.
ميزات متقدمة: المخططات المتداخلة والمعاملات
\nيدعم Utoipa أنواع البيانات المعقدة. على سبيل المثال، نضيف حقلًا بهيكل متداخل:
\n#[derive(Serialize, Deserialize, ToSchema)]\npub struct Address {\n #[schema(example = "موسكو")]\n pub city: String,\n #[schema(example = "شارع لينين، مبنى 1")]\n pub street: String,\n}\n\n