במדריך הזה מוסבר איך המרכז לניהול נתונים API מטפל בשגיאות ואיך הוא מעביר אותן. הבנה של המבנה והמשמעות של שגיאות ב-API היא חיונית לבניית אפליקציות חזקות שיכולות לטפל בבעיות בצורה חלקה, החל מקלט לא תקין ועד לחוסר זמינות זמני של השירות.
ה-API של המרכז לניהול נתונים פועל לפי מודל השגיאות הרגיל של Google API, שמבוסס על קודי סטטוס של gRPC. כל תגובה מה-API שמובילה לשגיאה כוללת אובייקט Status עם:
- קוד שגיאה מספרי.
- הודעת שגיאה.
- פרטי שגיאה נוספים (אופציונלי).
קודי שגיאה קנוניים
ה-API של המרכז לניהול נתונים משתמש בקבוצה של קודי שגיאה קנוניים שמוגדרים על ידי gRPC ו-HTTP. הקודים האלה מציינים באופן כללי את סוג השגיאה. תמיד כדאי לבדוק קודם את הקוד הזה כדי להבין את המהות הבסיסית של הבעיה.
פרטים נוספים על הקודים האלה זמינים במאמר מדריך לעיצוב API – קודי שגיאה.
טיפול בשגיאות
אם בקשה נכשלת, צריך לבצע את הפעולות הבאות:
כדי לגלות את סוג השגיאה, בודקים את קוד השגיאה.
- אם משתמשים ב-gRPC, קוד השגיאה נמצא בשדה
codeשלStatus. אם משתמשים בספריית לקוח, יכול להיות שהיא תזרוק סוג ספציפי של חריגה שמתאים לקוד השגיאה. לדוגמה, ספריית הלקוח ל-Java יוצרתcom.google.api.gax.rpc.InvalidArgumentExceptionאם קוד השגיאה הואINVALID_ARGUMENT. - אם משתמשים ב-REST, קוד השגיאה נמצא בתגובת השגיאה ב-
error.status, וסטטוס ה-HTTP המתאים נמצא ב-error.code.
- אם משתמשים ב-gRPC, קוד השגיאה נמצא בשדה
בודקים את מטען הייעודי הסטנדרטי של הפרטים של קוד השגיאה. מטעני הנתונים של הפרטים הרגילים הם קבוצה של הודעות לגבי שגיאות מ-Google APIs. הם מספקים פרטים על השגיאות בצורה מובנית ועקבית. כל שגיאה מ-API של המרכז לניהול נתונים עשויה לכלול כמה הודעות מטען ייעודי (payload) מפורטות רגילות. בספריות הלקוח של המרכז לניהול נתונים API יש שיטות עזר לקבלת מטען הייעודי (payload) של פרטים רגילים משגיאה.
לא משנה מה קוד השגיאה, מומלץ לבדוק ולתעד את מטען הנתונים (payload) של
ErrorInfo,RequestInfo,HelpושלLocalizedMessage.-
ErrorInfoמכיל מידע שאולי לא מופיע במטען ייעודי אחר. RequestInfoכולל את מזהה הבקשה, שיכול לעזור לכם אם תצטרכו לפנות לתמיכה.-
Helpו-LocalizedMessageמכילים קישורים ופרטים אחרים שיעזרו לכם לפתור את השגיאה.
בנוסף, מטען הייעודי (payload) של
BadRequest,QuotaFailureו-RetryInfoשימושי לקודי שגיאה ספציפיים:- אם קוד הסטטוס הוא
INVALID_ARGUMENT, צריך לבדוק את מטען הנתונים (payload) שלBadRequestכדי לראות אילו שדות גרמו לשגיאה. - אם קוד הסטטוס הוא
RESOURCE_EXHAUSTED, צריך לבדוק את מטען הייעוד שלQuotaFailureושלRetryInfoכדי לקבל מידע על המכסה והמלצה לגבי השהיה לפני ניסיון חוזר.
-
מטענים סטנדרטיים של פרטים
המטענים הנפוצים ביותר של פרטים רגילים ב-API של המרכז לניהול נתונים הם:
BadRequest
בודקים את המטען הייעודי (payload) של BadRequest כשבקשה נכשלת עם INVALID_ARGUMENT (קוד סטטוס של HTTP 400).
ההודעה BadRequest מציינת שבבקשה היו שדות עם ערכים לא תקינים, או שחסר ערך בשדה חובה. בודקים את הרשימה field_violations בBadRequest כדי לראות באילו שדות יש שגיאות. כל field_violations רשומה
כוללת מידע שיעזור לכם לתקן את השגיאה:
fieldהמיקום של השדה בבקשה, באמצעות תחביר נתיב ב-קאמל קייס.
אם נתיב מצביע על פריט ברשימה (שדה
repeated), האינדקס שלו מוצג בסוגריים מרובעים ([...]) אחרי שם הרשימה.לדוגמה,
destinations[0].operating_account.account_idהואaccount_idב-operating_accountשל הפריט הראשון ברשימהdestinations.descriptionהסבר למה הערך גרם לשגיאה.
reasonהערך enum
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 מוצגות שתי שגיאות:
לפרמטר הראשון
eventיש ערך שלא מקודד בפורמט הקסדצימלי במזהה המשתמש השני של האירוע.ל-
eventהשני יש ערך שלא מקודד בפורמט הקסדצימלי במזהה המשתמש השלישי של האירוע.
{
"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
אם בקשה נכשלת עם RESOURCE_EXHAUSTED (קוד סטטוס של HTTP 429), צריך לבדוק את מטען הייעודי (payload) של QuotaFailure ושל RetryInfo.
הודעה עם הסמל QuotaFailure מציינת שנגמר המשאב (לדוגמה, חרגתם מהמיכסה) או שיש עומס יתר על המערכת. בודקים את רשימת violations כדי לראות אילו מכסות חרגו.
יכול להיות שהשגיאה תכלול גם RetryInfo הודעה, שמציינת את
retry_delay המומלץ לניסיון חוזר של הבקשה.
RequestInfo
בכל פעם שבקשה נכשלת, בודקים את המטען הייעודי (payload) RequestInfo. RequestInfo
מכיל את request_id שמזהה באופן ייחודי את בקשת ה-API.
{
"@type": "type.googleapis.com/google.rpc.RequestInfo",
"requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}
כשמתעדים שגיאות או פונים לתמיכה, חשוב לכלול את מזהה הבקשה כדי לעזור באבחון בעיות.
ErrorInfo
כדאי לבדוק אם מופיעה ההודעה ErrorInfo כדי לאחזר מידע נוסף שאולי לא נכלל במטענים הייעודיים (payloads) האחרים של הפרטים הסטנדרטיים. המטען הייעודי (payload) ErrorInfo
מכיל מפה metadata עם מידע על השגיאה.
לדוגמה, כאן מופיע ErrorInfo של כשל PERMISSION_DENIED שנגרם בגלל שימוש בפרטי כניסה לפרויקט בענן של Google שבו המרכז לניהול נתונים 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 שבו המרכז לניהול נתונים API לא מופעל. מטען הייעודי (payload) של 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. כל מטען ייעודי (payload) של פרטים רגילים מכיל מידע שיעזור לכם להבין את הסיבה לשגיאה. - ההבדל בין שגיאות בצד הלקוח לבין שגיאות בצד השרת
בודקים אם השגיאה נגרמת בגלל בעיה בהטמעה (הלקוח) או ב-API (השרת).
- שגיאות בצד הלקוח: קודים כמו
INVALID_ARGUMENT,NOT_FOUND,PERMISSION_DENIED,FAILED_PRECONDITION,UNAUTHENTICATED. כדי לפתור את הבעיות האלה, צריך לשנות את הבקשה או את הסטטוס או את פרטי הכניסה של האפליקציה. אל תנסו לשלוח את הבקשה שוב בלי לפתור את הבעיה. - שגיאות בשרת: קודים כמו
UNAVAILABLE,INTERNAL,DEADLINE_EXCEEDED,UNKNOWN. ההודעות האלה מצביעות על בעיה זמנית בשירות ה-API.
- שגיאות בצד הלקוח: קודים כמו
- הטמעה של אסטרטגיית ניסיון חוזר
בודקים אם אפשר לנסות שוב לבצע את הפעולה שגרמה לשגיאה, ומשתמשים באסטרטגיה לניסיונות חוזרים.
- מומלץ לנסות שוב רק במקרה של שגיאות שרת זמניות כמו
UNAVAILABLE,DEADLINE_EXCEEDED,INTERNAL,UNKNOWNו-ABORTED. - כדאי להשתמש באלגוריתם של השהיה מעריכית לפני ניסיון חוזר (exponential backoff) כדי להמתין פרקי זמן הולכים וגדלים בין הניסיונות החוזרים. כך אפשר למנוע עומס יתר על שירות שכבר נמצא במצב של עומס. לדוגמה, צריך להמתין שנייה אחת, אחר כך שתי שניות, אחר כך ארבע שניות וכן הלאה, עד שמגיעים למספר המקסימלי של ניסיונות חוזרים או לזמן ההמתנה הכולל.
- מוסיפים כמות קטנה ואקראית של 'רעידות' לעיכובים של ההשהיה לפני ניסיון חוזר כדי למנוע את בעיית 'העדר הרועם', שבה לקוחות רבים מנסים שוב בו-זמנית.
- מומלץ לנסות שוב רק במקרה של שגיאות שרת זמניות כמו
- רישום מפורט ביומן
צריך לרשום ביומן את תגובת השגיאה המלאה, כולל כל מטען הנתונים של הפרטים הרגילים, במיוחד מזהה הבקשה. המידע הזה חיוני לניפוי באגים ולדיווח על בעיות לתמיכה של Google במקרה הצורך.
- שליחת משוב ממשתמשים
בהתבסס על הקודים וההודעות במטענים סטנדרטיים של פרטים, צריך לספק משוב ברור ומועיל למשתמשים באפליקציה. לדוגמה, במקום להגיד רק "An error occurred" (אירעה שגיאה), אפשר להגיד "Transaction ID was missing" (מזהה העסקה היה חסר) או "The account ID of the destination was not found" (מזהה החשבון של היעד לא נמצא).
אם תפעלו לפי ההנחיות האלה, תוכלו לנתח ולטפל ביעילות בשגיאות שמוחזרות על ידי Data Manager API, וכך ליצור אפליקציות יציבות וידידותיות למשתמש.