التعرّف على أخطاء واجهة برمجة التطبيقات

يشرح هذا الدليل كيفية تعامل واجهة برمجة التطبيقات Data Manager API مع الأخطاء والإبلاغ عنها. إنّ فهم بنية أخطاء واجهة برمجة التطبيقات ومعناها أمر بالغ الأهمية لإنشاء تطبيقات قوية يمكنها معالجة المشاكل بشكل سليم، بدءًا من الإدخال غير الصالح وصولاً إلى عدم توفّر الخدمة مؤقتًا.

تتّبع واجهة برمجة التطبيقات Data Manager API نموذج الخطأ العادي في Google API، الذي يستند إلى رموز حالة gRPC. يتضمّن كل ردّ من واجهة برمجة التطبيقات ينتج عنه خطأ كائن Status يتضمّن ما يلي:

  • رمز خطأ رقمي
  • رسالة خطأ
  • تفاصيل إضافية اختيارية عن الخطأ

رموز الخطأ الأساسية

تستخدِم واجهة برمجة التطبيقات Data Manager API مجموعة من رموز الخطأ الأساسية التي تحدّدها gRPC وHTTP. تقدّم هذه الرموز إشارة عالية المستوى إلى نوع الخطأ. ننصحك بالتحقّق من هذا الرمز أولاً لفهم الطبيعة الأساسية للمشكلة.

لمزيد من التفاصيل حول هذه الرموز، يُرجى الاطّلاع على دليل تصميم واجهة برمجة التطبيقات - رموز الخطأ.

معالجة الأخطاء

اتّبِع الخطوات التالية عندما يتعذّر تنفيذ طلب:

  1. تحقَّق من رمز الخطأ للعثور على نوع الخطأ.

    • إذا كنت تستخدِم gRPC، يكون رمز الخطأ في الحقل code من Status. إذا كنتَ تستخدِم مكتبة عميل، قد تطرح نوعًا معيّنًا من الاستثناءات يتطابق مع رمز الخطأ. على سبيل المثال، تعرض مكتبة العميل للغة Java استثناءً من النوع com.google.api.gax.rpc.InvalidArgumentException إذا كان رمز الخطأ هو INVALID_ARGUMENT.
    • إذا كنت تستخدِم REST، يكون رمز الخطأ في ردّ الخطأ ضِمن error.status، وتكون حالة HTTP المقابلة ضِمن error.code.
  2. تحقَّق من حمولة التفاصيل العادية لرمز الخطأ. حمولات التفاصيل العادية هي مجموعة من الرسائل للأخطاء من Google APIs. تقدّم لك تفاصيل الخطأ بطريقة منظَّمة ومتّسقة. قد يتضمّن كل خطأ من واجهة برمجة التطبيقات Data Manager API رسائل حمولة تفاصيل عادية متعدّدة. تحتوي مكتبات عميل واجهة برمجة التطبيقات Data Manager API على طرق مساعِدة للحصول على حمولات التفاصيل العادية من الخطأ.

    بغض النظر عن رمز الخطأ، ننصحك بالتحقّق من حمولات ErrorInfo وRequestInfo وHelp و وLocalizedMessage وتسجيلها.

    • تحتوي ErrorInfo على معلومات قد لا تكون متوفّرة في حمولات أخرى.
    • RequestInfo يحتوي على رقم تعريف الطلب، وهو مفيد إذا كنت بحاجة إلى التواصل مع فريق الدعم.
    • تحتوي Help وLocalizedMessage على روابط وتفاصيل أخرى لمساعدتك في معالجة الخطأ.

    بالإضافة إلى ذلك، تكون حمولة BadRequest مفيدة للأخطاء INVALID_ARGUMENT لأنّها تقدّم معلومات عن الحقول التي تسبّبت في الخطأ.

حمولة التفاصيل العادية

في ما يلي حمولات التفاصيل العادية الأكثر شيوعًا لواجهة برمجة التطبيقات Data Manager API:

BadRequest

تحقَّق من حمولة BadRequest عندما يتعذّر تنفيذ طلب بسبب INVALID_ARGUMENT (رمز حالة HTTP 400).

توضّح رسالة BadRequest أنّ الطلب يحتوي على حقول تتضمّن قيمًا غير صالحة أو لا يتضمّن قيمة لحقل مطلوب. تحقَّق من قائمة field_violations في BadRequest للعثور على الحقول التي تحتوي على أخطاء. يحتوي كل إدخال field_violations على معلومات لمساعدتك في إصلاح الخطأ:

field

موقع الحقل في الطلب، باستخدام بنية مسار camel case.

إذا كان المسار يشير إلى عنصر في قائمة (حقل repeated)، يظهر فهرسه بين قوسَين مربّعَين ([...]) بعد اسم القائمة.

على سبيل المثال، destinations[0].operating_account.account_id هو الـ account_id في الـ operating_account للعنصر الأول في قائمة الـ destinations.

description

شرح لسبب تسبُّب القيمة في حدوث خطأ

reason

تعداد ErrorReason، مثل INVALID_HEX_ENCODING أو INVALID_CURRENCY_CODE.

أمثلة على BadRequest

في ما يلي نموذج ردّ لخطأ INVALID_ARGUMENT مع رسالة BadRequest. توضّح field_violations أنّ الخطأ هو accountId ليس رقمًا. توضّح القيمة destinations[0].login_account.account_id للحقل field أنّ accountId الذي يتضمّن انتهاكًا للحقل موجود في login_account للعنصر الأول في قائمة destinations.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "destinations[0].login_account.account_id",
            "description": "String is not a valid number.",
            "reason": "INVALID_NUMBER_FORMAT"
          }
        ]
      }
    ]
  }
}

في ما يلي نموذج ردّ آخر من خطأ INVALID_ARGUMENT مع رسالة BadRequest. في هذه الحالة، تعرض قائمة field_violations خطأَين:

  1. يحتوي event الأول على قيمة غير مشفّرة بتنسيق سداسي عشري في معرّف المستخدِم الثاني للحدث .

  2. يحتوي event الثاني على قيمة غير مشفّرة بتنسيق سداسي عشري في معرّف المستخدِم الثالث للحدث .

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "events.events[0].user_data.user_identifiers[1]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          },
          {
            "field": "events.events[1].user_data.user_identifiers[2]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          }
        ]
      }
    ]
  }
}

RequestInfo

تحقَّق من حمولة RequestInfo في كل مرة يتعذّر فيها تنفيذ طلب. تحتوي RequestInfo على request_id الذي يحدّد طلب بيانات من واجهة برمجة التطبيقات بشكل فريد.

{
  "@type": "type.googleapis.com/google.rpc.RequestInfo",
  "requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}

عند تسجيل الأخطاء أو التواصل مع فريق الدعم، احرص على تضمين رقم تعريف الطلب للمساعدة في تشخيص المشاكل.

ErrorInfo

تحقَّق من رسالة ErrorInfo لاسترداد معلومات إضافية قد لا يتم تسجيلها في حمولات التفاصيل العادية الأخرى. تحتوي حمولة ErrorInfo على خريطة metadata تتضمّن معلومات عن الخطأ.

على سبيل المثال، إليك ErrorInfo لخطأ PERMISSION_DENIED ناتج عن استخدام بيانات اعتماد لمشروع على Google Cloud لم يتم تفعيل واجهة برمجة التطبيقات Data Manager API فيه. تقدّم ErrorInfo معلومات إضافية عن الخطأ، مثل:

  • المشروع المرتبط بالطلب، ضِمن metadata.consumer
  • اسم الخدمة، ضِمن metadata.serviceTitle
  • عنوان URL الذي يمكن تفعيل الخدمة فيه، ضِمن metadata.activationUrl
{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "SERVICE_DISABLED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "service": "datamanager.googleapis.com",
          "containerInfo": "PROJECT_NUMBER",
          "serviceTitle": "Data Manager API",
          "activationUrl": "https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

Help وLocalizedMessage

تحقَّق من حمولتَي Help وLocalizedMessage للحصول على روابط تؤدي إلى المستندات ورسائل الخطأ المترجَمة التي تساعدك في فهم الخطأ وإصلاحه.

على سبيل المثال، إليك Help وLocalizedMessage لخطأ PERMISSION_DENIED ناتج عن استخدام بيانات اعتماد لمشروع على Google Cloud لم يتم تفعيل واجهة برمجة التطبيقات Data Manager API فيه. تعرض حمولة Help عنوان URL الذي يمكن تفعيل الخدمة فيه، وتحتوي LocalizedMessage على وصف للخطأ.

{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
        "locale": "en-US",
        "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
      },
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google API Console API activation",
            "url": "https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
          }
        ]
      },
      ...
    ]
  }
}

الوصول إلى تفاصيل الخطأ

إذا كنت تستخدِم إحدى مكتبات العميل، استخدِم الطرق المساعِدة للحصول على حمولات التفاصيل العادية.

NET.

try {
    // Send API request
}
catch (Grpc.Core.RpcException rpcException)
{
    Console.WriteLine($"Exception encountered: {rpcException.Message}");
    var statusDetails =
        Google.Api.Gax.Grpc.RpcExceptionExtensions.GetAllStatusDetails(
            rpcException
        );
    foreach (var detail in statusDetails)
    {
        if (detail is Google.Rpc.BadRequest)
        {
            Google.Rpc.BadRequest badRequest = (Google.Rpc.BadRequest)detail;
            foreach (
                BadRequest.Types.FieldViolation? fieldViolation in badRequest.FieldViolations
            )
            {
                // Access attributes such as fieldViolation!.Reason and fieldViolation!.Field
            }
        }
        else if (detail is Google.Rpc.RequestInfo)
        {
            Google.Rpc.RequestInfo requestInfo = (Google.Rpc.RequestInfo)detail;
            string requestId = requestInfo.RequestId;
            // Log the requestId...
        }
        else if (detail is Google.Rpc.ErrorInfo)
        {
            Google.Rpc.ErrorInfo errorInfo = (Google.Rpc.ErrorInfo)detail;
            // Log the errorInfo.Reason and errorInfo.Metadata...

            // Log the details in the 'Metadata' map...
            foreach (
                KeyValuePair<String, String> metadataEntry in errorInfo.Metadata
            )
            {
                // Log the metadataEntry.Key and metadataEntry.Value...
            }
        }
        else
        {
            // ...
        }
    }
}

جافا

try {
  // Send API request
} catch (com.google.api.gax.rpc.InvalidArgumentException invalidArgumentException) {
  // Gets the standard BadRequest payload from the exception.
  BadRequest badRequest = invalidArgumentException.getErrorDetails().getBadRequest();
  for (int i = 0; i < badRequest.getFieldViolationsCount(); i++) {
    FieldViolation fieldViolation = badRequest.getFieldViolations(i);
    // Access attributes such as fieldViolation.getField() and fieldViolation.getReason()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.

  // Gets the standard ErrorInfo payload from the exception.
  ErrorInfo errorInfo = apiException.getErrorDetails().getErrorInfo();
  // Log the 'reason' and 'domain'...

  // Log the details in the 'metadata' map...
  for (Entry<String, String> metadataEntry : errorInfo.getMetadataMap().entrySet()) {
    // Log the metadataEntry key and value...
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
  ...
}

أفضل الممارسات لمعالجة الأخطاء

لإنشاء تطبيقات مرنة، اتّبِع أفضل الممارسات التالية.

فحص تفاصيل الخطأ
ابحث دائمًا عن إحدى حمولات التفاصيل العادية، مثل BadRequest. تحتوي كل حمولة تفاصيل عادية على معلومات لمساعدتك في فهم سبب الخطأ.
التمييز بين أخطاء العميل وأخطاء الخادم

حدِّد ما إذا كان الخطأ ناتجًا عن مشكلة في عملية التنفيذ (العميل) أو مشكلة في واجهة برمجة التطبيقات (الخادم).

  • أخطاء العميل: رموز مثل INVALID_ARGUMENT وNOT_FOUND وPERMISSION_DENIED وFAILED_PRECONDITION وUNAUTHENTICATED تتطلّب هذه الرموز إجراء تغييرات على الطلب أو حالة تطبيقك أو بيانات اعتماده. لا تعِد محاولة إرسال الطلب بدون معالجة المشكلة.
  • أخطاء الخادم: رموز مثل UNAVAILABLE وINTERNAL وDEADLINE_EXCEEDED وUNKNOWN تشير هذه الرموز إلى مشكلة مؤقتة في خدمة واجهة برمجة التطبيقات.
تنفيذ استراتيجية إعادة المحاولة

حدِّد ما إذا كان يمكن إعادة محاولة تنفيذ الطلب، واستخدِم استراتيجية إعادة المحاولة.

  • أعِد المحاولة فقط لأخطاء الخادم المؤقتة، مثل UNAVAILABLE وDEADLINE_EXCEEDED وINTERNAL وUNKNOWN وABORTED.
  • استخدِم خوارزمية الرقود الأسي لانتظار فترات متزايدة بين عمليات إعادة المحاولة. يساعد ذلك في تجنُّب إرهاق خدمة مضغوطة أصلاً. على سبيل المثال، انتظِر ثانية واحدة، ثم ثانيتَين، ثم 4 ثوانٍ، واستمرّ في ذلك حتى الوصول إلى الحد الأقصى لعدد عمليات إعادة المحاولة أو إجمالي وقت الانتظار.
  • أضِف مقدارًا صغيرًا عشوائيًا من "التذبذب" إلى فترات الرقود لتجنُّب مشكلة "القطيع الصاخب" حيث يعيد العديد من العملاء المحاولة في الوقت نفسه.
التسجيل بدقة

سجِّل ردّ الخطأ الكامل، بما في ذلك جميع حمولات التفاصيل العادية، وخاصةً رقم تعريف الطلب. هذه المعلومات ضرورية لتحديد المشاكل وحلّها وإبلاغ فريق دعم Google بها إذا لزم الأمر.

تقديم ملاحظات للمستخدمين

استنادًا إلى الرموز والرسائل في حمولات التفاصيل العادية، قدِّم ملاحظات واضحة ومفيدة لمستخدمي تطبيقك. على سبيل المثال، بدلاً من مجرد "حدث خطأ"، يمكنك كتابة "رقم تعريف المعاملة غير متوفّر" أو "لم يتم العثور على رقم تعريف حساب الوجهة".

باتّباع هذه الإرشادات، يمكنك تشخيص الأخطاء التي تعرضها واجهة برمجة التطبيقات Data Manager API ومعالجتها بفعالية، ما يؤدي إلى إنشاء تطبيقات أكثر استقرارًا وسهولة في الاستخدام.