مقدمة: لماذا GraphQL وKotlin؟
\nفي عالم تطوير الويب الحديث، يمكن أن يحدد اختيار النهج الصحيح لإنشاء API نجاح المشروع بأكمله. يقدم GraphQL، الذي طورته Facebook، بديلاً مرناً لـ REST، مما يسمح للعملاء بطلب البيانات التي يحتاجونها فقط. أما Kotlin، وهي لغة برمجة حديثة لـ JVM، فتضيف إلى ذلك الإيجاز، والسلامة من القيم الفارغة، والدعم القوي للروتينات المتزامنة.
\nفي هذا الدليل التعليمي، سنقوم عملياً بإنشاء GraphQL API كامل باستخدام Kotlin وإطار العمل graphql-kotlin-spring-server. ستتعلم كيفية إعداد الخادم، وتحديد مخطط البيانات، وكتابة المحللات، واختبار API. في نهاية المقال، ستكون قادراً على دمج GraphQL في مشاريعك الخاصة باستخدام Kotlin.
1. إعداد المشروع والتبعيات
\nللبدء، سننشئ مشروعاً جديداً على Spring Boot مع دعم GraphQL. سنستخدم Gradle كنظام بناء.
\n\n1.1. إنشاء الهيكل الأساسي
\nأنشئ مشروعاً جديداً في IntelliJ IDEA أو عبر Spring Initializr. أضف التبعيات التالية في ملف build.gradle.kts:
plugins {\n id("org.springframework.boot") version "3.2.0"\n id("io.spring.dependency-management") version "1.1.4"\n kotlin("jvm") version "1.9.21"\n kotlin("plugin.spring") version "1.9.21"\n}\n\ndependencies {\n implementation("org.springframework.boot:spring-boot-starter-web")\n implementation("com.expediagroup:graphql-kotlin-spring-server:7.0.1")\n implementation("org.jetbrains.kotlin:kotlin-reflect")\n implementation("org.jetbrains.kotlin:kotlin-stdlib")\n testImplementation("org.springframework.boot:spring-boot-starter-test")\n}\n\n1.2. تكوين التطبيق
\nأنشئ ملف application.yml في src/main/resources:
server:\n port: 8080\n\ngraphql:\n packages:\n - "com.example.graphqldemo"\n schema:\n introspection-enabled: true\n exception-handlers-enabled: true\nهذا تكوين أساسي. المعامل introspection-enabled: true يسمح باستخدام GraphiQL للاختبار.
2. تعريف مخطط GraphQL
\nفي graphql-kotlin، يتم بناء المخطط تلقائياً بناءً على فئات البيانات الخاصة بك (data classes). هذه إحدى المزايا الرئيسية - ليست هناك حاجة لكتابة ملف SDL منفصل.
2.1. إنشاء نموذج البيانات
\nلنفترض أننا ننشئ API لمكتبة كتب. دعنا نحدد النماذج:
\npackage com.example.graphqldemo.model\n\ndata class Book(\n val id: String,\n val title: String,\n val author: Author,\n val year: Int,\n val genre: String\n)\n\ndata class Author(\n val id: String,\n val name: String,\n val books: List<Book> = emptyList()\n)\n\n// أنواع الإدخال للتحويرات\ndata class BookInput(\n val title: String,\n val authorId: String,\n val year: Int,\n val genre: String\n)\n\n2.2. خدمة التعامل مع البيانات
\nلننشئ خدمة بسيطة في الذاكرة لتخزين البيانات:
\npackage com.example.graphqldemo.service\n\nimport com.example.graphqldemo.model.Author\nimport com.example.graphqldemo.model.Book\nimport com.example.graphqldemo.model.BookInput\nimport org.springframework.stereotype.Service\nimport java.util.UUID\n\n@Service\nclass LibraryService {\n private val authors = mutableListOf(\n Author("1", "جوان رولينج"),\n Author("2", "جورج أورويل")\n )\n private val books = mutableListOf(\n Book("1", "هاري بوتر وحجر الفيلسوف", authors[0], 1997, "فانتازيا"),\n Book("2", "1984", authors[1], 1949, "ديستوبيا")\n )\n\n fun getBooks(): List<Book> = books\n fun getBookById(id: String): Book? = books.find { it.id == id }\n fun getAuthors(): List<Author> = authors\n fun addBook(input: BookInput): Book {\n val author = authors.fin