טיפים בנושא ביצועים

במסמך הזה מפורטות כמה שיטות שיכולות לעזור לכם לשפר את ביצועי האפליקציה. במקרים מסוימים, נשתמש בדוגמאות מממשקי API אחרים או מממשקי API כלליים אחרים כדי להדגים את הרעיונות שמוצגים. עם זאת, אותם מושגים רלוונטיים ל-Google Wallet API.

דחיסה באמצעות gzip

דרך קלה ונוחה לצמצם את רוחב הפס הדרוש לכל בקשה היא להפעיל דחיסת נתונים מסוג gzip. על אף שהפעולה הזו דורשת זמן CPU (מעבד) נוסף כדי לבטל את הדחיסה של התוצאות, היא משתלמת מאוד בזכות הצמצום בעלויות של הרשת.

כדי לקבל תגובה בקידוד gzip, צריך לבצע שני דברים: להגדיר כותרת Accept-Encoding ולשנות את סוכן המשתמש כך שיכיל את המחרוזת gzip. הנה דוגמה לכותרות HTTP במבנה תקין להפעלת דחיסת נתונים מסוג gzip:

Accept-Encoding: gzip
User-Agent: my program (gzip)

עבודה עם משאבים חלקיים

דרך נוספת לשפר את ביצועי הקריאות ל-API היא לשלוח ולקבל רק את החלק של הנתונים הרצויים. הפעולה הזו מאפשרת לאפליקציה להימנע מהעברה, ניתוח ואחסון של שדות לא נחוצים, כדי להשתמש במשאבים כמו רשת, מעבד (CPU) וזיכרון בצורה יעילה יותר.

יש שני סוגים של בקשות חלקיות:

  • תגובה חלקית: בקשה שבה מציינים אילו שדות לכלול בתשובה (משתמשים בפרמטר הבקשה fields).
  • תיקון: בקשת עדכון שבה שולחים רק את השדות שרוצים לשנות (יש להשתמש בפועל PATCH של HTTP).

בסעיפים הבאים מפורט מידע נוסף על שליחת בקשות חלקיות.

תשובה חלקית

כברירת מחדל, השרת שולח חזרה ייצוג מלא של משאב לאחר עיבוד בקשות. כדי לשפר את הביצועים, אפשר לבקש מהשרת לשלוח רק את השדות שנחוצים לכם ולקבל במקום זאת תגובה חלקית.

כדי לבקש תשובה חלקית, משתמשים בפרמטר fields של הבקשה כדי לציין את השדות שרוצים להחזיר. אפשר להשתמש בפרמטר הזה בכל בקשה שמחזירה נתוני תגובה.

חשוב לשים לב שהפרמטר fields משפיע רק על נתוני התגובות. היא לא משפיעה על הנתונים שעליך לשלוח, אם בכלל. כדי להפחית את כמות הנתונים ששולחים כשמשנים משאבים, אפשר להשתמש בבקשת patch.

דוגמה

בדוגמה הבאה ניתן לראות את השימוש בפרמטר fields עם "הדגמה" כללי (פיקטיבי) API.

בקשה פשוטה: בקשת ה-HTTP הזו GET משמיטה את הפרמטר fields ומחזירה את המשאב המלא.

https://www.googleapis.com/demo/v1

תגובה מלאה למשאבים: נתוני המשאבים המלאים כוללים את השדות הבאים, ועוד רבים אחרים שהושמטו עקב קיצור.

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

בקשה לתגובה חלקית: הבקשה הבאה למשאב הזה משתמשת בפרמטר fields כדי לצמצם באופן משמעותי את כמות הנתונים שמוחזרים.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

תגובה חלקית: בתגובה לבקשה שלמעלה, השרת שולח תגובה שמכילה רק את הסוג הרלוונטי עם מערך פריטים מצומצם שכולל רק את כותרת ה-HTML ואת אורך המאפיינים של כל פריט.

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

הערה: התגובה היא אובייקט JSON שכולל רק את השדות שנבחרו ואת האובייקטים המצורפים של ההורה.

בהמשך מופיעים פרטים על הפורמט של הפרמטר fields, ולאחר מכן פרטים נוספים על מה בדיוק שמוחזר בתשובה.

סיכום התחביר של הפרמטרים של השדות

הפורמט של ערך הפרמטר של הבקשה fields מבוסס באופן חלש על תחביר XPath. מידע לגבי התחביר הנתמך מופיע בהמשך, ודוגמאות נוספות מופיעות בקטע הבא.

  • משתמשים ברשימה שמופרדת בפסיקים כדי לבחור כמה שדות.
  • אפשר להשתמש ב-a/b כדי לבחור שדה b שנמצא בתוך השדה a; צריך להשתמש בפונקציה a/b/c כדי לבחור שדה c שנמצא בתוך b.

    חריג לכלל הזה: תשובות מ-API שמשתמשות ב-"data" [נתונים] רכיבי wrapper, שבהם התגובה מוצבת בתוך אובייקט data שנראה כמו data: { ... }, לא כוללים את "data" במפרט fields. הכללת אובייקט הנתונים עם מפרט שדות כמו data/a/b תגרום לשגיאה. במקום זאת, צריך פשוט להשתמש במפרט fields כמו a/b.

  • משתמשים בבורר משנה כדי לבקש קבוצה של שדות משנה ספציפיים של מערכים או אובייקטים על ידי הוספת ביטויים בסוגריים "( )".

    לדוגמה: fields=items(id,author/email) מחזירה רק את מזהה הפריט ואת כתובת האימייל של המחבר עבור כל רכיב במערך הפריטים. אפשר גם לציין שדה משנה יחיד, שבו fields=items(id) שווה ל-fields=items/id.

  • אם צריך, משתמשים בתווים כלליים לחיפוש של שדות.

    לדוגמה: fields=items/pagemap/* בוחר את כל האובייקטים במפת דפים.

דוגמאות נוספות לשימוש בפרמטר של השדות

הדוגמאות הבאות כוללות תיאורים של האופן שבו ערך הפרמטר fields משפיע על התגובה.

הערה: בדומה לכל ערכי הפרמטרים של שאילתה, ערך הפרמטר fields חייב להיות מקודד בכתובת ה-URL. כדי לשפר את הקריאות, הדוגמאות במסמך הזה לא כוללות את הקידוד.

מזהים את השדות שרוצים להחזיר, או בוחרים את השדות שנבחרו.
ערך הפרמטר fields של הבקשה הוא רשימת שדות שמופרדים בפסיקים, וכל שדה מצוין ביחס לשורש של התגובה. לכן, אם אתם מבצעים פעולת רשימה, התגובה היא אוסף, ובדרך כלל כוללת מערך של משאבים. אם מבצעים פעולה שמחזירה משאב יחיד, השדות מצוינים ביחס למשאב הזה. אם השדה שאתם בוחרים הוא (או חלק ממנו) מערך, השרת מחזיר את החלק שנבחר מתוך כל הרכיבים במערך.

הנה כמה דוגמאות ברמת האוסף:
דוגמאות השפעה
items מחזירה את כל הרכיבים במערך הפריטים, כולל כל השדות בכל רכיב, אבל לא שדות אחרים.
etag,items הפונקציה מחזירה את השדה etag וגם את כל הרכיבים במערך הפריטים.
items/title הפונקציה מחזירה רק את השדה title לכל הרכיבים במערך הפריטים.

כשמוחזר שדה מקונן, התגובה כוללת את האובייקטים המצורפים של ההורה. שדות ההורה לא כוללים שדות צאצא אחרים, אלא אם הם גם נבחרו באופן מפורש.
context/facets/label מחזירה רק את השדה label לכל האיברים במערך facets, שממוקם בעצמו מתחת לאובייקט context.
items/pagemap/*/title לכל רכיב במערך הפריטים, הפונקציה מחזירה רק את השדה title (אם קיים) של כל האובייקטים שהם צאצאים של pagemap.

הנה כמה דוגמאות ברמת המשאב:
דוגמאות השפעה
title הפונקציה מחזירה את השדה title של המשאב המבוקש.
author/uri מחזירה את שדה המשנה uri של האובייקט author במשאב המבוקש.
links/*/href
מחזירה את השדה href של כל האובייקטים שהם צאצאים של links.
ניתן לבקש רק חלקים משדות ספציפיים באמצעות בחירות משנה.
כברירת מחדל, אם הבקשה מציינת שדות מסוימים, השרת מחזיר את האובייקטים או את רכיבי המערך בשלמותם. אפשר להגדיר תשובה שכוללת רק שדות משנה מסוימים. הפעולה הזו מתבצעת באמצעות '( )' של בחירת המשנה, כמו בדוגמה הבאה.
דוגמה השפעה
items(title,author/uri) מחזירה רק את הערכים של title ושל uri של המחבר לכל רכיב במערך הפריטים.

טיפול בתשובות חלקיות

אחרי ששרת מעבד בקשה חוקית שכוללת את פרמטר השאילתה fields, הוא שולח חזרה את קוד הסטטוס 200 OK של HTTP, יחד עם הנתונים המבוקשים. אם בפרמטר השאילתה fields יש שגיאה או שהוא לא תקין מסיבה אחרת, השרת מחזיר קוד הסטטוס 400 Bad Request של HTTP, יחד עם הודעת שגיאה שמפרטת למשתמשים מה הבעיה בבחירת השדות (לדוגמה, "Invalid field selection a/b").

זוהי דוגמה לתשובה חלקית שמוצגת בקטע המבוא שלמעלה. הבקשה משתמשת בפרמטר fields כדי לציין אילו שדות יוחזרו.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

התשובה החלקית נראית כך:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

הערה: לממשקי API שתומכים בפרמטרים של שאילתה לעימוד נתונים (לדוגמה, maxResults ו-nextPageToken), אפשר להשתמש בפרמטרים האלה כדי לצמצם את התוצאות של כל שאילתה לגודל שאפשר לנהל. אחרת, ייתכן שהביצועים יהיו טובים יותר אם נקבל תגובה חלקית.

תיקון (עדכון חלקי)

תוכלו גם להימנע משליחת נתונים מיותרים כשמשנים משאבים. כדי לשלוח נתונים מעודכנים רק בשדות הספציפיים שמשנים, משתמשים בפועל PATCH HTTP. הסמנטיקה של התיקונים שמתוארת במסמך הזה שונה (ופשוטה יותר) מכפי שהיא הייתה בהטמעת GData הקודמת של עדכון חלקי.

הדוגמה הקצרה הבאה מראה איך השימוש בתיקון מצמצם את הנתונים שצריך לשלוח כדי לבצע עדכון קטן.

דוגמה

בדוגמה הזו מוצגת בקשת תיקון פשוטה לעדכון השם של "הדגמה" גנרי (בדיוני) בלבד משאב API. למשאב יש גם הערה, קבוצת מאפיינים, סטטוס ושדות רבים אחרים, אבל הבקשה הזו שולחת רק את השדה title, כי הוא השדה היחיד ששונה:

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

תשובה:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

השרת מחזיר קוד הסטטוס 200 OK, יחד עם הייצוג המלא של המשאב המעודכן. מכיוון שרק השדה title נכלל בבקשת התיקון, זה הערך היחיד ששונה מבעבר.

הערה: אם אתם משתמשים בפרמטר תגובה חלקית fields בשילוב עם patch, אפשר להגביר עוד יותר את היעילות של בקשות העדכון. בקשת תיקון רק מקטינה את גודל הבקשה. תשובה חלקית מקטינה את גודל התגובה. לכן, כדי להפחית את כמות הנתונים שנשלחים בשני הכיוונים, צריך להשתמש בבקשת תיקון עם הפרמטר fields.

הסמנטיקה של בקשת התיקון

הגוף של בקשת התיקון כולל רק את שדות המשאבים שרוצים לשנות. כשמציינים שדה, צריך לכלול את כל האובייקטים של ההורה המצורפים, בדיוק כמו שתבניות ההורה המצורפים מוחזרות עם תגובה חלקית. הנתונים ששונו ששלחתם ימוזגו עם הנתונים של אובייקט ההורה, אם יש אובייקט כזה.

  • הוספה: כדי להוסיף שדה שלא קיים כבר, מציינים את השדה החדש ואת הערך שלו.
  • שינוי: כדי לשנות את הערך של שדה קיים, מציינים את השדה ומגדירים אותו לערך החדש.
  • מחיקה: כדי למחוק שדה, מציינים את השדה ומגדירים אותו לערך null. לדוגמה, "comment": null. אפשר גם למחוק אובייקט שלם (אם ניתן לשנות אותו) על ידי הגדרתו ל-null. אם משתמשים בספריית הלקוח של Java API, צריך להשתמש ב-Data.NULL_STRING במקום זאת. עבור לפרטים נוספים, ראו JSON null.

הערה לגבי מערכים: בקשות תיקון שמכילות מערכים מחליפים את המערך הקיים במערך שסיפקתם. לא ניתן לשנות, להוסיף או למחוק פריטים במערך בצורה חלקית.

שימוש בתיקון במחזור של קריאה-שינוי-כתיבה

מומלץ להתחיל באחזור תגובה חלקית עם הנתונים שרוצים לשנות. זה חשוב במיוחד למשאבים שמשתמשים ב-ETags, כי צריך לציין את ערך ה-ETag הנוכחי בכותרת ה-HTTP If-Match כדי לעדכן את המשאב בהצלחה. אחרי שתקבלו את הנתונים, תוכלו לשנות את הערכים שרוצים לשנות ולשלוח חזרה את הייצוג החלקי שהשתנה עם בקשת תיקון. הנה דוגמה שמניחה שמשאב ההדגמה משתמש ב-ETags:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

זו התגובה החלקית:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

בקשת התיקון הבאה מבוססת על התגובה הזו. כמו שמוצג בהמשך, הוא גם משתמש בפרמטר fields כדי להגביל את הנתונים שמוחזרים בתגובת התיקון:

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

השרת מגיב עם קוד מצב HTTP של 200 OK, והייצוג החלקי של המשאב המעודכן:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

פיתוח של בקשת תיקון באופן ישיר

עבור בקשות תיקון מסוימות, צריך לבסס אותן על הנתונים שאחזרתם בעבר. לדוגמה, אם רוצים להוסיף פריט למערך ולא לאבד אף אחד מהאלמנטים הקיימים של המערך, קודם צריך לקבל את הנתונים הקיימים. באופן דומה, אם API משתמש ב-ETags, צריך לשלוח עם הבקשה את ערך ה-ETag הקודם כדי לעדכן את המשאב בהצלחה.

הערה: אפשר להשתמש בכותרת HTTP של "If-Match: *" כדי לאלץ מעבר תיקון בזמן שימוש ב-ETags. אם עושים זאת, אין צורך לקרוא את ההודעה לפני הכתיבה.

עם זאת, במצבים אחרים ניתן ליצור את בקשת התיקון באופן ישיר, בלי לאחזר קודם את הנתונים הקיימים. לדוגמה, אתם יכולים להגדיר בקלות בקשת תיקון שמעדכנת שדה לערך חדש או מוסיפה שדה חדש. לדוגמה:

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

בבקשה הזו, אם בשדה ההערה יש ערך קיים, הערך החדש יחליף אותו. אחרת הוא יוגדר עם הערך החדש. באופן דומה, אם היה מאפיין נפח, הערך שלו יוחלף. אחרת, הוא נוצר. אם השדה מוגדר, הוא יוסר.

טיפול בתגובה לתיקון

אחרי עיבוד בקשת תיקון חוקית, ה-API מחזיר קוד תגובת HTTP 200 OK עם הייצוג המלא של המשאב שהשתנה. אם ה-API משתמש ב-ETags, השרת מעדכן את ערכי ה-ETag לאחר שהוא מעבד בהצלחה בקשת תיקון, בדיוק כמו ב-PUT.

בקשת התיקון מחזירה את ייצוג המשאב כולו, אלא אם משתמשים בפרמטר fields כדי לצמצם את כמות הנתונים שהיא מחזירה.

אם בקשת תיקון מובילה למצב משאב חדש שהוא לא חוקי מבחינה תחבירית או סמנטית, השרת יחזיר קוד סטטוס HTTP 400 Bad Request או 422 Unprocessable Entity, ומצב המשאב נשאר ללא שינוי. לדוגמה, אם תנסו למחוק את הערך של שדה חובה, השרת יחזיר שגיאה.

סימון חלופי כאשר אין תמיכה בפועל PATCH HTTP

אם חומת האש לא מאפשרת בקשות HTTP PATCH, צריך לשלוח בקשת POST HTTP ולהגדיר את כותרת השינוי לערך PATCH, כמו בדוגמה הבאה:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

ההבדל בין תיקון לעדכון

בפועל, כששולחים נתונים לבקשת עדכון שמשתמשת בפועל PUT HTTP, צריך לשלוח רק את השדות שהם שדות חובה או שדות אופציונליים. אם שולחים ערכים לשדות שהוגדרו על ידי השרת, המערכת מתעלמת מהם. יכול להיות שזו דרך נוספת לבצע עדכון חלקי, אבל לגישה הזו יש כמה מגבלות. בעדכונים שמשתמשים בפועל HTTP PUT, הבקשה תיכשל אם לא תספקו את הפרמטרים הנדרשים. אם לא תספקו פרמטרים אופציונליים, הבקשה תיכשל.

הרבה יותר בטוח להשתמש בתיקון מסיבה זו. צריך לספק נתונים רק עבור השדות שרוצים לשנות. שדות שאתה משמיט לא יימחקו. היוצא מן הכלל היחיד לכלל הזה הוא כאשר חוזרים על רכיבים או מערכים: אם משמיטים את כולם, הם נשארים בדיוק כמו שהם; אם מציינים אחד מהם, הקבוצה כולה תוחלף בקבוצה שסיפקתם.

בקשות אצווה ל-Google Wallet

Google Wallet API תומך בקיבוץ קריאות ל-API יחד כדי לצמצם את המספר הקשרים שהלקוח צריך לבצע. לקבלת מידע נוסף על בקשות באצווה ועל למבנה התגובות, ראו פרטי אצווה.

הקוד לדוגמה הבא מדגים בקשות באצווה. Java ו-PHP לדוגמה משתמשים ב-Google Wallet ספריות כדי לפשט את יצירת המחלקות והאובייקטים.

Java

כדי להתחיל בשילוב ב-Java, קראו את דוגמאות קוד ב-GitHub.

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 */
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
  // Create the batch request client
  BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));

  // The callback will be invoked for each request in the batch
  JsonBatchCallback<LoyaltyObject> callback =
      new JsonBatchCallback<LoyaltyObject>() {
        // Invoked if the request was successful
        public void onSuccess(LoyaltyObject response, HttpHeaders responseHeaders) {
          System.out.println("Batch insert response");
          System.out.println(response.toString());
        }

        // Invoked if the request failed
        public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
          System.out.println("Error Message: " + e.getMessage());
        }
      };

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++) {
    // Generate a random object suffix
    String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
    LoyaltyObject batchObject =
        new LoyaltyObject()
            .setId(String.format("%s.%s", issuerId, objectSuffix))
            .setClassId(String.format("%s.%s", issuerId, classSuffix))
            .setState("ACTIVE")
            .setHeroImage(
                new Image()
                    .setSourceUri(
                        new ImageUri()
                            .setUri(
                                "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                    .setContentDescription(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString()
                                    .setLanguage("en-US")
                                    .setValue("Hero image description"))))
            .setTextModulesData(
                    List.of(
                            new TextModuleData()
                                    .setHeader("Text module header")
                                    .setBody("Text module body")
                                    .setId("TEXT_MODULE_ID")))
            .setLinksModuleData(
                new LinksModuleData()
                    .setUris(
                        Arrays.asList(
                            new Uri()
                                .setUri("http://maps.google.com/")
                                .setDescription("Link module URI description")
                                .setId("LINK_MODULE_URI_ID"),
                            new Uri()
                                .setUri("tel:6505555555")
                                .setDescription("Link module tel description")
                                .setId("LINK_MODULE_TEL_ID"))))
            .setImageModulesData(
                    List.of(
                            new ImageModuleData()
                                    .setMainImage(
                                            new Image()
                                                    .setSourceUri(
                                                            new ImageUri()
                                                                    .setUri(
                                                                            "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                                                    .setContentDescription(
                                                            new LocalizedString()
                                                                    .setDefaultValue(
                                                                            new TranslatedString()
                                                                                    .setLanguage("en-US")
                                                                                    .setValue("Image module description"))))
                                    .setId("IMAGE_MODULE_ID")))
            .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
            .setLocations(
                    List.of(
                            new LatLongPoint()
                                    .setLatitude(37.424015499999996)
                                    .setLongitude(-122.09259560000001)))
            .setAccountId("Account ID")
            .setAccountName("Account name")
            .setLoyaltyPoints(
                new LoyaltyPoints()
                    .setLabel("Points")
                    .setBalance(new LoyaltyPointsBalance().setInt(800)));

    service.loyaltyobject().insert(batchObject).queue(batch, callback);
  }

  // Invoke the batch API calls
  batch.execute();
}

PHP

כדי להתחיל את השילוב עם PHP, קראו את דוגמאות קוד ב-GitHub.

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for the pass class.
 */
public function batchCreateObjects(string $issuerId, string $classSuffix)
{
  // Update the client to enable batch requests
  $this->client->setUseBatch(true);
  $batch = $this->service->createBatch();

  // Example: Generate three new pass objects
  for ($i = 0; $i < 3; $i++) {
    // Generate a random object suffix
    $objectSuffix = preg_replace('/[^\w.-]/i', '_', uniqid());

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
    $batchObject = new LoyaltyObject([
      'id' => "{$issuerId}.{$objectSuffix}",
      'classId' => "{$issuerId}.{$classSuffix}",
      'state' => 'ACTIVE',
      'heroImage' => new Image([
        'sourceUri' => new ImageUri([
          'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        ]),
        'contentDescription' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => 'Hero image description'
          ])
        ])
      ]),
      'textModulesData' => [
        new TextModuleData([
          'header' => 'Text module header',
          'body' => 'Text module body',
          'id' => 'TEXT_MODULE_ID'
        ])
      ],
      'linksModuleData' => new LinksModuleData([
        'uris' => [
          new Uri([
            'uri' => 'http://maps.google.com/',
            'description' => 'Link module URI description',
            'id' => 'LINK_MODULE_URI_ID'
          ]),
          new Uri([
            'uri' => 'tel:6505555555',
            'description' => 'Link module tel description',
            'id' => 'LINK_MODULE_TEL_ID'
          ])
        ]
      ]),
      'imageModulesData' => [
        new ImageModuleData([
          'mainImage' => new Image([
            'sourceUri' => new ImageUri([
              'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            ]),
            'contentDescription' => new LocalizedString([
              'defaultValue' => new TranslatedString([
                'language' => 'en-US',
                'value' => 'Image module description'
              ])
            ])
          ]),
          'id' => 'IMAGE_MODULE_ID'
        ])
      ],
      'barcode' => new Barcode([
        'type' => 'QR_CODE',
        'value' => 'QR code value'
      ]),
      'locations' => [
        new LatLongPoint([
          'latitude' => 37.424015499999996,
          'longitude' =>  -122.09259560000001
        ])
      ],
      'accountId' => 'Account ID',
      'accountName' => 'Account name',
      'loyaltyPoints' => new LoyaltyPoints([
        'balance' => new LoyaltyPointsBalance([
          'int' => 800
        ])
      ])
    ]);

    $batch->add($this->service->loyaltyobject->insert($batchObject));
  }

  // Make the batch request
  $batchResponse = $batch->execute();

  print "Batch insert response\n";
  foreach ($batchResponse as $key => $value) {
    if ($value instanceof Google_Service_Exception) {
      print_r($value->getErrors());
      continue;
    }
    print "{$value->getId()}\n";
  }
}

Python

כדי להתחיל את השילוב ב-Python, קראו את דוגמאות קוד ב-GitHub.

def batch_create_objects(self, issuer_id: str, class_suffix: str):
    """Batch create Google Wallet objects from an existing class.

    The request body will be a multiline string. See below for information.

    https://cloud.google.com/compute/docs/api/how-tos/batch#example

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for this pass class.
    """
    batch = self.client.new_batch_http_request()

    # Example: Generate three new pass objects
    for _ in range(3):
        # Generate a random object suffix
        object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')

        # See link below for more information on required properties
        # https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
        batch_object = {
            'id': f'{issuer_id}.{object_suffix}',
            'classId': f'{issuer_id}.{class_suffix}',
            'state': 'ACTIVE',
            'heroImage': {
                'sourceUri': {
                    'uri':
                        'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Hero image description'
                    }
                }
            },
            'textModulesData': [{
                'header': 'Text module header',
                'body': 'Text module body',
                'id': 'TEXT_MODULE_ID'
            }],
            'linksModuleData': {
                'uris': [{
                    'uri': 'http://maps.google.com/',
                    'description': 'Link module URI description',
                    'id': 'LINK_MODULE_URI_ID'
                }, {
                    'uri': 'tel:6505555555',
                    'description': 'Link module tel description',
                    'id': 'LINK_MODULE_TEL_ID'
                }]
            },
            'imageModulesData': [{
                'mainImage': {
                    'sourceUri': {
                        'uri':
                            'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                    },
                    'contentDescription': {
                        'defaultValue': {
                            'language': 'en-US',
                            'value': 'Image module description'
                        }
                    }
                },
                'id': 'IMAGE_MODULE_ID'
            }],
            'barcode': {
                'type': 'QR_CODE',
                'value': 'QR code'
            },
            'locations': [{
                'latitude': 37.424015499999996,
                'longitude': -122.09259560000001
            }],
            'accountId': 'Account id',
            'accountName': 'Account name',
            'loyaltyPoints': {
                'label': 'Points',
                'balance': {
                    'int': 800
                }
            }
        }

        batch.add(self.client.loyaltyobject().insert(body=batch_object))

    # Invoke the batch API calls
    response = batch.execute()

    print('Batch complete')

C#‎

כדי להתחיל את השילוב ב-C#, עיינו דוגמאות קוד ב-GitHub.

/// <summary>
/// Batch create Google Wallet objects from an existing class.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
public async void BatchCreateObjects(string issuerId, string classSuffix)
{
  // The request body will be a multiline string
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch//example
  string data = "";

  HttpClient httpClient = new HttpClient();
  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer",
    credentials.GetAccessTokenForRequestAsync().Result
  );

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++)
  {
    // Generate a random object suffix
    string objectSuffix = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
    LoyaltyObject batchObject = new LoyaltyObject
    {
      Id = $"{issuerId}.{objectSuffix}",
      ClassId = $"{issuerId}.{classSuffix}",
      State = "ACTIVE",
      HeroImage = new Image
      {
        SourceUri = new ImageUri
        {
          Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
        },
        ContentDescription = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "Hero image description"
          }
        }
      },
      TextModulesData = new List<TextModuleData>
      {
        new TextModuleData
        {
          Header = "Text module header",
          Body = "Text module body",
          Id = "TEXT_MODULE_ID"
        }
      },
      LinksModuleData = new LinksModuleData
      {
        Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
        {
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "http://maps.google.com/",
            Description = "Link module URI description",
            Id = "LINK_MODULE_URI_ID"
          },
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "tel:6505555555",
            Description = "Link module tel description",
            Id = "LINK_MODULE_TEL_ID"
          }
        }
      },
      ImageModulesData = new List<ImageModuleData>
      {
        new ImageModuleData
        {
          MainImage = new Image
          {
            SourceUri = new ImageUri
            {
              Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
            },
            ContentDescription = new LocalizedString
            {
              DefaultValue = new TranslatedString
              {
                Language = "en-US",
                Value = "Image module description"
              }
            }
          },
          Id = "IMAGE_MODULE_ID"
        }
      },
      Barcode = new Barcode
      {
        Type = "QR_CODE",
        Value = "QR code"
      },
      Locations = new List<LatLongPoint>
      {
        new LatLongPoint
        {
          Latitude = 37.424015499999996,
          Longitude = -122.09259560000001
        }
      },
      AccountId = "Account id",
      AccountName = "Account name",
      LoyaltyPoints = new LoyaltyPoints
      {
        Label = "Points",
        Balance = new LoyaltyPointsBalance
        {
          Int__ = 800
        }
      }
    };

    data += "--batch_createobjectbatch\n";
    data += "Content-Type: application/json\n\n";
    data += "POST /walletobjects/v1/loyaltyObject/\n\n";

    data += JsonConvert.SerializeObject(batchObject) + "\n\n";
  }
  data += "--batch_createobjectbatch--";

  // Invoke the batch API calls
  HttpRequestMessage batchObjectRequest = new HttpRequestMessage(
      HttpMethod.Post,
      "https://walletobjects.googleapis.com/batch");

  batchObjectRequest.Content = new StringContent(data);
  batchObjectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(
      "multipart/mixed");
  // `boundary` is the delimiter between API calls in the batch request
  batchObjectRequest.Content.Headers.ContentType.Parameters.Add(
      new NameValueHeaderValue("boundary", "batch_createobjectbatch"));

  HttpResponseMessage batchObjectResponse = httpClient.Send(
      batchObjectRequest);

  string batchObjectContent = await batchObjectResponse
      .Content
      .ReadAsStringAsync();

  Console.WriteLine("Batch insert response");
  Console.WriteLine(batchObjectContent);
}

Node.js

כדי להתחיל את השילוב ב-Node, צריך לעיין ב דוגמאות קוד ב-GitHub.

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for this pass class.
 */
async batchCreateObjects(issuerId, classSuffix) {
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch#example
  let data = '';
  let batchObject;
  let objectSuffix;

  // Example: Generate three new pass objects
  for (let i = 0; i < 3; i++) {
    // Generate a random object suffix
    objectSuffix = uuidv4().replace('[^\w.-]', '_');

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
    batchObject = {
      'id': `${issuerId}.${objectSuffix}`,
      'classId': `${issuerId}.${classSuffix}`,
      'state': 'ACTIVE',
      'heroImage': {
        'sourceUri': {
          'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        },
        'contentDescription': {
          'defaultValue': {
            'language': 'en-US',
            'value': 'Hero image description'
          }
        }
      },
      'textModulesData': [
        {
          'header': 'Text module header',
          'body': 'Text module body',
          'id': 'TEXT_MODULE_ID'
        }
      ],
      'linksModuleData': {
        'uris': [
          {
            'uri': 'http://maps.google.com/',
            'description': 'Link module URI description',
            'id': 'LINK_MODULE_URI_ID'
          },
          {
            'uri': 'tel:6505555555',
            'description': 'Link module tel description',
            'id': 'LINK_MODULE_TEL_ID'
          }
        ]
      },
      'imageModulesData': [
        {
          'mainImage': {
            'sourceUri': {
              'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            },
            'contentDescription': {
              'defaultValue': {
                'language': 'en-US',
                'value': 'Image module description'
              }
            }
          },
          'id': 'IMAGE_MODULE_ID'
        }
      ],
      'barcode': {
        'type': 'QR_CODE',
        'value': 'QR code'
      },
      'locations': [
        {
          'latitude': 37.424015499999996,
          'longitude': -122.09259560000001
        }
      ],
      'accountId': 'Account id',
      'accountName': 'Account name',
      'loyaltyPoints': {
        'label': 'Points',
        'balance': {
          'int': 800
        }
      }
    };

    data += '--batch_createobjectbatch\n';
    data += 'Content-Type: application/json\n\n';
    data += 'POST /walletobjects/v1/loyaltyObject\n\n';

    data += JSON.stringify(batchObject) + '\n\n';
  }
  data += '--batch_createobjectbatch--';

  // Invoke the batch API calls
  let response = await this.client.context._options.auth.request({
    url: 'https://walletobjects.googleapis.com/batch',
    method: 'POST',
    data: data,
    headers: {
      // `boundary` is the delimiter between API calls in the batch request
      'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch'
    }
  });

  console.log('Batch insert response');
  console.log(response);
}

Go

כדי להתחיל את השילוב עם Go, אפשר לעיין בדוגמאות הקוד המלאות שלנו ב-GitHub דוגמאות קוד ב-GitHub.

// Batch create Google Wallet objects from an existing class.
func (d *demoLoyalty) batchCreateObjects(issuerId, classSuffix string) {
	data := ""
	for i := 0; i < 3; i++ {
		objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")

		loyaltyObject := new(walletobjects.LoyaltyObject)
		loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
		loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
		loyaltyObject.AccountName = "Account name"
		loyaltyObject.AccountId = "Account id"
		loyaltyObject.State = "ACTIVE"

		loyaltyJson, _ := json.Marshal(loyaltyObject)
		batchObject := fmt.Sprintf("%s", loyaltyJson)

		data += "--batch_createobjectbatch\n"
		data += "Content-Type: application/json\n\n"
		data += "POST /walletobjects/v1/loyaltyObject\n\n"
		data += batchObject + "\n\n"
	}
	data += "--batch_createobjectbatch--"

	res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))

	if err != nil {
		fmt.Println(err)
	} else {
		b, _ := io.ReadAll(res.Body)
		fmt.Printf("Batch insert response:\n%s\n", b)
	}
}