مقدمة: لماذا Go مثالي لـ REST API؟
Go (أو Golang) هي لغة برمجة حديثة ومترجمة، تم إنشاؤها في Google. تجمع بين أداء C++ وبساطة Python، مما يجعلها خيارًا مثاليًا لبناء خدمات الويب عالية التحميل و REST API. على عكس العديد من اللغات الأخرى، تتمتع Go بدعم مدمج لخادم HTTP، وتعدد المهام، وسرعة الترجمة.
في هذا الدليل، سنقوم خطوة بخطوة ببناء REST API كامل لإدارة قائمة المهام (Todo List). ستتعلم:
- إعداد خادم HTTP بلغة Go
- العمل مع طلبات واستجابات JSON
- تنفيذ عمليات CRUD (إنشاء، قراءة، تحديث، حذف)
- اختبار API باستخدام curl أو Postman
ستستغرق العملية بأكملها أقل من 30 دقيقة. هيا بنا!
1. تثبيت وإعداد المشروع
قبل كتابة الكود، تأكد من تثبيت Go. يمكنك التحقق من ذلك باستخدام الأمر:
go versionإذا لم يكن Go مثبتًا، قم بتنزيل أحدث إصدار من الموقع الرسمي.
أنشئ دليلاً جديدًا للمشروع وقم بتهيئة الوحدة النمطية:
mkdir go-rest-apicd go-rest-apigo mod init go-rest-apiالآن، أنشئ ملف main.go — سيكون فيه كل الكود الخاص بنا. لسهولة التعامل مع المسارات، سنستخدم المكتبة القياسية net/http، المضمنة بالفعل في Go. لا حاجة لأي تبعيات خارجية — هذه إحدى المزايا الرئيسية للغة.
2. تعريف هيكل البيانات والتخزين
لنبدأ بوصف نموذج البيانات. للتبسيط، سنخزن المهام في الذاكرة (في شريحة)، وليس في قاعدة بيانات. سننشئ هيكل Task وعداد ID عام:
package main
import ( "encoding/json" "log" "net/http" "strconv" "strings" "sync")
// Task تمثل مهمةtype Task struct { ID int `json:"id"` Title string `json:"title"` Done bool `json:"done"`}
// مخزن المهام (في الذاكرة)var ( tasks []Task nextID int = 1 mu sync.Mutex)لاحظ sync.Mutex — إنه ضروري للوصول الآمن إلى البيانات في بيئة متعددة الخيوط، حيث يمكن لخادم Go معالجة الطلبات بشكل متوازٍ.
3. تنفيذ عمليات CRUD
الآن سنكتب المعالجات الأساسية لكل طريقة HTTP. سنستخدم نمط التوجيه عبر URL:
GET /tasks— الحصول على جميع المهامPOST /tasks— إنشاء مهمة جديدةGET /tasks/{id}— الحصول على مهمة حسب IDPUT /tasks/{id}— تحديث مهمةDELETE /tasks/{id}— حذف مهمة
3.1. الحصول على جميع المهام (GET /tasks)
func getTasks(w http.ResponseWriter, r *http.Request) { mu.Lock() defer mu.Unlock()
w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(tasks)}3.2. إنشاء مهمة (POST /tasks)
func createTask(w http.ResponseWriter, r *http.Request) { var newTask Task if err := json.NewDecoder(r.Body).Decode(&newTask); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return }
mu.Lock() newTask.ID = nextID nextID++ tasks = append(tasks, newTask) mu.Unlock()
w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(newTask)}3.3. الحصول على مهمة وتحديثها وحذفها حسب ID
لهذه العمليات، نحتاج إلى استخراج ID من URL. لا تحتوي المكتبة القياسية في Go على محلل مسارات مدمج، لذا سنكتب أداة بسيطة: