ทำความเข้าใจข้อผิดพลาดของ API

คู่มือนี้อธิบายวิธีที่ Data Manager API จัดการและสื่อสารข้อผิดพลาด การทำความเข้าใจโครงสร้างและความหมายของข้อผิดพลาดของ API เป็นสิ่งสำคัญในการสร้าง แอปพลิเคชันที่มีประสิทธิภาพซึ่งสามารถจัดการปัญหาได้อย่างราบรื่น ตั้งแต่ข้อมูลที่ไม่ถูกต้องไปจนถึง บริการที่ไม่พร้อมใช้งานชั่วคราว

Data Manager API เป็นไปตามรูปแบบข้อผิดพลาดของ Google API มาตรฐาน ซึ่งอิงตามรหัสสถานะ gRPC การตอบกลับ API แต่ละรายการที่ทำให้เกิดข้อผิดพลาด จะมีออบเจ็กต์ Status ที่มีข้อมูลต่อไปนี้

  • รหัสข้อผิดพลาดที่เป็นตัวเลข
  • ข้อความแสดงข้อผิดพลาด
  • รายละเอียดข้อผิดพลาดเพิ่มเติม (ไม่บังคับ)

รหัสข้อผิดพลาด Canonical

API ของ Data Manager ใช้ชุดรหัสข้อผิดพลาด Canonical ที่กำหนดโดย gRPC และ HTTP รหัสเหล่านี้จะระบุประเภทข้อผิดพลาดในระดับสูง คุณควรตรวจสอบโค้ดนี้ก่อนเสมอเพื่อทำความเข้าใจลักษณะพื้นฐานของปัญหา

ดูรายละเอียดเพิ่มเติมเกี่ยวกับรหัสเหล่านี้ได้ที่คู่มือการออกแบบ API - รหัสข้อผิดพลาด

จัดการข้อผิดพลาด

ทำตามขั้นตอนต่อไปนี้เมื่อคำขอไม่สำเร็จ

  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, QuotaFailure และ RetryInfo ยังมีประโยชน์สำหรับรหัสข้อผิดพลาดที่เฉพาะเจาะจง ดังนี้

    • หากรหัสสถานะเป็น INVALID_ARGUMENT ให้ตรวจสอบเพย์โหลด BadRequest เพื่อดูข้อมูลเกี่ยวกับฟิลด์ที่ทำให้เกิดข้อผิดพลาด
    • หากรหัสสถานะคือ RESOURCE_EXHAUSTED ให้ตรวจสอบเพย์โหลด QuotaFailure และ RetryInfo เพื่อดูข้อมูลโควต้า และคำแนะนำเกี่ยวกับการหน่วงเวลาการลองใหม่

เพย์โหลดรายละเอียดมาตรฐาน

Payload รายละเอียดมาตรฐานที่พบบ่อยที่สุดสำหรับ 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 ที่ไม่ใช่ตัวเลข ค่า field destinations[0].login_account.account_id แสดง 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 รายการจะแสดงข้อผิดพลาด 2 รายการ ดังนี้

  1. event แรกมีค่าที่ไม่ได้เข้ารหัสฐานสิบหกในตัวระบุผู้ใช้ที่ 2 ของเหตุการณ์

  2. event รายการที่ 2 มีค่าที่ไม่ได้เข้ารหัสฐาน 16 ในตัวระบุผู้ใช้ที่ 3 ของเหตุการณ์

{
  "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"
          }
        ]
      }
    ]
  }
}

QuotaFailure และ RetryInfo

ตรวจสอบเพย์โหลด QuotaFailure และ RetryInfo เมื่อคำขอไม่สำเร็จ โดยมี RESOURCE_EXHAUSTED (รหัสสถานะ HTTP 429)

QuotaFailure ข้อความระบุว่าทรัพยากรหมด (เช่น คุณใช้โควต้าเกิน) หรือระบบทำงานหนักเกินไป ตรวจสอบ รายการ violations เพื่อดูว่าโควต้าใดที่เกิน

ข้อผิดพลาดอาจมีRetryInfoข้อความretry_delayที่ระบุว่าควร retry_delayลองส่งคำขออีกครั้ง

RequestInfo

ตรวจสอบเพย์โหลด RequestInfo ทุกครั้งที่คำขอไม่สำเร็จ RequestInfo มี request_id ที่ระบุคำขอ API ของคุณอย่างไม่ซ้ำกัน

{
  "@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.developers.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.developers.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.developers.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.developers.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 developers console API activation",
            "url": "https://console.developers.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.QuotaFailure)
        {
            Google.Rpc.QuotaFailure quotaFailure = (Google.Rpc.QuotaFailure)detail;
            foreach (
                Google.Rpc.QuotaFailure.Types.Violation violation in quotaFailure.Violations
            )
            {
                // Access attributes such as violation.Subject and violation.QuotaId
            }
        }
        else
        {
            // ...
        }
    }
}

Java

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.QuotaFailureException quotaFailureException) {
  // Gets the standard QuotaFailure payload from the exception.
  QuotaFailure quotaFailure = quotaFailureException.getErrorDetails().getQuotaFailure();
  for (int i = 0; i < quotaFailure.getViolationsCount(); i++) {
    QuotaFailure.Violation violation = quotaFailure.getViolations(i);
    // Access attributes such as violation.getSubject() and violation.getQuotaId()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = quotaFailureException.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.
  ...
}

แนวทางปฏิบัติแนะนำสำหรับการจัดการข้อผิดพลาด

หากต้องการสร้างแอปพลิเคชันที่ยืดหยุ่น ให้ใช้แนวทางปฏิบัติแนะนำต่อไปนี้

ตรวจสอบรายละเอียดข้อผิดพลาด
มองหาเพย์โหลดรายละเอียดมาตรฐานอย่างใดอย่างหนึ่งเสมอ เช่น BadRequest เพย์โหลดรายละเอียดมาตรฐานแต่ละรายการมีข้อมูลที่จะช่วยให้คุณเข้าใจสาเหตุของข้อผิดพลาด
แยกความแตกต่างระหว่างข้อผิดพลาดของไคลเอ็นต์กับข้อผิดพลาดของเซิร์ฟเวอร์

พิจารณาว่าข้อผิดพลาดเกิดจากปัญหาในการติดตั้งใช้งาน (ไคลเอ็นต์) หรือปัญหาเกี่ยวกับ API (เซิร์ฟเวอร์)

  • ข้อผิดพลาดของไคลเอ็นต์: รหัสเช่น INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED ข้อผิดพลาดเหล่านี้ ต้องมีการเปลี่ยนแปลงคำขอหรือสถานะ/ข้อมูลเข้าสู่ระบบของแอปพลิเคชัน อย่าลองส่งคำขออีกครั้งโดยไม่แก้ไขปัญหา
  • ข้อผิดพลาดของเซิร์ฟเวอร์: รหัส เช่น UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED, UNKNOWN ซึ่งบ่งบอกว่าบริการ API อาจมีปัญหาชั่วคราว
ใช้กลยุทธ์การลองใหม่

พิจารณาว่าข้อผิดพลาดลองใหม่ได้หรือไม่ และใช้กลยุทธ์การลองใหม่

  • ลองอีกครั้งเฉพาะข้อผิดพลาดเกี่ยวกับเซิร์ฟเวอร์ชั่วคราว เช่น UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN และ ABORTED
  • ใช้อัลกอริทึม Exponential Backoff เพื่อรอระยะเวลาที่เพิ่มขึ้น ระหว่างการลองใหม่ ซึ่งจะช่วยไม่ให้บริการที่ทำงานหนักอยู่แล้ว ต้องรับภาระหนักขึ้นไปอีก เช่น รอ 1 วินาที แล้วรอ 2 วินาที จากนั้นรอ 4 วินาที และรอต่อไปจนกว่าจะถึงจำนวนการลองใหม่สูงสุดหรือเวลารอทั้งหมด
  • เพิ่ม "Jitter" จำนวนเล็กน้อยแบบสุ่มลงในระยะเวลาหน่วงของการหยุดชั่วคราวเพื่อป้องกันปัญหา "Thundering Herd" ที่ไคลเอ็นต์จำนวนมากพยายามอีกครั้งพร้อมกัน
บันทึกอย่างละเอียด

บันทึกการตอบกลับข้อผิดพลาดทั้งหมด รวมถึงเพย์โหลดรายละเอียดมาตรฐานทั้งหมด โดยเฉพาะรหัสคำขอ ข้อมูลนี้มีความสำคัญต่อการแก้ไขข้อบกพร่องและการรายงานปัญหาไปยังทีมสนับสนุนของ Google หากจำเป็น

แสดงความคิดเห็นของผู้ใช้

ระบุความคิดเห็นที่ชัดเจนและเป็นประโยชน์แก่ผู้ใช้แอปพลิเคชันของคุณโดยอิงตามรหัสและข้อความในเพย์โหลดรายละเอียดมาตรฐาน เช่น แทนที่จะพูดว่า "เกิดข้อผิดพลาด" คุณสามารถพูดว่า "ไม่มีรหัสธุรกรรม" หรือ "ไม่พบรหัสบัญชี ของปลายทาง"

การทำตามหลักเกณฑ์เหล่านี้จะช่วยให้คุณวินิจฉัยและจัดการข้อผิดพลาดที่ API ของ Data Manager แสดงผลได้อย่างมีประสิทธิภาพ ซึ่งจะช่วยให้แอปพลิเคชันมีความเสถียรและใช้งานง่ายมากขึ้น