مقدمة إلى GraphQL وKotlin
GraphQL هي لغة استعلام لواجهات برمجة التطبيقات (API) تتيح للعملاء تلقي البيانات التي يحتاجونها فقط. على عكس REST، حيث يعيد كل نقطة نهاية بنية ثابتة، توفر GraphQL مرونة: يمكن لاستعلام واحد أن يجمع بيانات من مصادر مختلفة. Kotlin، بدورها، هي لغة حديثة لـ JVM تجمع بين الإيجاز وأمان الأنواع. في هذا البرنامج التعليمي، سننشئ واجهة برمجة تطبيقات GraphQL كاملة الميزات باستخدام Kotlin ومكتبة graphql-kotlin-spring-server.
ستتعلم كيفية إعداد مشروع، تعريف مخطط، كتابة أدوات الحل، واختبار الواجهة البرمجية عبر GraphiQL. هل أنت مستعد؟ هيا بنا!
1. إعداد المشروع
1.1. إنشاء تطبيق Spring Boot
أولاً، لننشئ مشروعاً جديداً على Spring Initializr. اختر:
- نوع المشروع: Gradle (Kotlin)
- اللغة: Kotlin
- Spring Boot: 3.2+
- الاعتماديات: Spring Web, Spring Boot DevTools
بعد التنزيل، أضف اعتمادية GraphQL إلى ملف build.gradle.kts:
dependencies { implementation("com.expediagroup:graphql-kotlin-spring-server:7.0.0") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") testImplementation("org.springframework.boot:spring-boot-starter-test")}1.2. إعداد التطبيق
أنشئ ملف application.yml في المسار src/main/resources:
server: port: 8080
graphql: packages: - "com.example.graphql.demo"سيؤدي هذا إلى توجيه Spring Boot لفحص الحزمة com.example.graphql.demo بحثاً عن أدوات الحل والأنواع.
2. تعريف مخطط GraphQL
2.1. إنشاء نموذج البيانات
لننشئ نموذجاً بسيطاً لكتاب ومؤلف. في Kotlin، نستخدم فئات البيانات:
// src/main/kotlin/com/example/graphql/demo/model/Book.ktpackage com.example.graphql.demo.model
data class Book( val id: String, val title: String, val author: Author, val year: Int)
data class Author( val id: String, val name: String, val books: List<Book> = emptyList())2.2. تعريف المخطط عبر الكود (SDL)
بدلاً من كتابة ملف schema.graphqls، سنستخدم التعليقات التوضيحية @GraphQLDescription و@GraphQLIgnore. تقوم مكتبة graphql-kotlin تلقائياً بتوليد المخطط بناءً على الفئات. لكن للتوضيح، لننشئ ملف schema.graphqls في src/main/resources:
type Query { books: [Book!]! book(id: String!): Book authors: [Author!]!}
type Mutation { addBook(title: String!, authorId: String!, year: Int!): Book!}
type Book { id: String! title: String! author: Author! year: Int!}
type Author { id: String! name: String! books: [Book!]!}3. تنفيذ أدوات الحل
3.1. خدمة تخزين البيانات
للتبسيط، سنستخدم تخزيناً في الذاكرة:
// src/main/kotlin/com/example/graphql/demo/service/LibraryService.ktpackage com.example.graphql.demo.service
import com.example.graphql.demo.model.Authorimport com.example.graphql.demo.model.Bookimport org.springframework.stereotype.Serviceimport java.util.UUID
@Serviceclass LibraryService { private val authors = mutableListOf( Author(id = "1", name = "George Orwell"), Author(id = "2", name = "Ray Bradbury") )
private val books = mutableListOf( Book(id = "1", title = "1984", author = authors[0], year = 1949), Book(id = "2", title = "Fahrenheit 451", author = authors[1], year = 1953) )
fun getBooks(): List<Book> = books fun getBook(id: String): Book? = books.find { it.id == id } fun getAuthors(): List<Author> = authors fun getAuthor(id: String): Author? = authors.find { it.id == id }
fun addBook(title: String, authorId: String, year: Int): Book { val author = authors.find { it.id == authorId } ?: throw IllegalArgumentException("Author not found") val book = Book(id = UUID.randomUUID().toString(), title = title, author = author, year = year) books.add(book) return book }}3.2. أداة حل الاستعلامات
أنشئ أداة حل للاستعلامات:
// src/main/kotlin/com/example/graphql/demo/resolver/QueryResolver.ktpackage com.example.graphql.demo.resolver
import com.example.graphql.demo.model.Authorimport com.example.graphql.demo.model.Bookimport com.example.graphql.demo.service.LibraryServiceimport org.springframework.stereotype.Component
@Componentclass QueryResolver(private val libraryService: LibraryService) {
fun books(): List<Book> = libraryService.getBooks()
fun book(id: String): Book? = libraryService.getBook(id)
fun authors(): List<Author> = libraryService.getAuthors()}3.3. أداة حل الطفرات (Mutations)
أنشئ أداة حل للطفرات:
// src/main/kotlin/com/example/graphql/demo/resolver/MutationResolver.ktpackage com.example.graphql.demo.resolver
import com.example.graphql.demo.model.Bookimport com.example.graphql.demo.service.LibraryServiceimport org.springframework.stereotype.Component
@Componentclass MutationResolver(private val libraryService: LibraryService) {
fun addBook(title: String, authorId: String, year: Int): Book { return libraryService.addBook(title, authorId, year) }}4. اختبار الواجهة البرمجية
4.1. تشغيل التطبيق
قم بتشغيل التطبيق عبر الفئة الرئيسية أو باستخدام الأمر:
./gradlew bootRunبعد التشغيل، ستكون نقطة نهاية GraphQL متاحة على http://localhost:8080/graphql، وواجهة GraphiQL على http://localhost:8080/graphiql.
4.2. أمثلة على الاستعلامات
افتح GraphiQL ونفّذ الاستعلامات التالية:
الحصول على جميع الكتب:
query { books { id title author { name } year }}الحصول على كتاب بواسطة المعرف:
query { book(id: "1") { title author { name } }}إضافة كتاب جديد:
mutation { addBook(title: "Brave New World", authorId: "1", year: 1932) { id title author { name } }}الخلاصة
لقد قمنا بإنشاء واجهة برمجة تطبيقات GraphQL كاملة الوظائف باستخدام Kotlin وSpring Boot. في هذا البرنامج التعليمي، غطينا الخطوات الأساسية: إعداد المشروع، تعريف المخطط، تنفيذ أدوات الحل، والاختبار. توفر GraphQL إمكانيات قوية لاسترجاع البيانات بمرونة، وتجعل Kotlin الكود موجزاً وآمناً.
لمزيد من الدراسة، نوصي باستكشاف الاشتراكات (subscriptions)، معالجة الأخطاء، والتكامل مع قواعد البيانات. حظاً موفقاً في تطويرك!