עדכונים בזמן אמת

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

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

דרישות מוקדמות

לפני שמטמיעים עדכונים בזמן אמת, צריך את הפרטים הבאים:

  1. ממשק ה-API להזמנה של מפות Google מופעל:
    • ב-GCP, יש לעבור אל APIs & שירותים > ספרייה
    • מחפשים את 'Google Maps Booking API' (ממשק ה-API של מפות Google להזמנה)
      איתור ממשקי ה-API של הזמנות במפות Google
    • מוצאים את המופע של Sandbox ('Google Maps Booking API (Dev)') ולוחצים הפעלה
    • מחפשים את המופע של סביבת הייצור ("Google Maps Booking API") ולוחצים על אפשר
      הפעלת ממשק ה-API להזמנה של מפות Google
  2. המערכת יוצרת חשבון שירות עם תפקיד עריכה בפרויקט GCP. עבור פרטים נוספים: הגדרת החשבון.
  3. פידים של נתונים בסביבת ייצור או ב-Sandbox מתארחים ומוטמעים בהם. לפרטים נוספים, ראו הטמעת נתונים באצווה.
  4. לאימות API מומלץ להתקין את ספריית הלקוח של Google בשפה של בחירה. להשתמש ב-"https://www.googleapis.com/auth/mapsbooking" בתור פרוטוקול OAuth היקף. דוגמאות הקוד שכלולות בהמשך משתמשות בספריות האלה. אחרת, יהיה עליכם לטפל בהמרות אסימונים באופן ידני, כפי שמתואר שימוש ב-OAuth 2.0 כדי לגשת ל-Google APIs.

סקירה כללית

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

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

  • Sandbox – partnerdev-mapsbooking.googleapis.com
  • הפקה – mapsbooking.googleapis.com

נקודות קצה (endpoints)

ה-API של העדכונים בזמן אמת חושף שתי נקודות קצה (endpoints) לטיפול בבקשות הנכנסות כדי לעדכן את המלאי:

  • UPSERT – /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
  • מחיקה – /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete

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

מזהה השותף בפורטל השותפים

שימוש ב-10000001 כערך של PARTNER_ID כדוגמה צילום המסך שלמעלה, את כתובות ה-URL המלאות לשליחת בקשות API ב-Sandbox לסביבת הייצור ייראה כמו בדוגמאות שלמטה.

# Sandbox UPSERT
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Sandbox DELETE
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete
# Production UPSERT
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Production DELETE
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete

עדכון ישויות

כדי לעדכן ישויות במלאי, משתמשים בנקודת הקצה (endpoint) של UPSERT. ולשלוח בקשות HTTP POST. כל בקשת POST חייבת לכלול את PARTNER_ID יחד עם המטען הייעודי (payload) של JSON שמכיל את הפונקציה נתונים מובְנים של כל סוג ישות שמופיע בסכימת המלאי.

מטען ייעודי (payload) של בקשה ל-Upsert

גוף הבקשה הוא אובייקט JSON עם רשימה של רשומות. כל רשומה תואם לישות שמתעדכנת. הוא מורכב מהשדה data_record במטען הייעודי (payload) של הישות שמקודד ב-Base64 וב-generation_timestamp שמציין את המועד שבו מתבצע עדכון היישות:

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_ENTITY",
        "generation_timestamp":"UPDATE_TIMESTAMP"
      }
    ]
  }

במטען הייעודי (payload) שלמעלה, מחליפים את הרכיבים הבאים:

  • BASE_64_ENCODED_ENTITY: מחרוזת ה-JSON בקידוד Base64 של . הישות המפוענחת JSON צריכה להיות באותו מבנה כמו מפרט הפיד, לדוגמה:

    {"@type":"MenuSection","name":"My Updated Menu Section","menuId":{"@id":"10824","displayOrder":1},"@id":"853705"}
  • UPDATE_TIMESTAMP: חשוב לכלול את חותמת הזמן של המועד שבו נוצרה במערכות של הקצה העורפי שלך. חותמת הזמן הזו משמשת ל: כדי לוודא שעדכוני המלאי מתבצעים בצורה נכונה. אם השדה הזה לא כלול, יוגדר השעה שבה Google תקבל את הבקשה. בזמן העדכון ישות באמצעות בקשת batchPush, השדה generation_timestamp הוא משמש לניהול גרסאות של ישויות. מה צפוי? פורמט של ערכי זמן במלאי יחסי של Google.

כל בקשה לעדכון בזמן אמת צריכה לעמוד בתנאים הבאים:

  • גודלו של גוף המטען הייעודי (Payload) לא יעלה על 5MB. באופן דומה לפעולת אצווה מומלץ להסיר רווחים לבנים כדי להתאים יותר נתונים.
  • בקשת batchPush יכולה לכלול עד 1,000 ישויות.

דוגמאות

דוגמה 1: עדכון מסעדה

נניח שאתם צריכים לעדכן בדחיפות את מספר הטלפון של מסעדה. שלך מכיל את ה-JSON של כל המסעדה.

נניח שאתם יוצרים פיד בכמות גדולה שנראה כך:

{
  "@type": "Restaurant",
  "@id": "restaurant12345",
  "name": "Some Restaurant",
  "url": "https://www.provider.com/somerestaurant",
  "telephone": "+16501234570",
  "streetAddress": "345 Spear St",
  "addressLocality": "San Francisco",
  "addressRegion": "CA",
  "postalCode": "94105",
  "addressCountry": "US",
  "latitude": 37.472842,
  "longitude": -122.217144
}
  

במקרה כזה, העדכון בזמן אמת באמצעות HTTP POST יהיה:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501234570",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      }
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

אותה דוגמה עם מטען ייעודי (payload) בקידוד Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM0NTcwIiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0="
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

דוגמה 2: עדכון של כמה מסעדות

כדי לעדכן שתי ישויות של מסעדות בקריאה אחת ל-API, בקשת ה-HTTP POST ייראה כך:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501235555",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant123",
        "name": "Some Other Restaurant",
        "url": "https://www.provider.com/someotherrestaurant",
        "telephone": "+16501231235",
        "streetAddress": "385 Spear St",
        "addressLocality": "San Mateo",
        "addressRegion": "CA",
        "postalCode": "94115",
        "addressCountry": "US"
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

Base64

אותה דוגמה עם מטען ייעודי (payload) בקידוד Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM1NTU1Iiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzIiwibmFtZSI6IlNvbWUgT3RoZXIgUmVzdGF1cmFudCIsInVybCI6Imh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9zb21lcmVzdGF1cmFudCIsInRlbGVwaG9uZSI6IisxNjUwMTIzMTIzNSIsInN0cmVldEFkZHJlc3MiOiIzODUgU3BlYXIgU3QiLCJhZGRyZXNzTG9jYWxpdHkiOiJTYW4gTWF0ZW8iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMTUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIn0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

דוגמה 3: עדכון מחיר של אפשרות בתפריט

נניח שצריך לשנות את המחיר של אפשרות בתפריט.

נניח שאתם יוצרים פיד בכמות גדולה שנראה כך:

{
  "@type": "MenuItemOffer",
  "@id": "menuitemoffer6680262",
  "sku": "offer-cola",
  "menuItemId": "menuitem896532",
  "price": 2,
  "priceCurrency": "USD"
}

אז העדכון בזמן אמת דרך POST ייראה כך:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItemOffer",
        "@id": "menuitemoffer6680262",
        "sku": "offer-cola",
        "menuItemId": "menuitem896532",
        "price": 2,
        "priceCurrency": "USD"
      },
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}
    

Base64

אותה דוגמה עם מטען ייעודי (payload) בקידוד Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtT2ZmZXIiLCJAaWQiOiJtZW51aXRlbW9mZmVyNjY4MDI2MiIsInNrdSI6Im9mZmVyLWNvbGEiLCJtZW51SXRlbUlkIjoibWVudWl0ZW04OTY1MzIiLCJwcmljZSI6MiwicHJpY2VDdXJyZW5jeSI6IlVTRCJ9",
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}

    

הוספת ישויות

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

מחיקת ישויות

כדי למחוק ישויות מהמלאי, אפשר ללחוץ על DELETE endpoint, ושולחים בקשות HTTP POST. כל בקשת POST חייבת צריך לכלול את הפרמטר PARTNER_ID יחד עם המטען הייעודי (payload) של JSON שמכיל את המזהה של ישות כלשהי במלאי שלכם.

מחיקת המטען הייעודי (payload) של הבקשה

הגוף של בקשת המחיקה בנוי באופן דומה לזה בקשה לעדכון. יש בו גם רשימה של רשומות עם השדות data_record ו-delete_time:

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_REFERENCE",
        "delete_time": "DELETE_TIMESTAMP"
      }
    ]
  }

במטען הייעודי (payload) שלמעלה, מחליפים את הרכיבים הבאים:

  • BASE_64_ENCODED_REFERENCE: מחרוזת ה-JSON בקידוד Base64 של הפניה לישות תוסר. קובץ עזר מורכב בלבד מהסוג ומהמזהה של הישות, לדוגמה, ייצוג JSON של הפניה אל MenuSection:

    {"@type":"MenuSection","@id":"853705"}
  • DELETE_TIMESTAMP: חשוב לכלול את חותמת הזמן של המועד שבו נמחקה במערכת הקצה העורפי שלך. חותמת הזמן הזו משמשת ל: לקבוע את הסדר שבו תחול מחיקה על המלאי.

בקשת batchDelete יכולה לכלול עד 1,000 ישויות.

דוגמאות

דוגמה 1: הסרת שתי ישויות MenuItem

כדי להסיר שתי אפשרויות בתפריט בקריאה אחת ל-API, בקשת ה-HTTP POST תהיה ככה:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_1234"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_5678"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    }
  ]
}
    

Base64

אותה דוגמה עם מטען ייעודי (payload) בקידוד Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV8xMjM0In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV81Njc4In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
  ]
}
    

דוגמה 2: מחיקת ישות מסוג Restaurant

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

בקשה לדוגמה למחיקת ישות של מסעדה עם מזהה https://www.provider.com/restaurant/12345:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "https://www.provider.com/restaurant/12345"
      },
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

אותה דוגמה עם מטען ייעודי (payload) בקידוד Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "ewogICJAdHlwZSI6ICJSZXN0YXVyYW50IiwKICAiQGlkIjogImh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9yZXN0YXVyYW50LzEyMzQ1Igp9"
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

אימות קודי תגובה של API

יש שני סוגי אימותים בקריאות ל-API לעדכון בזמן אמת:

  • Request-level – האימותים האלה מוודאים שהמטען הייעודי (Payload) עומד בדרישות של למעלה או מחיקה וכל data_record מכיל גם את השדה @id וגם את השדה @type. הבדיקות האלה מסונכרנות והתוצאות מוחזרות ב-API גוף התגובה. המשמעות של קוד תגובה 200 וגוף JSON ריק {} אימותים שעברו והישויות בבקשה הזו נוספו לתור בעיבוד. קוד תגובה שונה מ-200 פירושו אחד או יותר האימותים נכשלו והבקשה כולה נדחתה (כולל כל ישויות במטען הייעודי (payload). לדוגמה, אם בdata_record היה חסר @type, תוחזר תגובת השגיאה הבאה:

    {
      "error": {
        "code": 400,
        "message": "Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n",
        "status": "INVALID_ARGUMENT",
        "details": [
          {
            "@type": "type.googleapis.com/google.rpc.DebugInfo",
            "detail": "[ORIGINAL ERROR] generic::invalid_argument: Failed to parse one or more rtu records. Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n [google.rpc.error_details_ext] { message: \"Record:{\\\"@id\\\":\\\"2717/86853/DELIVERY\\\",\\\"applicableServiceType\\\":[\\\"DELIVERY\\\",\\\"TAKEOUT\\\"],\\\"menuId\\\":[{\\\"@id\\\":\\\"2717/DELIVERY\\\",\\\"displayOrder\\\":1},{\\\"@id\\\":\\\"2717/TAKEOUT\\\",\\\"displayOrder\\\":2}],\\\"name\\\":\\\"Salad\\\",\\\"offeredById\\\":[\\\"2717\\\"]} has following errors: \\nThe entity type could not be extracted from the entity value.\\n\" }"
          }
        ]
      }
    }
    
  • ברמת הישות – כל ישות במטען הייעודי (payload) מאומתת מול סכימת יחסים. בעיות שיאותרו בשלב האימות הזה לא מדווחות ב-API תשובה. הן מדווחות רק ב- דיווח RTU במרכז הבקרה.

מכסות ל-API

לעדכוני API בזמן אמת יש מכסה של 1,500 בקשות כל 60 שניות, או 25 בקשות לשנייה בממוצע. כשחורגים ממכסה, Google משיבה את הודעת השגיאה הבאה:

{
  "error": {
    "code": 429,
    "message": "Insufficient tokens for quota ...",
    "status": "RESOURCE_EXHAUSTED",
    "details": [...]
  }
}

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

דוגמאות קוד

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

עדכון ישויות

Node.js

הקוד הזה משתמש בספריית האימות של Google ל-Node.js.

/* Sample code for Real-time update batchPush implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchPush`;

/**
 * Send a Real-time update request to update/insert entities
 */
async function batchUpsert(entities) {
  /**
   * Sign JWT token using private key from service account secret file
   * provided. The client can be created without providing a service account
   * secret file by implementing Application Default Credentials.
   * https://github.com/googleapis/google-auth-library-nodejs
   */
  const client = new JWT({
    email: serviceAccountJson.client_email,
    key: serviceAccountJson.private_key,
    scopes: ['https://www.googleapis.com/auth/mapsbooking'],
  });
  const request = {records: toPushRecords(entities)};
  const body = JSON.stringify(request);
  try {
    const response = await client.request({
      method: 'POST',
      url,
      data: body,
      headers: {'Content-Type': 'application/json'}
    });
    console.log('request body:', body);
    console.log('response status:', response.status);
    console.log(
        'response data:', response.data);  // successful response returns '{}'
  } catch (error) {
    console.log('error:', error);
  }
}

/**
 * Maps array of entities to records for batch push requests
 */
const toPushRecords = (entities) => {
  return entities.map((entity) => {
    // Using dateModified to set generation_timestamp. Defaulting to the
    // current timestamp for records that do not have dateModified.
    const generation_timestamp =
        entity.dateModified ? entity.dateModified : new Date().toISOString();
    return {data_record: btoa(JSON.stringify(entity)), generation_timestamp};
  });
};

// Call batchUpsert with example entities. dateModified is optional and is
// used to hold the actual timestamp when the entity was updated/created.
batchUpsert([
  {
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  },
  {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  }
]);

Python

הקוד הזה משתמש בספריית האימות של Google ל-Python.

"""Sample code for the Real-time update batchPush implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchPush'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_upsert(entities):
  """Makes a batchPush request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to update or add.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_push_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_push_record(entity):
  """Creates a record from an entity for batchPush requests.

  Args:
      entity: The entity object to create the record from.

  Returns:
      The constructed record for the batchPush request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set generation_timestamp. Defaulting to the
  # current timestamp for records that do not have dateModified.
  generation_timestamp = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'generation_timestamp': generation_timestamp,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_upsert with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was updated/created.
batch_upsert([{
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}, {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}])

Java

הקוד הזה משתמש בספריית האימות של Google ל-Java.

המודלים של קוד המקור של הלקוח בחבילות rtusamples.inventory ו-rtusamples.realtime נוצרו לפי השלבים שבמאמר יצירת ספריות לקוח.

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.MenuItemOffer;
import rtusamples.inventory.MenuItemOfferType;
import rtusamples.inventory.ServiceTypeElement;
import rtusamples.realtime.BatchPushGenericRecordRequest;
import rtusamples.realtime.GenericRecord;

/** Sample code for Real-time update batchPush implementation. */
public final class BasicPush {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 12345678;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      //    "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
      "https://mapsbooking.googleapis.com"; // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example MenuItemOffer entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was updated/created.
    MenuItemOffer menuItemOfferPizza = new MenuItemOffer();
    menuItemOfferPizza.setID("6680261");
    menuItemOfferPizza.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferPizza.setMenuItemID("18931508");
    menuItemOfferPizza.setPrice(15.5);
    menuItemOfferPizza.setPriceCurrency("USD");
    menuItemOfferPizza.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferPizza.setInventoryLevel(0.0);
    menuItemOfferPizza.setDateModified("2022-10-07T13:00:00.000Z");

    MenuItemOffer menuItemOfferSalad = new MenuItemOffer();
    menuItemOfferSalad.setID("6680262");
    menuItemOfferSalad.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferSalad.setMenuItemID("18931509");
    menuItemOfferSalad.setPrice(25.5);
    menuItemOfferSalad.setPriceCurrency("USD");
    menuItemOfferSalad.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferSalad.setInventoryLevel(0.0);
    menuItemOfferSalad.setDateModified("2022-10-07T13:00:00.000Z");

    // Example array of MenuItemOffer entities to update.
    List<MenuItemOffer> menuItemOffers = Arrays.asList(menuItemOfferPizza, menuItemOfferSalad);

    // Create list of GenericRecord from menuItemOffers.
    List<GenericRecord> menuItemOfferGenericRecords =
        menuItemOffers.stream()
            .map(
                (menuItemOffer) ->
                    toBatchPushRecord(menuItemOffer, menuItemOffer.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be updated/created.
    List<GenericRecord> recordsToBeUpdated = new ArrayList<>();

    // Add list of menuItemOffer generic records.
    recordsToBeUpdated.addAll(menuItemOfferGenericRecords);

    // Request object that contains all records.
    BatchPushGenericRecordRequest batchPushRequest = new BatchPushGenericRecordRequest();
    batchPushRequest.setRecords(recordsToBeUpdated.toArray(new GenericRecord[0]));

    // Execute batchPush request.
    BasicPush basicPush = new BasicPush();
    basicPush.batchPush(batchPushRequest, credentials);
  }

  public void batchPush(
      BatchPushGenericRecordRequest batchPushRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchPushRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchPush",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericRecord toBatchPushRecord(T entity, String dateModified) {
    GenericRecord genericRecord = new GenericRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set generation_timestamp. Defaulting to the
      // current timestamp for records that do not have dateModified.
      String generationTimestamp =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setGenerationTimestamp(generationTimestamp);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

הסרת ישויות

Node.js

הקוד הזה משתמש בספריית האימות של Google ל-Node.js.

/* Sample code for Real-time update batchDelete implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchDelete`;


/**
 * Send a Real-time update request to delete entities
 */
async function batchDelete(entities) {
  try {
    /**
     * Sign JWT token using private key from service account secret file
     * provided. The client can be created without providing a service account
     * secret file by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-nodejs
     */
    const client = new JWT({
      email: serviceAccountJson.client_email,
      key: serviceAccountJson.private_key,
      scopes: ['https://www.googleapis.com/auth/mapsbooking'],
    });
    const request = {
      records: toDeleteRecords(entities)
    };
    const body = JSON.stringify(request);
    try {
      const response = await client.request({
        method: 'POST',
        url,
        data: body,
        headers: {'Content-Type': 'application/json'}
      });
      console.log('request body:', body);
      console.log('response status:', response.status);
      console.log('response data:', response.data);  // successful response returns '{}'
    } catch (error) {
      console.log('error:', error);
    }
  }

  /**
   * Maps array of entities to records for batch delete requests
   */
  const toDeleteRecords = (entities) => {
    return entities.map((entity) => {
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      const delete_time =
          entity.dateModified ? entity.dateModified : new Date().toISOString();
      return {data_record: btoa(JSON.stringify(entity)), delete_time};
    });
  };

  // Call batchDelete with example entities. dateModified is optional and is
  // used to hold the actual timestamp when the entity was deleted.
  batchDelete([
    {
      '@type': 'Menu',
      '@id': '853706',
      'dateModified': '2022-06-19T15:43:50.970Z'
    },
    {
      '@type': 'Menu',
      '@id': '853705',
      'dateModified': '2022-06-19T15:13:00.280Z'
    }
  ]);

Python

הקוד הזה משתמש בספריית האימות של Google ל-Python.

"""Sample code for the Real-time update batchDelete implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchDelete'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_delete(entities):
  """Makes a batch delete request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to delete.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_delete_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_delete_record(entity):
  """Creates a record from an entity for batchDelete requests.

  Args:
    entity: The entity object to create the record from.

  Returns:
    The constructed record for the batchDelete request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set delete_time. Defaulting to the current
  # timestamp for records that do not have dateModified.
  delete_time = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'delete_time': delete_time,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_delete with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was deleted.
batch_delete([{
    '@type': 'Menu',
    '@id': '853706',
    'dateModified': '2022-06-19T13:10:00.000Z'
}, {
    '@type': 'Menu',
    '@id': '853705',
    'dateModified': '2022-06-19T13:30:10.000Z'
}])

Java

הקוד הזה משתמש בספריית האימות של Google ל-Java.

המודלים של קוד המקור של הלקוח בחבילות rtusamples.inventory ו-rtusamples.realtime נוצרו לפי השלבים שבמאמר יצירת ספריות לקוח.

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.Menu;
import rtusamples.inventory.MenuType;
import rtusamples.realtime.BatchDeleteGenericRecordsRequest;
import rtusamples.realtime.GenericDeleteRecord;

/** Sample code for the Real-time update batchDelete implementation. */
public final class BasicDelete {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 123456789;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
  // "https://mapsbooking.googleapis.com" // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example Menu entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was deleted.
    Menu menuLunch = new Menu();
    menuLunch.setID("853705");
    menuLunch.setType(MenuType.MENU);
    menuLunch.setDateModified("2022-09-19T13:10:00.000Z");

    Menu menuDinner = new Menu();
    menuDinner.setID("853706");
    menuDinner.setType(MenuType.MENU);
    menuDinner.setDateModified("2022-09-19T13:13:10.000Z");

    // Example array of Menu entities to update.
    List<Menu> menus = Arrays.asList(menuLunch, menuDinner);

    // Create list of GenericDeleteRecord from menus.
    List<GenericDeleteRecord> menuGenericDeleteRecords =
        menus.stream()
            .map((menu) -> toBatchDeleteRecord(menu, menu.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be deleted.
    List<GenericDeleteRecord> recordsToBeDeleted = new ArrayList<>();

    // Add list of menu generic records.
    recordsToBeDeleted.addAll(menuGenericDeleteRecords);

    // Request object that contains all records.
    BatchDeleteGenericRecordsRequest batchDeleteRequest = new BatchDeleteGenericRecordsRequest();
    batchDeleteRequest.setRecords(recordsToBeDeleted.toArray(new GenericDeleteRecord[0]));

    // Execute batchDelete request.
    BasicDelete basicDelete = new BasicDelete();
    basicDelete.batchDelete(batchDeleteRequest, credentials);
  }

  public void batchDelete(
      BatchDeleteGenericRecordsRequest batchDeleteRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchDeleteRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchDelete",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericDeleteRecord toBatchDeleteRecord(T entity, String dateModified) {
    GenericDeleteRecord genericRecord = new GenericDeleteRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      String deleteTime =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setDeleteTime(deleteTime);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

תרחישים לדוגמה

תרחישי השימוש הבאים הם דוגמאות לעדכונים בזמן אמת, עדכוני פידים בכמות גדולה, לבין התוכן ברמה גבוהה בקריאה ל-API:

תרחיש הישות שצריך לעדכן תיאור ואפקטים
השבתת שירות Service

צריך להשבית שירות מסיבה בלתי צפויה.

עדכונים בזמן אמת: עדכון הישות Service בזמן אמת על ידי הגדרת המאפיין isDisabled שלו ל-true, אבל להשאיר את המאפיינים האחרים ללא שינוי.

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

פריט מסוים חסר במלאי MenuItemOffer עדכונים בזמן אמת: שולחים את הקובץ MenuItemOffer ישות עם inventoryLevel מוגדרת ל-0 עבור הנתון MenuItem וכל שאר הנתונים ללא שינוי.
שינוי במחיר של האפשרות בתפריט MenuItemOffer עדכונים בזמן אמת: שולחים את הקובץ MenuItemOffer ישות עם price מוגדרת למחיר המעודכן של הנכס הנתון MenuItem וכל שאר הנתונים ללא שינוי.

הוספת ישות חדשה ברמה העליונה

רלוונטי רק לישויות מסוג Menu, Restaurant ו-Service.

Menu, Restaurant Service

למשל, אתם צריכים להוסיף תפריט חדש למסעדה.

פידים מלאים: מוסיפים את הישות אל הפידים של הנתונים וממתינים להטמעת נתונים באצווה.

מחיקה סופית של ישות ברמה העליונה

רלוונטי רק לישויות מסוג Menu, Restaurant ו-Service.

Menu, Restaurant Service

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

פידים מלאים: הקפידו להסיר את הישות מהפידים המלאים לפני באחזור הבא של Google, אחרת הישות תתווסף מחדש.

הוספת אזור משלוחים חדש בService ספציפי ServiceArea פידים של אצווה: שולחים את הישות ServiceArea הרלוונטית עם כל ללא שינוי, כמו שבדרך כלל עושים בפידים מלאים, עם אזור חדש למשלוחים שצוינו בתוך polygon, geoRadius או postalCode.
עדכון זמן ההגעה המשוער למסירה בService ServiceHours פידים באצווה: שולחים את הServiceHours כמו ב: העדכונים, מלבד העדכון של ה-leadTimeMin שלהם בהתאם.
עדכון מחירי המשלוח בService Fee פידים של באצווה: שליחת Fee מסירה מלאה באמצעות הטבלה price עודכנה.
עדכון שעות הפעילות של משלוחים או טייק אוויי בService ServiceHours פידים באצווה: שולחים את הServiceHours כמו ב: הפידים, מלבד המאפיינים opens ו-closes שלהם מעודכנים בהתאם.
Service (שינוי סכום ההזמנה המינימלי) Fee פידים של באצווה: שליחת Fee מלאים באמצעות minPrice עודכן
מחיקה סופית של MenuItem Menu פידים באצווה: שולחים את הMenuItem כמו במייל אבל עם parentMenuSectionId ריק.

זמני עיבוד למשימות באצווה ועדכונים בזמן אמת

ישות שעדכנה או נמחקה באמצעות פיד בכמות גדולה תעובד בתוך 2 שעות לעומת ישות שעודכנה באמצעות עדכון בזמן אמת 5 דקות. א' ישות לא פעילה יימחק בתוך 14 ימים.

אפשר לשלוח ל-Google:

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