במדריך הזה מוסבר איך Data Manager API מטפל בשגיאות ואיך הוא מעביר אותן. הבנת המבנה והמשמעות של שגיאות ב-API היא חיונית לבניית אפליקציות חזקות שיכולות לטפל בבעיות בצורה חלקה, החל מקלט לא תקין ועד לזמינות זמנית של שירות.
Data Manager API פועל לפי מודל השגיאות הרגיל של Google API, שמבוסס על קודי סטטוס של gRPC. כל תגובה מה-API שמובילה לשגיאה כוללת אובייקט Status עם:
- קוד שגיאה מספרי.
- הודעת שגיאה.
- פרטי שגיאה נוספים (אופציונלי).
קודי שגיאה קנוניים
ב-Data Manager API נעשה שימוש בקבוצה של קודי שגיאה קנוניים שמוגדרים על ידי gRPC ו-HTTP. הקודים האלה מציינים באופן כללי את סוג השגיאה. תמיד כדאי לבדוק קודם את הקוד הזה כדי להבין את מהות הבעיה.
פרטים נוספים על הקודים האלה זמינים במאמר מדריך לעיצוב API – קודי שגיאה.
מודל של כשל מהיר
ה-Data Manager API משתמש במודל של כשל מהיר. אם בקשה מכילה שגיאות מבניות או אם אימות של רשומה כלשהי נכשל בגלל שדה חובה, הבקשה כולה נכשלת וה-API לא מעבד אף אחד מהנתונים בבקשה.
מודל הכשל המהיר שונה ממודל הכשל החלקי בממשקי API אחרים של Google, כמו Google Ads API ו-Campaign Manager 360 API. במודל של כשל חלקי, הבקשה מצליחה גם אם יש שגיאות בחלק מהרשומות, והתשובה מכילה פרטים על השגיאות ברשומות שנכשלו.
למרות שהמודל של כשל חלקי יכול להיות נוח, הוא כרוך בסיכונים משמעותיים כי הוא לא מתריע באופן יזום על שגיאות – אתם צריכים לבדוק במפורש אם יש שגיאות בכל תשובה. הבעיה היא שאפשר להסתיר בעיות חשובות, כי הבקשה מצליחה גם אם ה-API דוחה הרבה רשומות בבקשה, או אפילו את כולן. אם חלק משמעותי מהרשומות בבקשה מכיל שגיאות, אבל אתם לא בודקים את התגובה, יכול להיות שלא תדעו על בעיות נרחבות בנתונים שלכם, ותגלו אותן רק ימים או שבועות לאחר מכן, כשהתוצאות המצטברות לא יתאימו לציפיות שלכם.
מודל הכשל המהיר מאפשר לכם להימנע מהבעיות האלה כי הוא מתריע על בעיות בנתונים או בשילוב באופן מיידי, כדי שתוכלו לפעול בהתאם.
טיפול בשגיאות
אם הבקשה נכשלת, פועלים לפי השלבים הבאים:
כדי לגלות את סוג השגיאה, בודקים את קוד השגיאה.
- אם משתמשים ב-gRPC, קוד השגיאה נמצא בשדה
codeשלStatus. אם משתמשים בספריית לקוח, יכול להיות שהיא תזרוק סוג ספציפי של חריגה שמתאים לקוד השגיאה. לדוגמה, ספריית הלקוח ל-Java מחזירה את השגיאהcom.google.api.gax.rpc.InvalidArgumentExceptionאם קוד השגיאה הואINVALID_ARGUMENT. - אם משתמשים ב-REST, קוד השגיאה מופיע בתגובת השגיאה בכתובת
error.status, וסטטוס ה-HTTP המתאים מופיע בכתובתerror.code.
- אם משתמשים ב-gRPC, קוד השגיאה נמצא בשדה
בודקים את מטען הנתונים של הפרטים הרגילים כדי למצוא את קוד השגיאה. מטעני הנתונים של הפרטים הרגילים הם קבוצה של הודעות לגבי שגיאות מ-Google APIs. הן מספקות פרטים על השגיאות בצורה מובנית ועקבית. לכל שגיאה מ-Data Manager API יכולות להיות כמה הודעות מטען ייעודי (payload) עם פרטים רגילים. בספריות הלקוח של Data Manager API יש שיטות עזר לקבלת מטען ייעודי (payload) של פרטים רגילים משגיאה.
לא משנה מה קוד השגיאה, מומלץ לבדוק את מטען הנתונים (payload) של
ErrorInfo,RequestInfo,HelpושלLocalizedMessageולתעד אותו.-
ErrorInfoמכיל מידע שאולי לא מופיע במטען ייעודי אחר. RequestInfoכולל את מזהה הבקשה, שיכול לעזור לכם אם תצטרכו לפנות לתמיכה.-
Helpו-LocalizedMessageמכילים קישורים ופרטים אחרים שיעזרו לך לפתור את השגיאה.
בנוסף, מטען הנתונים
BadRequestשימושי לשגיאותINVALID_ARGUMENTכי הוא מספק מידע על השדות שגרמו לשגיאה.-
אזהרות לגבי הטמעה
Data Manager API מקבל כמה שיותר בקשות להטמעת נתונים. אם תכללו נתונים שלא נדרשים, בקשת האימות של השדות האלה לא תיכשל. לדוגמה, אם פריט בעגלת הקניות לא כולל מזהה מוצר של המוכר, ה-API מעבד את שאר הבקשה ומחזיר אזהרה.
תשובה מוצלחת על הטמעה (קוד סטטוס של HTTP 200) כוללת את האזהרות האלה ברשימה field_warnings. כל רשומה היא אובייקט FieldWarning עם השדות הבאים:
fieldהמיקום של השדה בבקשה, בתחביר של נתיב בפורמט snake case.
אם נתיב מצביע על פריט ברשימה (שדה
repeated), האינדקס שלו מוצג בסוגריים מרובעים ([...]) אחרי שם הרשימה.לדוגמה,
events.events[0].cart_data.items[0].merchant_product_idמציין אזהרה שקשורה לפריט הראשון בנתוני עגלת הקניות של האירוע הראשון בבקשה.descriptionהסבר למה הערך שצוין גרם להצגת אזהרה.
reasonערך ה-enum
WarningReasonשמזהה את סוג האזהרה.
דוגמה עם FieldWarning
זו דוגמה לתגובה לבקשת הטמעה מוצלחת שמכילה אזהרה כי חסר מזהה מוצר של מוֹכר לאחד מהפריטים בעגלת הקניות.
{
"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"
}
]
}
מטענים סטנדרטיים של פרטים
אלה המטענים הייעודיים (payloads) הנפוצים ביותר של פרטים סטנדרטיים ב-Data Manager API:
BadRequest
אם בקשה נכשלת עם INVALID_ARGUMENT (קוד סטטוס של HTTP 400), צריך לבדוק את מטען הייעודי (payload) של BadRequest.
ההודעה BadRequest מציינת שבבקשה היו שדות עם ערכים שגויים, או שחסר ערך בשדה חובה. בודקים את הרשימה field_violations בBadRequest כדי לראות באילו שדות יש שגיאות. כל רשומה field_violations כוללת מידע שיעזור לכם לתקן את השגיאה:
fieldהמיקום של השדה בבקשה, בתחביר של נתיב בפורמט snake case.
אם נתיב מצביע על פריט ברשימה (שדה
repeated), האינדקס שלו מוצג בסוגריים מרובעים ([...]) אחרי שם הרשימה.לדוגמה,
destinations[0].operating_account.account_idהואaccount_idב-operating_accountשל הפריט הראשון ברשימהdestinations.descriptionהסבר למה הערך גרם לשגיאה.
reasonהספירה
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"
}
]
}
]
}
}
RequestInfo
בכל פעם שבקשה נכשלת, בודקים את מטען הייעודי (payload) של RequestInfo. RequestInfo
כולל את request_id שמזהה באופן ייחודי את בקשת ה-API.
{
"@type": "type.googleapis.com/google.rpc.RequestInfo",
"requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}
כשרושמים שגיאות ביומן או פונים לתמיכה, חשוב לכלול את מזהה הבקשה כדי לאבחן בעיות.
ErrorInfo
כדאי לבדוק אם מופיעה ההודעה ErrorInfo כדי לאחזר מידע נוסף שאולי לא נכלל במטענים הייעודיים (payloads) האחרים של הפרטים הסטנדרטיים. המטען הייעודי ErrorInfo(Payload) מכיל מפת metadata עם מידע על השגיאה.
לדוגמה, כאן מופיע ErrorInfo של כשל PERMISSION_DENIED שנגרם כתוצאה משימוש בפרטי כניסה לפרויקט בענן של Google Cloud שבו Data Manager 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.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"
}
},
...
]
}
}
Help וגם LocalizedMessage
כדאי לבדוק את מטען הנתונים Help ו-LocalizedMessage כדי לקבל קישורים למסמכים ולהודעות שגיאה מותאמות לשפה המקומית, שיעזרו לכם להבין את השגיאה ולתקן אותה.
לדוגמה, הנה Help ו-LocalizedMessage של PERMISSION_DENIEDשגיאה שנגרמת משימוש בפרטי כניסה לפרויקט בענן ב-Google Cloud שבו Data Manager API לא מופעל. Help מטען הייעודי (payload) מציג את כתובת ה-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.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"
}
]
},
...
]
}
}
גישה לפרטי השגיאה
אם אתם משתמשים באחת מספריות הלקוח, תוכלו להשתמש בשיטות העזר כדי לקבל את מטען הייעודי (payload) של הפרטים הרגילים.
.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...
// 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'...
// 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 = invalidArgumentException.getErrorDetails().getRequestInfo();
if (requestInfo != null) {
String requestId = requestInfo.getRequestId();
// Log the requestId...
}
...
}
שיטות מומלצות לטיפול בשגיאות
כדי ליצור אפליקציות עמידות, כדאי להטמיע את השיטות המומלצות הבאות.
- בדיקת פרטי השגיאה
- תמיד כדאי לחפש אחת ממטען הנתונים של הפרטים הרגילים, כמו
BadRequest. כל מטען ייעודי סטנדרטי של פרטים מכיל מידע שיעזור לכם להבין את הסיבה לשגיאה. - הבחנה בין שגיאות בצד הלקוח לבין שגיאות בצד השרת
בודקים אם השגיאה נגרמת בגלל בעיה בהטמעה (הלקוח) או ב-API (השרת).
- שגיאות בצד הלקוח: קודים כמו
INVALID_ARGUMENT, NOT_FOUND,PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED. כדי לפתור את הבעיות האלה, צריך לשנות את הבקשה או את מצב האפליקציה או את פרטי הכניסה שלה. אל תנסו לשלוח את הבקשה שוב בלי לפתור את הבעיה. - שגיאות בשרת: קודים כמו
UNAVAILABLE,INTERNAL,DEADLINE_EXCEEDED,UNKNOWN. ההודעות האלה מצביעות על בעיה זמנית בשירות ה-API.
- שגיאות בצד הלקוח: קודים כמו
- הטמעה של אסטרטגיה של ניסיון חוזר
בודקים אם אפשר לנסות שוב לבצע את הפעולה שגרמה לשגיאה, ומשתמשים באסטרטגיה לניסיונות חוזרים.
- מומלץ לנסות שוב רק במקרה של שגיאות שרת זמניות כמו
UNAVAILABLE,DEADLINE_EXCEEDED,INTERNAL,UNKNOWNו-ABORTED. - צריך להשתמש באלגוריתם של השהיה מעריכית לפני ניסיון חוזר כדי להמתין פרקי זמן ארוכים יותר בין הניסיונות החוזרים. כך אפשר להימנע מעומס יתר על שירות שכבר נמצא במצב של עומס. לדוגמה, צריך להמתין שנייה אחת, אחר כך שתי שניות, אחר כך ארבע שניות, ולהמשיך עד למספר המקסימלי של ניסיונות חוזרים או עד לזמן ההמתנה הכולל.
- מוסיפים כמות קטנה ואקראית של "רעידות" להשהיות של ה-backoff כדי למנוע את בעיית "העדר הרועם", שבה לקוחות רבים מנסים שוב בו-זמנית.
- מומלץ לנסות שוב רק במקרה של שגיאות שרת זמניות כמו
- רישום מפורט ביומן
רישום ביומן של תגובת השגיאה המלאה, כולל כל מטען הפרטים הסטנדרטי, במיוחד מזהה הבקשה. המידע הזה חיוני לניפוי באגים ולדיווח על בעיות לתמיכה של Google, אם צריך.
- שליחת משוב מהמשתמשים
בהתבסס על הקודים וההודעות במטענים של פרטים רגילים, צריך לספק משוב ברור ומועיל למשתמשים באפליקציה. לדוגמה, במקום "An error occurred" (אירעה שגיאה), אפשר לומר "Transaction ID was missing" (מזהה העסקה היה חסר) או "The account ID of the destination was not found" (מזהה החשבון של היעד לא נמצא).
אם תפעלו לפי ההנחיות האלה, תוכלו לאבחן ולטפל ביעילות בשגיאות שמוחזרות על ידי Data Manager API, וכך ליצור אפליקציות יציבות וידידותיות יותר למשתמשים.