Memahami error API

Panduan ini menjelaskan cara Data Manager API menangani dan mengomunikasikan error. Memahami struktur dan arti error API sangat penting untuk membangun aplikasi yang tangguh yang dapat menangani masalah dengan baik, mulai dari input yang tidak valid hingga ketidaktersediaan layanan sementara.

Data Manager API mengikuti model error Google API standar, yang didasarkan pada kode Status gRPC. Setiap respons API yang menghasilkan error menyertakan objek Status dengan:

  • Kode error numerik.
  • Pesan error.
  • Opsional, detail error tambahan.

Kode error kanonis

Data Manager API menggunakan serangkaian kode error kanonis yang ditentukan oleh gRPC dan HTTP. Kode ini memberikan indikasi umum tentang jenis error. Anda harus selalu memeriksa kode ini terlebih dahulu untuk memahami sifat mendasar dari masalah tersebut.

Untuk mengetahui detail selengkapnya tentang kode ini, lihat Panduan Desain API - Kode error.

Menangani error

Ikuti langkah-langkah berikut jika permintaan gagal:

  1. Periksa kode error untuk menemukan jenis error.

    • Jika Anda menggunakan gRPC, kode error ada di kolom code pada Status. Jika Anda menggunakan library klien, library tersebut dapat memunculkan jenis pengecualian tertentu yang sesuai dengan kode error. Misalnya, library klien untuk Java akan menampilkan com.google.api.gax.rpc.InvalidArgumentException jika kode errornya adalah INVALID_ARGUMENT.
    • Jika Anda menggunakan REST, kode error ada dalam respons error di error.status, dan status HTTP yang sesuai ada di error.code.
  2. Periksa payload detail standar untuk kode error. Payload detail standar adalah sekumpulan pesan untuk error dari Google API. Hal ini memberi Anda detail error dengan cara yang terstruktur dan konsisten. Setiap error dari Data Manager API mungkin memiliki beberapa pesan payload detail standar. Library klien Data Manager API memiliki metode helper untuk mendapatkan payload detail standar dari error.

    Apa pun kode errornya, sebaiknya periksa dan catat payload ErrorInfo, RequestInfo, Help, dan LocalizedMessage.

    • ErrorInfo memiliki informasi yang mungkin tidak ada di payload lain.
    • RequestInfo memiliki ID permintaan, yang berguna jika Anda perlu menghubungi dukungan.
    • Help dan LocalizedMessage berisi link dan detail lainnya untuk membantu Anda mengatasi error.

    Selain itu, payload BadRequest, QuotaFailure, dan RetryInfo berguna untuk kode error tertentu:

    • Jika kode statusnya adalah INVALID_ARGUMENT, periksa payload BadRequest untuk mengetahui informasi tentang kolom mana yang menyebabkan error.
    • Jika kode statusnya adalah RESOURCE_EXHAUSTED, periksa payload QuotaFailure dan RetryInfo untuk mendapatkan informasi kuota dan rekomendasi penundaan percobaan ulang.

Payload detail standar

Payload detail standar yang paling umum untuk Data Manager API adalah:

BadRequest

Periksa payload BadRequest saat permintaan gagal dengan INVALID_ARGUMENT (kode status HTTP 400).

Pesan BadRequest menunjukkan bahwa permintaan memiliki kolom dengan nilai yang buruk, atau tidak memiliki nilai untuk kolom wajib diisi. Periksa daftar field_violations di BadRequest untuk menemukan kolom mana yang memiliki error. Setiap entri field_violations memiliki informasi untuk membantu Anda memperbaiki error:

field

Lokasi kolom dalam permintaan, menggunakan sintaks jalur camel case.

Jika jalur mengarah ke item dalam daftar (kolom repeated), indeksnya akan ditampilkan dalam tanda kurung siku ([...]) setelah nama daftar.

Misalnya, destinations[0].operating_account.account_id adalah account_id dalam operating_account item pertama dalam daftar destinations.

description

Penjelasan mengapa nilai menyebabkan error.

reason

Enum ErrorReason, seperti INVALID_HEX_ENCODING atau INVALID_CURRENCY_CODE.

Contoh BadRequest

Berikut adalah contoh respons untuk error INVALID_ARGUMENT dengan pesan BadRequest. field_violations menunjukkan bahwa error tersebut adalah accountId yang bukan angka. Nilai field destinations[0].login_account.account_id menunjukkan bahwa accountId dengan pelanggaran kolom ada di login_account item pertama dalam daftar 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"
          }
        ]
      }
    ]
  }
}

Berikut contoh respons lain dari error INVALID_ARGUMENT dengan pesan BadRequest. Dalam hal ini, daftar field_violations menampilkan dua kesalahan:

  1. event pertama memiliki nilai yang tidak dienkode hex pada ID pengguna kedua peristiwa.

  2. event kedua memiliki nilai yang tidak dienkode hex pada ID pengguna ketiga peristiwa.

{
  "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 dan RetryInfo

Periksa payload QuotaFailure dan RetryInfo saat permintaan gagal dengan RESOURCE_EXHAUSTED (kode status HTTP 429).

Pesan QuotaFailure menunjukkan bahwa resource telah habis (misalnya, Anda telah melampaui kuota), atau sistem mengalami kelebihan beban. Periksa daftar violations untuk menentukan kuota mana yang terlampaui.

Error juga dapat berisi pesan RetryInfo, yang menunjukkan retry_delay yang direkomendasikan untuk mencoba kembali permintaan.

RequestInfo

Periksa payload RequestInfo setiap kali permintaan gagal. RequestInfo berisi request_id yang secara unik mengidentifikasi permintaan API Anda.

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

Saat mencatat error atau menghubungi dukungan, pastikan untuk menyertakan ID permintaan untuk membantu mendiagnosis masalah.

ErrorInfo

Periksa pesan ErrorInfo untuk mengambil informasi tambahan yang mungkin tidak tercatat dalam payload detail standar lainnya. Payload ErrorInfo berisi peta metadata dengan informasi tentang error.

Misalnya, berikut ErrorInfo untuk kegagalan PERMISSION_DENIED yang disebabkan oleh penggunaan kredensial untuk project Google Cloud yang tidak mengaktifkan Data Manager API. ErrorInfo memberikan informasi tambahan tentang error, seperti:

  • Project yang terkait dengan permintaan, di bagian metadata.consumer.
  • Nama layanan, di bagian metadata.serviceTitle.
  • URL tempat layanan dapat diaktifkan, di bagian 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 dan LocalizedMessage

Periksa payload Help dan LocalizedMessage untuk mendapatkan link ke dokumentasi dan pesan error yang dilokalkan yang membantu Anda memahami dan memperbaiki error.

Misalnya, berikut Help dan LocalizedMessage untuk kegagalan PERMISSION_DENIED yang disebabkan oleh penggunaan kredensial untuk project Google Cloud yang Data Manager API-nya tidak diaktifkan. Payload Help menampilkan URL tempat layanan dapat diaktifkan, dan LocalizedMessage memiliki deskripsi error.

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

Mengakses detail error

Jika Anda menggunakan salah satu library klien, gunakan metode helper untuk mendapatkan payload detail standar.

.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.
  ...
}

Praktik terbaik untuk penanganan error

Untuk membangun aplikasi yang tangguh, terapkan praktik terbaik berikut.

Memeriksa detail error
Selalu cari salah satu payload detail standar seperti BadRequest. Setiap payload detail standar berisi informasi untuk membantu Anda memahami penyebab error.
Membedakan error klien dari error server

Tentukan apakah error disebabkan oleh masalah pada penerapan Anda (klien) atau masalah pada API (server).

  • Error klien: Kode seperti INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED. Error ini memerlukan perubahan pada permintaan atau status/kredensial aplikasi Anda. Jangan coba lagi permintaan tanpa mengatasi masalahnya.
  • Error server: Kode seperti UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED, UNKNOWN. Error ini menunjukkan masalah sementara pada layanan API.
Menerapkan strategi percobaan ulang

Tentukan apakah error dapat dicoba lagi, dan gunakan strategi percobaan ulang.

  • Coba lagi hanya untuk error server sementara seperti UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN, dan ABORTED.
  • Gunakan algoritma backoff eksponensial untuk menunggu dalam jangka waktu yang semakin lama di antara percobaan ulang. Tindakan ini membantu menghindari layanan yang sudah tertekan menjadi lebih tertekan. Misalnya, tunggu 1 detik, lalu 2 detik, lalu 4 detik, dan teruskan hingga jumlah maksimum percobaan ulang atau total waktu tunggu.
  • Tambahkan sejumlah kecil "jitter" acak ke penundaan mundur untuk mencegah masalah "kawanan guntur" saat banyak klien mencoba lagi secara bersamaan.
Catat secara menyeluruh

Catat respons error lengkap, termasuk semua payload detail standar, terutama ID permintaan. Informasi ini penting untuk men-debug dan melaporkan masalah ke dukungan Google jika diperlukan.

Memberikan masukan pengguna

Berdasarkan kode dan pesan dalam payload detail standar, berikan masukan yang jelas dan bermanfaat kepada pengguna aplikasi Anda. Misalnya, alih-alih hanya "Terjadi kesalahan", Anda dapat mengatakan "ID transaksi tidak ada" atau "ID akun tujuan tidak ditemukan".

Dengan mengikuti panduan ini, Anda dapat mendiagnosis dan menangani error yang ditampilkan oleh Data Manager API secara efektif, sehingga menghasilkan aplikasi yang lebih stabil dan mudah digunakan.