مقدمة: لماذا GraphQL و Go هما الثنائي المثالي؟
تتطلب تطوير الويب الحديث واجهات برمجة تطبيقات مرنة وعالية الأداء. REST API، على الرغم من شعبيته، غالباً ما يعاني من زيادة تحميل البيانات (over-fetching) أو نقصها (under-fetching). GraphQL يحل هذه المشكلة من خلال السماح للعميل بطلب ما يحتاجه بالضبط. أما Go (Golang) بسرعته وبساطته ودعمه المدمج للتزامن، فهو لغة مثالية لبناء خوادم GraphQL.
في هذا البرنامج التعليمي، سنقوم خطوة بخطوة ببناء GraphQL API كامل بلغة Go. ستتعلم كيفية إعداد الخادم، تعريف المخطط، كتابة المحللين (resolvers)، وتنفيذ الاستعلامات (queries) والتحويرات (mutations). في نهاية المقال، سيكون لديك API جاهز للتكامل مع أي عميل.
الخطوة 1: إعداد المشروع وتثبيت التبعيات
لنبدأ بإنشاء وحدة Go جديدة وتثبيت المكتبات اللازمة. سنستخدم مكتبتين شهيرتين لـ GraphQL: graphql-go و graphql-go-handler.
1.1. تهيئة الوحدة
go mod init graphql-tutorial1.2. تثبيت المكتبات
go get github.com/graphql-go/graphqlgo get github.com/graphql-go/handlerتوفر هذه المكتبات جميع الأدوات اللازمة للعمل مع المخططات والأنواع والمحللين.
الخطوة 2: إنشاء مخطط GraphQL أساسي
المخطط هو قلب GraphQL API. يحدد البيانات التي يمكن الحصول عليها والإجراءات التي يمكن تنفيذها. سنبدأ بنموذج بسيط "مستخدم".
2.1. تعريف نوع User
import "github.com/graphql-go/graphql"
var userType = graphql.NewObject(graphql.ObjectConfig{ Name: "User", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.Int, }, "name": &graphql.Field{ Type: graphql.String, }, "email": &graphql.Field{ Type: graphql.String, }, },})2.2. إنشاء استعلام جذري
var rootQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "RootQuery", Fields: graphql.Fields{ "user": &graphql.Field{ Type: userType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { id, _ := p.Args["id"].(int) // هنا سيكون منطق الحصول على المستخدم من قاعدة البيانات return getUserByID(id), nil }, }, },})2.3. الدمج في مخطط
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: rootQuery,})الخطوة 3: تنفيذ المحللين والخادم
الآن بعد أن أصبح المخطط جاهزاً، نحتاج إلى كتابة المحللين (resolvers) - وهي الدوال التي تعيد البيانات فعلياً. للتبسيط، سنستخدم تخزيناً في الذاكرة (in-memory).
3.1. التخزين في الذاكرة
type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"`}
var users = []User{ {ID: 1, Name: "إيفان بيتروف", Email: "ivan@example.com"}, {ID: 2, Name: "ماريا سيدوروفا", Email: "maria@example.com"},}
func getUserByID(id int) *User { for _, u := range users { if u.ID == id { return &u } } return nil}3.2. تشغيل خادم HTTP
package main
import ( "fmt" "log" "net/http"
"github.com/graphql-go/handler")
func main() { h := handler.New(&handler.Config{ Schema: &schema, Pretty: true, GraphiQL: true, // تفعيل IDE المدمج })
http.Handle("/graphql", h) fmt.Println("الخادم قيد التشغيل على")