Skip to content

توثيق الـ API

يُولّد FORGE توثيق API تفاعلي باستخدام مواصفات OpenAPI 3.0. التوثيق يُولّد تلقائياً من تعليقات الـ handler وتعريفات أنواع الـ DTO، مما يضمن بقاء التوثيق متزامناً دائماً مع الكود. المشروع المُولّد يتضمن واجهتي Swagger UI و ReDoc جاهزتين للاستخدام.

نقاط نهاية التوثيق

نقطة النهايةالواجهةالوصف
/docsSwagger UIمستكشف API تفاعلي
/redocReDocتوثيق نظيف وقابل للقراءة
/api-docs/openapi.jsonJSON خامملف مواصفات OpenAPI 3.0

افتح Swagger UI في متصفحك على http://localhost:8080/docs بعد تشغيل خادم التطوير.

نصيحة

Swagger UI يسمح لك بتنفيذ استدعاءات API مباشرة من المتصفح. انقر على "Authorize" والصق JWT token الخاص بك لاختبار نقاط النهاية المُصادق عليها بدون مغادرة صفحة التوثيق.

كيف يعمل

يستخدم FORGE مكتبة Utoipa لتوليد مواصفات OpenAPI من كود Rust. التوثيق يُستمد من ثلاثة مصادر:

  1. تعليقات الـ Handler تُعرّف مسارات نقاط النهاية والطرق والمعاملات والاستجابات
  2. derives الـ DTO تُعرّف مخططات الطلب/الاستجابة
  3. tags الوحدات تُنظّم نقاط النهاية في مجموعات منطقية
┌──────────────┐     ┌──────────────┐     ┌────────────────┐
│  #[utoipa::  │     │  ToSchema    │     │   ApiDoc       │
│   path(...)] │────▶│  derives     │────▶│   struct       │
│  على handlers│     │  على DTOs   │     │   (يجمع        │
│              │     │              │     │    كل شيء)     │
└──────────────┘     └──────────────┘     └────────────────┘


                                          ┌────────────────┐
                                          │  OpenAPI JSON   │
                                          │  /docs (Swagger)│
                                          │  /redoc         │
                                          └────────────────┘

تعليق الـ Handlers

أضف attribute الـ #[utoipa::path] لكل handler لإدراجه في التوثيق المُولّد:

rust
use utoipa;

/// List all users with pagination
#[utoipa::path(
    get,
    path = "/api/admin/users",
    tag = "Users",
    params(
        ("page" = Option<i64>, Query, description = "رقم الصفحة"),
        ("per_page" = Option<i64>, Query, description = "عدد العناصر لكل صفحة"),
        ("search" = Option<String>, Query, description = "البحث بالاسم أو البريد"),
    ),
    responses(
        (status = 200, description = "قائمة مستخدمين مُرقّمة", body = PaginatedResponse<UserResponse>),
        (status = 401, description = "غير مُصادق", body = ErrorResponse),
        (status = 403, description = "ممنوع", body = ErrorResponse),
    ),
    security(
        ("bearer_auth" = [])
    )
)]
pub async fn list_users(
    State(pool): State<PgPool>,
    Extension(user): Extension<AuthUser>,
    Query(params): Query<PaginatedRequest>,
) -> Result<impl IntoResponse, AppError> {
    let users = UserService::list(&pool, &params).await?;
    Ok(Json(ApiResponse::success(users)))
}

مرجع التعليقات

Attributeالغرضمثال
get/post/put/deleteطريقة HTTPget
pathمسار URL"/api/admin/users/{id}"
tagاسم المجموعة في التوثيق"Users"
paramsمعاملات Query/path("id" = Uuid, Path, description = "...")
request_bodyمخطط جسم الطلبbody = CreateUserRequest
responsesاستجابات HTTP الممكنة(status = 200, body = UserResponse)
securityمتطلبات المصادقة("bearer_auth" = [])

اشتقاق المخططات للـ DTOs

جميع أنواع الطلب والاستجابة تشتق ToSchema لتوليد المخطط تلقائياً:

rust
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use validator::Validate;

/// Request to create a new user
#[derive(Deserialize, Validate, ToSchema)]
pub struct CreateUserRequest {
    /// User's full name
    #[schema(example = "Jane Doe")]
    #[validate(length(min = 1, max = 255))]
    pub name: String,

    /// Email address (must be unique)
    #[schema(example = "jane@example.com")]
    #[validate(email)]
    pub email: String,

    /// Password (minimum 8 characters)
    #[schema(example = "securepassword123")]
    #[validate(length(min = 8))]
    pub password: String,

    /// Role IDs to assign
    #[schema(example = json!(["550e8400-e29b-41d4-a716-446655440000"]))]
    pub role_ids: Option<Vec<Uuid>>,
}

/// User response returned from API
#[derive(Serialize, ToSchema)]
pub struct UserResponse {
    pub id: Uuid,
    pub name: String,
    pub email: String,
    pub is_active: bool,
    pub roles: Vec<RoleResponse>,
    pub created_at: chrono::DateTime<chrono::Utc>,
}

نصيحة

استخدم #[schema(example = ...)] لتوفير قيم أمثلة ذات معنى. هذه تظهر في ميزة "Try it out" في Swagger UI، مما يُسهّل على مطوري الواجهة الأمامية فهم الصيغ المتوقعة.

تنظيم الـ Tags

نقاط النهاية تُجمّع بـ tags تُقابل الوحدات:

rust
use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
    info(
        title = "FORGE API",
        version = "1.0.0",
        description = "Auto-generated API documentation"
    ),
    tags(
        (name = "Auth", description = "نقاط نهاية المصادقة"),
        (name = "Users", description = "إدارة المستخدمين"),
        (name = "Roles", description = "إدارة الأدوار"),
        (name = "Permissions", description = "إدارة الصلاحيات"),
        (name = "Contents", description = "إدارة المحتوى"),
        (name = "Settings", description = "إعدادات التطبيق"),
        (name = "Profile", description = "ملف المستخدم الحالي"),
        (name = "Media", description = "رفع الملفات والوسائط"),
    ),
    paths(
        handlers::auth::login,
        handlers::auth::register,
        handlers::auth::refresh,
        handlers::auth::logout,
        handlers::admin::users::list_users,
        handlers::admin::users::create_user,
        handlers::admin::users::show_user,
        handlers::admin::users::update_user,
        handlers::admin::users::delete_user,
        // ... more handlers
    ),
    components(
        schemas(
            CreateUserRequest,
            UpdateUserRequest,
            UserResponse,
            LoginRequest,
            TokenResponse,
            ApiResponse<UserResponse>,
            PaginatedResponse<UserResponse>,
            ErrorResponse,
            // ... more schemas
        )
    ),
    modifiers(&SecurityAddon)
)]
pub struct ApiDoc;

مخطط الأمان

مصادقة JWT bearer token مُسجّلة كمخطط أمان:

rust
use utoipa::Modify;
use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};

struct SecurityAddon;

impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "bearer_auth",
                SecurityScheme::Http(
                    HttpBuilder::new()
                        .scheme(HttpAuthScheme::Bearer)
                        .bearer_format("JWT")
                        .build(),
                ),
            );
        }
    }
}

تقديم التوثيق

مسارات التوثيق تُسجّل في main.rs:

rust
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
use utoipa_redoc::{Redoc, Servable};

let app = Router::new()
    // API routes
    .nest("/api/admin", routes::admin::routes(pool.clone()))
    .nest("/api", routes::public::routes(pool.clone()))
    // Documentation
    .merge(SwaggerUi::new("/docs").url("/api-docs/openapi.json", ApiDoc::openapi()))
    .merge(Redoc::with_url("/redoc", ApiDoc::openapi()));

أوامر CLI

توثيق الـ API يُولّد تلقائياً من تعليقات الـ handler الخاصة بك. مواصفات OpenAPI تُقدّم على https://api.<yourapp>.test/docs عند تشغيل خادم التطوير بـ forge serve.

نصيحة

خادم الـ API يُعرّض Swagger UI مدمج على نقطة النهاية /docs. لا يُحتاج لأمر CLI منفصل — فقط شغّل الخادم وانتقل لعنوان التوثيق.

تخصيص التوثيق

إضافة الأوصاف

استخدم تعليقات توثيق Rust على الـ handlers والـ DTOs. تصبح تلقائياً أوصاف OpenAPI:

rust
/// Create a new content entry
///
/// Creates a content entry with translations for all supported languages.
/// The slug must be unique across all content entries.
/// Requires `contents.create` permission.
#[utoipa::path(/* ... */)]
pub async fn create_content(/* ... */) {
    // ...
}

إخفاء نقاط النهاية الداخلية

احذف نقاط النهاية الداخلية من قائمة paths في struct الـ ApiDoc. فقط الـ handlers المُدرجة في attribute الـ #[openapi(paths(...))] تظهر في التوثيق.

انظر أيضاً

  • الـ Handlers — كتابة handlers مع تعليقات التوثيق
  • الـ DTOs — أنواع الطلب/الاستجابة مع اشتقاق المخطط
  • الـ Routes — تسجيل المسارات لنقاط النهاية المُوثّقة

Released under the MIT License.