API hatalarını anlama

Bu kılavuzda, Veri Yöneticisi API'sinin hataları nasıl işlediği ve ilettiği açıklanmaktadır. API hatalarının yapısını ve anlamını anlamak, geçersiz girişten geçici hizmet kullanılamazlığına kadar sorunları düzgün bir şekilde ele alabilen sağlam uygulamalar oluşturmak için çok önemlidir.

Veri Yöneticisi API'si, gRPC durum kodlarına dayalı olan standart Google API hata modelini kullanır. Hataya neden olan her API yanıtı, aşağıdakileri içeren bir Status nesnesi içerir:

  • Sayısal bir hata kodu.
  • Hata mesajı
  • İsteğe bağlı, ek hata ayrıntıları.

Standartlaştırma hata kodları

Veri Yöneticisi API'si, gRPC ve HTTP tarafından tanımlanan bir dizi standart hata kodu kullanır. Bu kodlar, hata türü hakkında üst düzey bir gösterge sağlar. Sorunun temel doğasını anlamak için önce bu kodu kontrol etmeniz gerekir.

Bu kodlar hakkında daha fazla bilgi için API Tasarım Kılavuzu - Hata kodları başlıklı makaleyi inceleyin.

Hataları işleme

Bir istek başarısız olduğunda şu adımları uygulayın:

  1. Hata türünü bulmak için hata kodunu kontrol edin.

    • gRPC kullanıyorsanız hata kodu, Status öğesinin code alanındadır. İstemci kitaplığı kullanıyorsanız hata koduna karşılık gelen belirli bir istisna türü oluşturabilir. Örneğin, Java için istemci kitaplığı, hata kodu INVALID_ARGUMENT ise com.google.api.gax.rpc.InvalidArgumentException hatası verir.
    • REST kullanıyorsanız hata kodu error.status konumundaki hata yanıtında, karşılık gelen HTTP durumu ise error.code konumundadır.
  2. Hata kodu için standart ayrıntı yükünü kontrol edin. Standart ayrıntı yükleri, Google API'lerinden kaynaklanan hatalarla ilgili bir mesaj grubudur. Hata ayrıntılarını yapılandırılmış ve tutarlı bir şekilde sunar. Veri Yöneticisi API'sindeki her hata birden fazla standart ayrıntı yükü mesajı içerebilir. Data Manager API istemci kitaplıklarında, bir hatadan standart ayrıntı yüklerini almak için yardımcı yöntemler bulunur.

    Hata kodu ne olursa olsun ErrorInfo, RequestInfo, Help ve LocalizedMessage yüklerini kontrol etmenizi ve günlüğe kaydetmenizi öneririz.

    • ErrorInfo, diğer yüklerde bulunmayabilecek bilgiler içeriyor.
    • RequestInfo içinde, destek ekibiyle iletişime geçmeniz gerekirse yararlı olacak istek kimliği bulunur.
    • Help ve LocalizedMessage, hatayı gidermenize yardımcı olacak bağlantılar ve diğer ayrıntıları içerir.

    Ayrıca, BadRequest, QuotaFailure ve RetryInfo yükleri belirli hata kodları için yararlıdır:

    • Durum kodu INVALID_ARGUMENT ise hangi alanların hataya neden olduğu hakkında bilgi edinmek için BadRequest yükünü kontrol edin.
    • Durum kodu RESOURCE_EXHAUSTED ise kota bilgileri ve yeniden deneme gecikmesi önerisi için QuotaFailure ve RetryInfo yüklerini kontrol edin.

Standart ayrıntı yükleri

Veri Yöneticisi API'si için en yaygın standart ayrıntı yükleri şunlardır:

BadRequest

Bir istek INVALID_ARGUMENT (HTTP durum kodu 400) ile başarısız olduğunda BadRequest yükünü kontrol edin.

BadRequest mesajı, isteğin kötü değerlere sahip alanlar içerdiğini veya zorunlu bir alan için değerin eksik olduğunu gösterir. Hangi alanlarda hata olduğunu öğrenmek için field_violations listesini kontrol edin.BadRequest Her field_violations girişi, hatayı düzeltmenize yardımcı olacak bilgiler içerir:

field

İstekteki alanın konumu (camel case yolu söz dizimi kullanılarak).

Bir yol, listedeki bir öğeyi (repeated alanı) işaret ediyorsa dizini, liste adından sonra köşeli parantez içinde ([...]) gösterilir.

Örneğin, destinations[0].operating_account.account_id, destinations listesindeki ilk öğenin operating_account bölümündeki account_id'dir.

description

Değerin neden hataya yol açtığına dair açıklama.

reason

ErrorReason numaralandırması (ör. INVALID_HEX_ENCODING veya INVALID_CURRENCY_CODE).

BadRequest örnekleri

Aşağıda, BadRequest mesajı içeren bir INVALID_ARGUMENT hatasıyla ilgili örnek bir yanıt verilmiştir. field_violations, hatanın accountId olmayan bir sayı olduğunu gösterir. field değeri destinations[0].login_account.account_id, accountId alan ihlali olan login_account öğesinin destinations listesindeki ilk öğe olduğunu gösterir.

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

Aşağıda, BadRequest mesajı içeren bir INVALID_ARGUMENT hatasından alınan başka bir örnek yanıt verilmiştir. Bu durumda, field_violations listesinde iki hata gösterilir:

  1. İlk event, etkinliğin ikinci kullanıcı tanımlayıcısında onaltılık kodlanmamış bir değere sahip.

  2. İkinci event, etkinliğin üçüncü kullanıcı tanımlayıcısında onaltılık kodlanmamış bir değere sahip.

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

Bir istek RESOURCE_EXHAUSTED (HTTP durum kodu 429) ile başarısız olduğunda QuotaFailure ve RetryInfo yüklerini kontrol edin.

QuotaFailure mesajı, bir kaynağın tükendiğini (ör. kotanızı aştınız) veya bir sistemin aşırı yüklendiğini gösterir. Hangi kotaların aşıldığını belirlemek için violations listesini inceleyin.

Hata, isteğin yeniden denenmesinin önerildiğini belirten bir RetryInfo mesajı da içerebilir.retry_delay

RequestInfo

Bir istek başarısız olduğunda RequestInfo yükünü kontrol edin. RequestInfo, API isteğinizi benzersiz şekilde tanımlayan request_id içerir.

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

Hata günlüğüne kaydederken veya destek ekibiyle iletişime geçerken sorunların teşhis edilmesine yardımcı olmak için istek kimliğini eklediğinizden emin olun.

ErrorInfo

Diğer standart ayrıntı yüklerinde yakalanmamış olabilecek ek bilgileri almak için ErrorInfo mesajını kontrol edin. Yük, hatayla ilgili bilgilerin yer aldığı bir ErrorInfometadata haritası içerir.

Örneğin, Data Manager API'nin etkin olmadığı bir Google Cloud projesi için kimlik bilgileri kullanıldığında ortaya çıkan PERMISSION_DENIED hatasıyla ilgili ErrorInfo bölümünü burada bulabilirsiniz. ErrorInfo, hata hakkında ek bilgiler sağlar. Örneğin:

  • metadata.consumer altındaki istekle ilişkili proje.
  • metadata.serviceTitle bölümünde hizmetin adı.
  • metadata.activationUrl bölümünde hizmetin etkinleştirilebileceği URL.
{
  "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 ve LocalizedMessage

Hatayı anlamanıza ve düzeltmenize yardımcı olacak belgelere ve yerelleştirilmiş hata mesajlarına yönelik bağlantılar almak için Help ve LocalizedMessage yüklerini kontrol edin.

Örneğin, Data Manager API'nin etkinleştirilmediği bir Google Cloud projesi için kimlik bilgileri kullanmaktan kaynaklanan PERMISSION_DENIED hatasıyla ilgili Help ve LocalizedMessage aşağıda verilmiştir. Help yükünde, hizmetin etkinleştirilebileceği URL gösterilir. LocalizedMessage içinde ise hatanın açıklaması yer alır.

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

Erişim hatası ayrıntılarına erişme

İstemci kitaplıklarından birini kullanıyorsanız standart ayrıntı yüklerini almak için yardımcı yöntemleri kullanın.

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

Hata işleme ile ilgili en iyi uygulamalar

Esnek uygulamalar oluşturmak için aşağıdaki en iyi uygulamaları uygulayın.

Hata ayrıntılarını inceleme
Her zaman BadRequest gibi standart ayrıntı yüklerinden birini arayın. Her standart ayrıntı yükü, hatanın nedenini anlamanıza yardımcı olacak bilgiler içerir.
İstemci hataları ile sunucu hatalarını ayırt etme

Hataya uygulamanızla (istemci) ilgili bir sorunun mu yoksa API ile (sunucu) ilgili bir sorunun mu neden olduğunu belirleyin.

  • İstemci hataları: INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED gibi kodlar. Bu tür hatalar, isteğin veya uygulamanızın durumu/kimlik bilgilerinde değişiklik yapılmasını gerektirir. Sorunu gidermeden isteği yeniden göndermeyin.
  • Sunucu hataları: UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED, UNKNOWN gibi kodlar. Bunlar, API hizmetiyle ilgili geçici bir soruna işaret eder.
Yeniden deneme stratejisi uygulama

Hatayı yeniden denemenin mümkün olup olmadığını belirleyin ve yeniden deneme stratejisi kullanın.

  • UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN ve ABORTED gibi geçici sunucu hataları yalnızca yeniden denenir.
  • Yeniden denemeler arasında artan sürelerle beklemek için eksponansiyel geri yükleme algoritması kullanın. Bu, zaten stresli olan bir hizmetin aşırı yüklenmesini önlemeye yardımcı olur. Örneğin, önce 1 saniye, sonra 2 saniye, sonra 4 saniye bekleyin ve maksimum yeniden deneme sayısı veya toplam bekleme süresine ulaşana kadar bu şekilde devam edin.
  • Birçok istemcinin aynı anda yeniden denediği "gürleyen sürü" sorununu önlemek için geri çekilme gecikmelerine küçük bir rastgele "titreme" miktarı ekleyin.
Kapsamlı günlük kaydı

Tüm standart ayrıntı yükleri dahil olmak üzere hatayla ilgili tam yanıtı, özellikle de istek kimliğini günlüğe kaydedin. Bu bilgiler, hata ayıklama ve gerekirse sorunları Google Destek Ekibi'ne bildirme açısından önemlidir.

Kullanıcı geri bildirimi sağlama

Standart ayrıntı yüklerindeki kodlara ve mesajlara göre uygulamanızın kullanıcılarına net ve faydalı geri bildirimler sağlayın. Örneğin, yalnızca "Bir hata oluştu" demek yerine "İşlem kimliği eksikti" veya "Hedefin hesap kimliği bulunamadı" diyebilirsiniz.

Bu yönergeleri uygulayarak Veri Yöneticisi API'sinin döndürdüğü hataları etkili bir şekilde teşhis edip işleyebilir, böylece daha kararlı ve kullanıcı dostu uygulamalar oluşturabilirsiniz.