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 andal yang dapat menangani masalah dengan baik, mulai dari input yang tidak valid hingga layanan yang tidak tersedia untuk 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.

Model gagal cepat

Data Manager API menggunakan model gagal cepat. Jika permintaan berisi error struktural atau jika ada rekaman yang gagal divalidasi untuk kolom wajib diisi, seluruh permintaan akan gagal, dan API tidak akan memproses data apa pun dalam permintaan tersebut.

Perbandingan dengan model kegagalan parsial

Model kegagalan cepat berbeda dengan model kegagalan parsial di beberapa Google API lainnya, seperti Google Ads API dan Campaign Manager 360 API. Dalam model kegagalan parsial, permintaan berhasil meskipun beberapa data mengalami error, dan respons berisi detail error untuk data yang gagal.

Meskipun kegagalan sebagian dapat memberikan kemudahan, hal ini membawa risiko yang signifikan karena model kegagalan sebagian tidak secara proaktif memberi tahu Anda tentang error—Anda harus memeriksa error secara eksplisit di setiap respons. Hal ini dapat menutupi masalah penting karena permintaan berhasil meskipun API menolak banyak atau bahkan semua catatan dalam permintaan. Jika sebagian besar data dalam permintaan memiliki error, tetapi Anda tidak memeriksa respons, Anda mungkin tidak menyadari masalah yang meluas pada data Anda, dan baru mengetahui masalah tersebut beberapa hari atau minggu kemudian saat hasil kumulatif tidak sesuai dengan harapan Anda.

Model gagal cepat menghindari potensi masalah ini dengan segera memberi tahu Anda tentang masalah pada data atau integrasi sehingga Anda dapat mengambil tindakan yang sesuai.

Memeriksa error kegagalan cepat dengan validateOnly

Sebagian besar permintaan penyerapan dan permintaan penghapusan mendukung kolom validateOnly. Saat Anda menetapkan validateOnly ke true, Data Manager API menjalankan pemeriksaan validasi dasar yang sama seperti yang dilakukan untuk permintaan reguler, tetapi tidak menyerap atau menghapus data apa pun.

  • Jika permintaan memiliki error, permintaan akan gagal dengan respons error yang sama seperti yang akan Anda dapatkan dari permintaan reguler.
  • Jika permintaan lolos validasi, permintaan akan berhasil. Respons menyertakan fieldWarnings untuk kolom opsional, seperti permintaan biasa.

Gunakan validateOnly untuk:

  • Uji integrasi baru atau yang diperbarui tanpa memengaruhi data aktif Anda.
  • Pastikan perbaikan menyelesaikan error sebelum Anda mengirim ulang permintaan.

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 kumpulan pesan untuk error dari Google API. Mereka 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 berguna untuk error INVALID_ARGUMENT karena memberikan informasi tentang kolom mana yang menyebabkan error.

Peringatan penyerapan

Data Manager API menerima sebanyak mungkin permintaan penyerapan. Jika Anda menyertakan data yang tidak diperlukan, kegagalan validasi untuk kolom tersebut tidak akan menyebabkan permintaan gagal. Misalnya, jika item keranjang tidak memiliki ID produk penjual, API akan memproses sisa permintaan dan menampilkan peringatan.

Respons penyerapan yang berhasil (kode status HTTP 200) mencakup peringatan ini dalam daftar fieldWarnings. Setiap entri adalah objek FieldWarning dengan kolom berikut:

field

Lokasi kolom dalam permintaan, dalam sintaks jalur snake case.

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

Misalnya, events.events[0].cart_data.items[0].merchant_product_id mengidentifikasi peringatan yang terkait dengan item pertama dalam data keranjang dari peristiwa pertama dalam permintaan.

description

Penjelasan mengapa nilai yang diberikan menyebabkan peringatan.

reason

Nilai enum WarningReason yang mengidentifikasi jenis peringatan.

Contoh dengan FieldWarning

Berikut adalah contoh respons untuk permintaan penyerapan yang berhasil yang berisi peringatan karena ID produk penjual tidak ada untuk salah satu item keranjang.

{
  "requestId": "126365e1-16d0-4c81-9de9-f362711e250a",
  "fieldWarnings": [
    {
      "field": "events.events[0].cart_data.items[0].merchant_product_id",
      "description": "The merchant product ID is missing in the cart item.",
      "reason": "WARNING_REASON_CART_DATA_ITEM_MERCHANT_PRODUCT_ID_MISSING"
    }
  ]
}

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, dalam sintaks jalur snake case.

Jika jalur mengarah ke item dalam daftar (kolom repeated), indeksnya 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 tersebut 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 accountId dengan pelanggaran kolom berada 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 dalam hex pada ID pengguna kedua peristiwa.

  2. event kedua memiliki nilai yang tidak dienkode dalam 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"
          }
        ]
      }
    ]
  }
}

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 Data Manager API-nya tidak diaktifkan. ErrorInfo memberikan informasi tambahan tentang error, seperti:

  • Project yang terkait dengan permintaan, di bagian metadata.consumer.
  • Nama layanan, di bawah 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.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"
        }
      },
      ...
    ]
  }
}

Error kuota dan pembatasan kapasitas

Jika permintaan melebihi batas project, API akan menampilkan error RESOURCE_EXHAUSTED (kode status HTTP 429). Payload ErrorInfo memberikan detail tentang batas yang terlampaui dalam peta metadata-nya:

consumer
Project Google Cloud yang terkait dengan permintaan, diformat sebagai projects/PROJECT_NUMBER.
quota_limit
Nama batas kuota yang terlampaui, seperti IngestionMutateRequestsPerMinutePerProject atau IngestionMutateRequestsPerDayPerProject. Anda dapat menggunakan nilai ini untuk menentukan apakah aplikasi melampaui batas per menit atau batas harian. Untuk daftar lengkap nama batas, lihat Batas project.
quota_location
Lokasi tempat kuota diterapkan. Untuk Data Manager API, nilai ini selalu global.
quota_metric
Metrik yang terkait dengan batas, seperti datamanager.googleapis.com/ingestion_mutate_requests.
service
Nama layanan, datamanager.googleapis.com.

Berikut adalah contoh respons error RESOURCE_EXHAUSTED saat permintaan melebihi batas per menit untuk permintaan modifikasi penyerapan:

{
  "error": {
    "code": 429,
    "message": "Quota exceeded for quota metric 'Ingestion mutate requests' and limit 'Ingestion mutate requests per minute' of service 'datamanager.googleapis.com' for consumer 'project_number:PROJECT_NUMBER'.",
    "status": "RESOURCE_EXHAUSTED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "RATE_LIMIT_EXCEEDED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "quota_limit": "IngestionMutateRequestsPerMinutePerProject",
          "quota_location": "global",
          "quota_metric": "datamanager.googleapis.com/ingestion_mutate_requests",
          "service": "datamanager.googleapis.com"
        }
      }
    ]
  }
}

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 tidak mengaktifkan Data Manager API. 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.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"
          }
        ]
      },
      ...
    ]
  }
}

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.ErrorInfo)
        {
            Google.Rpc.ErrorInfo errorInfo = (Google.Rpc.ErrorInfo)detail;
            // Log the errorInfo.Reason and errorInfo.Metadata...

            // If handling a rate limit error, check the exceeded quota limit:
            if (errorInfo.Reason == "RATE_LIMIT_EXCEEDED" &&
                errorInfo.Metadata.TryGetValue("quota_limit", out string quotaLimit))
            {
                // Inspect quotaLimit to determine whether it is a per-minute
                // or daily limit (for example,
                // IngestionMutateRequestsPerMinutePerProject).
            }

            // Log the details in the 'Metadata' map...
            foreach (
                KeyValuePair<String, String> metadataEntry in errorInfo.Metadata
            )
            {
                // Log the metadataEntry.Key and metadataEntry.Value...
            }
        }
        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.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'...

  // If handling a rate limit error, check the exceeded quota limit:
  if (errorInfo != null && "RATE_LIMIT_EXCEEDED".equals(errorInfo.getReason())) {
    String quotaLimit = errorInfo.getMetadataMap().get("quota_limit");
    // Inspect quotaLimit to determine whether it is a per-minute
    // or daily limit (for example,
    // IngestionMutateRequestsPerMinutePerProject).
  }

  // 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 = apiException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
  ...
}

Praktik terbaik untuk penanganan error

Untuk membangun aplikasi yang tangguh, terapkan praktik terbaik berikut.

Validasi sebelum Anda mengirim
Saat Anda membuat atau mengubah integrasi, kirim permintaan dengan validateOnly yang ditetapkan ke true untuk mendeteksi error gagal cepat sebelum Anda memproses data.
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. Hal 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) dan pembatasan kapasitas per menit (RESOURCE_EXHAUSTED dengan RATE_LIMIT_EXCEEDED).

  • Untuk pembatasan kapasitas, periksa quota_limit di ErrorInfo:

    • Jika batasnya adalah per menit (seperti IngestionMutateRequestsPerMinutePerProject), jeda permintaan dan coba lagi menggunakan backoff eksponensial dengan jitter.

    • Jika batasnya adalah harian (seperti IngestionMutateRequestsPerDayPerProject), jangan coba lagi segera. Menjeda pemrosesan hingga kuota harian direset pada tengah malam Waktu Pasifik.

  • Gunakan algoritma backoff eksponensial untuk menunggu jangka waktu yang semakin lama di antara percobaan ulang. Hal ini membantu menghindari layanan yang sudah tertekan. Misalnya, tunggu 1 detik, lalu 2 detik, lalu 4 detik, dan teruskan hingga jumlah maksimum percobaan ulang atau total waktu tunggu.

  • Tambahkan sedikit "jitter" acak ke penundaan mundur untuk mencegah masalah "kawanan guntur" saat banyak klien mencoba lagi secara bersamaan.

Catat secara menyeluruh

Mencatat respons error lengkap, termasuk semua payload detail standar, terutama ID permintaan. Informasi ini sangat 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 bagi 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.