Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

فك التغليف باستخدام `errors.As`

جزء من قسم Logic & Flow في رحلة GO على Coddy — الدرس 41 من 68.

بينما تساعدك errors.Is على تحديد قيم أخطاء محددة في سلسلة (chain)، ستحتاج أحياناً إلى الوصول إلى الحقول والبيانات الفعلية لنوع خطأ مخصص. توفر الدالة errors.As هذه الإمكانية من خلال العثور على أول خطأ في سلسلة يطابق نوعاً معيناً واستخراجه للفحص.

تأخذ الدالة errors.As معاملين: الخطأ المراد فحصه ومؤشرًا لمتغير من نوع الخطأ المستهدف. إذا وجدت نوع خطأ مطابقًا في السلسلة، فإنها تقوم بتعيين المتغير الخاص بك إلى ذلك الخطأ وتعيد القيمة true:

var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
    fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}

هذا قوي بشكل خاص عند العمل مع أنواع الأخطاء المخصصة التي تحتوي على سياق إضافي. على عكس errors.Is الذي يتحقق فقط من التساوي، يقوم errors.As باستخراج مثيل الخطأ الفعلي، مما يسمح لك بالوصول إلى حقوله وطرقه. وهذا يجعل معالجة الأخطاء أكثر تطوراً وغنى بالمعلومات في التطبيقات المعقدة.

quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

challenge icon

التحدي

سهل

قم ببناء نظام لمعالجة أخطاء واجهة برمجة التطبيقات (API) يستخدم errors.As لاستخراج وفحص أنواع الأخطاء المخصصة من سلاسل الأخطاء المغلفة (wrapped error chains). يوضح هذا التحدي كيفية استخدام errors.As للوصول إلى الحقول والبيانات الخاصة بأنواع الأخطاء المخصصة، حتى عندما يتم تغليفها بسياق إضافي.

ستتلقى مدخلين:

  • سلسلة نصية تحتوي على تفاصيل طلب API بتنسيق "endpoint,method,error_code,error_field" (على سبيل المثال، "/users,POST,400,email")
  • سلسلة نصية تحتوي على سياق النظام بتنسيق "service_name,request_id" (على سبيل المثال، "UserAPI,req_12345")

مهمتك هي:

  1. إنشاء نوع خطأ مخصص يسمى APIError كبنية (struct) تحتوي على ثلاثة حقول:
    • Code (int) - رمز حالة HTTP
    • Field (string) - الحقل الذي تسبب في الخطأ
    • Message (string) - وصف للخطأ
  2. تنفيذ تابع Error() string لـ APIError والذي يعيد: "API error [code]: [message] (field: [field])"
  3. تحليل المدخل الأول عن طريق التقسيم عند الفواصل للحصول على endpoint و method و error code و error field
  4. تحليل المدخل الثاني عن طريق التقسيم عند الفواصل للحصول على service name و request ID
  5. تحويل سلسلة رمز الخطأ النصية إلى عدد صحيح (integer)
  6. إنشاء مثيل من APIError بناءً على رمز الخطأ:
    • إذا كان الرمز 400: الرسالة "invalid request data"
    • إذا كان الرمز 401: الرسالة "authentication required"
    • إذا كان الرمز 404: الرسالة "resource not found"
    • إذا كان الرمز 500: الرسالة "internal server error"
    • لأي رمز آخر: الرسالة "unknown error"
  7. إنشاء خطأ مغلف على مستوى الـ endpoint باستخدام fmt.Errorf مع %w: "[method] [endpoint] failed: %w"
  8. إنشاء خطأ مغلف على مستوى الخدمة (service-level): "[service_name] request [request_id] failed: %w"
  9. استخدام errors.As لاستخراج APIError من سلسلة الأخطاء المغلفة وعرض نتيجة الاستخراج:
    • إذا نجح الاستخراج: "API error extracted successfully"
    • إذا فشل الاستخراج: "Failed to extract API error"
  10. إذا نجح الاستخراج، قم بعرض تفاصيل الخطأ المستخرج:
    • "Extracted Error Details:"
    • "Code: [code]"
    • "Field: [field]"
    • "Message: [message]"
    • "Full error: [full_error_message_from_Error_method]"
  11. عرض سلسلة الأخطاء الكاملة:
    • "Error Chain:"
    • "Original: [original_api_error_message]"
    • "Endpoint level: [endpoint_level_error_message]"
    • "Service level: [service_level_error_message]"
  12. عرض تحليل نهائي:
    • "Error Analysis:"
    • "Service: [service_name]"
    • "Request ID: [request_id]"
    • "Endpoint: [method] [endpoint]"
    • "HTTP Status: [code]"
    • "Problem Field: [field]"
    • "Error Category: [error_category]" حيث يكون error_category هو "Client Error" للأكواد 400-499، أو "Server Error" للأكواد 500-599، أو "Unknown" للأكواد الأخرى

استخدم حزمة strings لتقسيم سلاسل المدخلات عند الفواصل، وحزمة strconv لتحويل سلسلة رمز الخطأ إلى عدد صحيح، وحزمة errors من أجل errors.As، وحزمة fmt لتغليف الأخطاء. يوضح هذا التحدي كيف تتيح لك errors.As الوصول إلى الحقول والأساليب المحددة لأنواع الأخطاء المخصصة داخل سلاسل الأخطاء المغلفة، مما يتيح معالجة وتحليل الأخطاء بشكل متطور.

ورقة مرجعية

تقوم الدالة errors.As باستخراج أنواع أخطاء محددة من سلاسل الأخطاء، مما يسمح بالوصول إلى حقول وطرق الأخطاء المخصصة.

تأخذ errors.As معاملين: الخطأ المراد فحصه ومؤشر (pointer) لمتغير من نوع الخطأ المستهدف:

var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
    fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}

على عكس errors.Is التي تتحقق فقط من التساوي، تقوم errors.As باستخراج مثيل الخطأ الفعلي، مما يتيح الوصول إلى حقوله وطرقه لمعالجة أخطاء أكثر تطوراً.

جرّب بنفسك

package main

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// قراءة المدخلات
	var apiDetails string
	var systemContext string
	fmt.Scanln(&apiDetails)
	fmt.Scanln(&systemContext)
	
	// تحليل المدخلات
	apiParts := strings.Split(apiDetails, ",")
	endpoint := apiParts[0]
	method := apiParts[1]
	errorCodeStr := apiParts[2]
	errorField := apiParts[3]
	
	contextParts := strings.Split(systemContext, ",")
	serviceName := contextParts[0]
	requestID := contextParts[1]
	
	// تحويل رمز الخطأ إلى عدد صحيح
	errorCode, _ := strconv.Atoi(errorCodeStr)
	
	// TODO: اكتب الكود الخاص بك أدناه
	// 1. قم بإنشاء هيكل APIError مع حقول Code و Field و Message
	// 2. قم بتنفيذ طريقة Error() لهيكل APIError
	// 3. قم بإنشاء مثيل APIError بناءً على رمز الخطأ
	// 4. قم بإنشاء أخطاء مغلفة (على مستوى نقطة النهاية وعلى مستوى الخدمة)
	// 5. استخدم errors.As لاستخراج APIError من سلسلة الأخطاء المغلفة
	// 6. عرض نتيجة الاستخراج وتفاصيل الخطأ
	// 7. عرض سلسلة الأخطاء والتحليل النهائي
	
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Logic & Flow