Juniper — GraphQL بلغة Rust مع أمان الأنواع والأداء العالي
في عالم واجهات برمجة تطبيقات الويب الحديثة، أصبحت GraphQL معيارًا لبناء واجهات مرنة وفعالة. إذا كنت تطور باستخدام Rust وتبحث عن مكتبة ناضجة وآمنة وسريعة لتنفيذ GraphQL، فإن Juniper هو ما تحتاجه. يوفر Juniper نهجًا يعتمد على الماكرو التصريحي، ودعمًا كاملاً لأنواع Rust، وتكاملًا سلسًا مع أطر الويب الشائعة.
يتيح لك Juniper وصف مخطط GraphQL مباشرة من خلال الهياكل والتعدادات في Rust، مما يضمن أمان الأنواع (type-safety) في جميع المراحل. تدعم المكتبة الاشتراكات (subscriptions)، والتحويرات (mutations)، والأنواع المعقدة، والواجهات، وأنواع الاتحاد (union-types)، والعدديات المخصصة. بفضل التجريدات ذات التكلفة الصفرية في Rust، يعمل Juniper بأقل تكاليف إضافية.
الميزات الرئيسية لـ Juniper
- وصف تصريحي للمخطط — استخدم الماكرو
#[derive(GraphQLObject)]و#[derive(GraphQLInputObject)]و#[derive(GraphQLEnum)]. - دعم التزامن غير المتزامن — يعمل مع
async/awaitوأي بيئة تشغيل غير متزامنة (Tokio، async-std). - سياقات مدمجة — مرر الحالة (قاعدة بيانات، تفويض) عبر
Context. - الاشتراكات (Subscriptions) — تنفيذ التحديثات في الوقت الفعلي عبر WebSocket.
- التكامل مع الأطر — حزم رسمية لـ
actix-webوrocketوwarpوaxumوiron. - التحقق من الصحة والأخطاء — فحص تلقائي للأنواع وأخطاء مخصصة عبر
FieldError.
بداية سريعة مع Juniper وActix-web
لنلقِ نظرة على مثال بسيط لخادم GraphQL باستخدام Actix-web. للبدء، أضف التبعيات إلى Cargo.toml:
[dependencies]juniper = "0.16"actix-web = "4"actix-rt = "2"serde = { version = "1", features = ["derive"] }serde_json = "1"الآن، لننشئ مخططًا بسيطًا مع استعلام جذر واحد:
use juniper::{GraphQLObject, GraphQLInputObject, FieldResult, Context, RootNode};
// تعريف كائن للرد#[derive(GraphQLObject)]struct User { id: i32, name: String, email: String,}
// كائن إدخال للتحوير#[derive(GraphQLInputObject)]struct CreateUserInput { name: String, email: String,}
// السياق — مخزن بيانات (مثل in-memory)pub struct Database { users: Vec<User>,}
impl Context for Database {}
// الاستعلامات الجذرية (Query)pub struct Query;
#[juniper::graphql_object(context = Database)]impl Query { fn users(context: &Database) -> Vec<User> { context.users.clone() }
fn user(context: &Database, id: i32) -> Option<User> { context.users.iter().find(|u| u.id == id).cloned() }}
// التحويرات الجذرية (Mutation)pub struct Mutation;
#[juniper::graphql_object(context = Database)]impl Mutation { fn create_user(context: &mut Database, input: CreateUserInput) -> FieldResult<User> { let new_id = context.users.len() as i32 + 1; let user = User { id: new_id, name: input.name, email: input.email, }; context.users.push(user.clone()); Ok(user) }}
// تجميع المخططpub type Schema = RootNode<'static, Query, Mutation>;التكامل مع Actix-web
الآن، لنربط Juniper بنقاط نهاية HTTP في Actix-web:
use actix_web::{web, App, HttpServer, HttpResponse, middleware};use juniper_actix::{graphql_handler, playground_handler};use std::sync::Mutex;\