API 오류 이해

이 가이드에서는 Data Manager API가 오류를 처리하고 전달하는 방법을 설명합니다. API 오류의 구조와 의미를 이해하는 것은 잘못된 입력부터 일시적인 서비스 사용 불가능에 이르기까지 문제를 원활하게 처리할 수 있는 강력한 애플리케이션을 빌드하는 데 매우 중요합니다.

데이터 관리자 API는 gRPC 상태 코드를 기반으로 하는 표준 Google API 오류 모델을 따릅니다. 오류가 발생하는 각 API 응답에는 다음이 포함된 Status 객체가 포함됩니다.

  • 숫자 오류 코드입니다.
  • 오류 메시지입니다.
  • 선택사항인 추가 오류 세부정보입니다.

표준 오류 코드

데이터 관리자 API는 gRPC 및 HTTP로 정의된 표준 오류 코드 집합을 사용합니다. 이 코드는 오류 유형을 대략적으로 나타냅니다. 이 코드를 먼저 확인하여 문제의 근본적인 성격을 파악해야 합니다.

이러한 코드에 대한 자세한 내용은 API 디자인 가이드 - 오류 코드를 참고하세요.

오류 처리

요청이 실패하면 다음 단계를 따르세요.

  1. 오류 코드를 확인하여 오류 유형을 찾습니다.

    • gRPC를 사용하는 경우 오류 코드는 Statuscode 필드에 있습니다. 클라이언트 라이브러리를 사용하는 경우 오류 코드에 해당하는 특정 유형의 예외가 발생할 수 있습니다. 예를 들어 오류 코드가 INVALID_ARGUMENT인 경우 Java용 클라이언트 라이브러리는 com.google.api.gax.rpc.InvalidArgumentException를 발생시킵니다.
    • REST를 사용하는 경우 오류 코드는 error.status의 오류 응답에 있고 해당 HTTP 상태는 error.code에 있습니다.
  2. 오류 코드의 표준 세부정보 페이로드를 확인합니다. 표준 세부정보 페이로드는 Google API의 오류 메시지 집합입니다. 오류 세부정보를 구조화되고 일관된 방식으로 제공합니다. Data Manager API의 각 오류에는 여러 표준 세부정보 페이로드 메시지가 있을 수 있습니다. 데이터 관리 도구 API 클라이언트 라이브러리에는 오류에서 표준 세부정보 페이로드를 가져오는 도우미 메서드가 있습니다.

    오류 코드와 관계없이 ErrorInfo, RequestInfo, Help, LocalizedMessage 페이로드를 확인하고 로깅하는 것이 좋습니다.

    • ErrorInfo에는 다른 페이로드에 없을 수 있는 정보가 있습니다.
    • RequestInfo에는 요청 ID가 있어 지원팀에 문의해야 하는 경우에 유용합니다.
    • HelpLocalizedMessage에는 오류를 해결하는 데 도움이 되는 링크와 기타 세부정보가 포함되어 있습니다.

    또한 BadRequest, QuotaFailure, RetryInfo 페이로드는 특정 오류 코드에 유용합니다.

    • 상태 코드가 INVALID_ARGUMENT인 경우 BadRequest 페이로드를 확인하여 오류를 일으킨 필드에 관한 정보를 확인합니다.
    • 상태 코드가 RESOURCE_EXHAUSTED인 경우 QuotaFailureRetryInfo 페이로드에서 할당량 정보와 재시도 지연 권장사항을 확인합니다.

표준 세부정보 페이로드

Data Manager API의 가장 일반적인 표준 세부정보 페이로드는 다음과 같습니다.

BadRequest

요청이 INVALID_ARGUMENT (HTTP 상태 코드 400)로 실패할 때 BadRequest 페이로드를 확인합니다.

BadRequest 메시지는 요청에 잘못된 값이 있는 필드가 있거나 필수 필드의 값이 누락되었음을 나타냅니다. BadRequest에서 field_violations 목록을 확인하여 오류가 있는 필드를 찾습니다. 각 field_violations 항목에는 오류를 수정하는 데 도움이 되는 정보가 있습니다.

field

카멜 표기법 경로 구문을 사용하는 요청의 필드 위치입니다.

경로가 목록의 항목 (repeated 필드)을 가리키는 경우 목록 이름 뒤에 대괄호 ([...])로 색인이 표시됩니다.

예를 들어 destinations[0].operating_account.account_iddestinations 목록의 첫 번째 항목의 operating_account에 있는 account_id입니다.

description

값이 오류를 일으킨 이유에 대한 설명입니다.

reason

INVALID_HEX_ENCODING 또는 INVALID_CURRENCY_CODE과 같은 ErrorReason enum입니다.

BadRequest의 예

BadRequest 메시지가 포함된 INVALID_ARGUMENT 오류의 샘플 응답은 다음과 같습니다. field_violations에는 숫자가 아닌 accountId 오류가 표시됩니다. fielddestinations[0].login_account.account_id은 필드 위반이 있는 accountIddestinations 목록의 첫 번째 항목의 login_account에 있음을 보여줍니다.

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

다음은 BadRequest 메시지가 포함된 INVALID_ARGUMENT 오류의 또 다른 샘플 응답입니다. 이 경우 field_violations 목록에 두 가지 오류가 표시됩니다.

  1. 첫 번째 event의 값이 이벤트의 두 번째 사용자 식별자에서 16진수로 인코딩되지 않았습니다.

  2. 두 번째 event에는 이벤트의 세 번째 사용자 식별자에 16진수로 인코딩되지 않은 값이 있습니다.

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

QuotaFailureRetryInfo

요청이 RESOURCE_EXHAUSTED (HTTP 상태 코드 429)로 실패할 때 QuotaFailureRetryInfo 페이로드를 확인합니다.

QuotaFailure 메시지는 리소스가 소진되었거나(예: 할당량 초과) 시스템에 과부하가 걸렸음을 나타냅니다. violations 목록을 검사하여 초과된 할당량을 확인합니다.

오류에는 요청을 재시도하기 위해 권장되는 retry_delay를 나타내는 RetryInfo 메시지가 포함될 수도 있습니다.

RequestInfo

요청이 실패할 때마다 RequestInfo 페이로드를 확인합니다. RequestInfo에는 API 요청을 고유하게 식별하는 request_id가 포함됩니다.

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

오류를 로깅하거나 지원팀에 문의할 때는 문제 진단에 도움이 되도록 요청 ID를 포함하세요.

ErrorInfo

ErrorInfo 메시지를 확인하여 다른 표준 세부정보 페이로드에 포착되지 않을 수 있는 추가 정보를 가져옵니다. ErrorInfo 페이로드에는 오류에 관한 정보가 포함된 metadata 지도가 포함되어 있습니다.

예를 들어 Data Manager API가 사용 설정되지 않은 Google Cloud 프로젝트의 사용자 인증 정보를 사용하여 발생한 PERMISSION_DENIED 오류의 ErrorInfo는 다음과 같습니다. ErrorInfo는 다음과 같은 오류에 대한 추가 정보를 제공합니다.

  • metadata.consumer 아래에 있는 요청과 연결된 프로젝트입니다.
  • metadata.serviceTitle 아래의 서비스 이름입니다.
  • metadata.activationUrl에서 서비스를 사용 설정할 수 있는 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"
        }
      },
      ...
    ]
  }
}

HelpLocalizedMessage

HelpLocalizedMessage 페이로드를 확인하여 오류를 이해하고 수정하는 데 도움이 되는 문서 링크와 현지화된 오류 메시지를 확인합니다.

예를 들어 Data Manager API가 사용 설정되지 않은 Google Cloud 프로젝트의 사용자 인증 정보를 사용하여 발생한 PERMISSION_DENIED 실패의 HelpLocalizedMessage는 다음과 같습니다. 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
        {
            // ...
        }
    }
}

자바

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과 같은 일시적인 서버 오류에 대해서만 다시 시도하세요.
  • 지수 백오프 알고리즘을 사용하여 재시도 간 대기 시간을 늘립니다. 이렇게 하면 이미 스트레스를 받고 있는 서비스에 과부하가 걸리지 않습니다. 예를 들어 1초, 2초, 4초 동안 기다리는 식으로 최대 재시도 횟수 또는 총 대기 시간까지 계속합니다.
  • 많은 클라이언트가 동시에 재시도하는 'thundering herd' 문제를 방지하기 위해 백오프 지연에 작은 임의의 '지터'를 추가합니다.
철저하게 로깅

모든 표준 세부정보 페이로드, 특히 요청 ID를 포함한 전체 오류 응답을 로깅합니다. 이 정보는 필요한 경우 문제를 디버깅하고 Google 지원팀에 보고하는 데 필수적입니다.

사용자 의견 제공

표준 세부정보 페이로드의 코드와 메시지를 기반으로 애플리케이션 사용자에게 명확하고 유용한 의견을 제공합니다. 예를 들어 '오류가 발생했습니다'라고만 말하는 대신 '거래 ID가 누락되었습니다' 또는 '목적지의 계정 ID를 찾을 수 없습니다'라고 말할 수 있습니다.

이 가이드라인을 따르면 Data Manager API에서 반환된 오류를 효과적으로 진단하고 처리하여 더 안정적이고 사용자 친화적인 애플리케이션을 만들 수 있습니다.