בסעיף הזה נסביר איך אפשר לשלוח ל-Google עדכונים תלויי-זמן של יישויות המלאי. ה-API לעדכון מצטבר מאפשר לעדכן עדכונים ולמחוק את המלאי ב-Sandbox או במלאי הייצור שלכם כמעט בזמן אמת.
הפונקציונליות הזו מיועדת בעיקר לעדכונים שלא ניתן לחזות, כמו סגירות חירום. במקרה כזה, כל שינוי שנשלח דרך ה-API של עדכון ההוצאות צריך להתבצע תוך שעה לכל היותר. אם אין צורך לשקף את השינוי באופן מיידי, תוכלו להשתמש במקום זאת בהטמעת נתונים בכמות גדולה. עדכונים מצטברים מעובדים בתוך חמש דקות לכל היותר.
דרישות מוקדמות
כדי להטמיע עדכונים מצטברים, יש לבצע את הפריטים הבאים:
- חשבון שירות נוצר עם הרשאת עריכה בפרויקט הפעולות. פרטים נוספים זמינים במאמר יצירה והגדרה של פרויקט.
- פידים של נתוני ייצור או ארגז חול מתארחים ונטמעים. מידע נוסף זמין במאמר הטמעת נתונים של אצווה.
- (אופציונלי, אבל מומלץ) מתקינים את ספריית הלקוח של Google בשפה שבחרתם, כדי שתוכלו להשתמש ב-OAuth 2.0 בזמן הקריאה ל-API. דגימות הקוד המפורטות למטה משתמשות בספריות אלה. אחרת, עליכם לטפל בהחלפה של אסימון באופן ידני, כפי שמתואר במאמר שימוש ב-OAuth 2.0 לגישה ל-Google APIs.
נקודות קצה
בבקשות הבאות, יש להחליף את הפרטים הבאים:
- PROJECT_ID: מזהה הפרויקט ב-Google Cloud שמשויך לפרויקט שיצרתם בקטע יצירה והגדרה של פרויקט.
- TYPE: סוג הישות (נכס
@type
) של האובייקט בפיד הנתונים שרוצים לעדכן. - ENTITY_ID (מחיקת נקודת קצה בלבד): מזהה הישות למחיקה. הקפידו לקודד את כתובות ה-URL של מזהה הישות.
- DELETE_TIME (מחיקת נקודת קצה בלבד): שדה אופציונלי לציון הזמן שבו הישות נמחקה במערכות שלכם (ברירת המחדל היא כאשר הבקשה מתקבלת). הערך לא יכול להיות עתידי. בעת שליחת ישות באמצעות שיחה מצטברת, גרסת הישות משתמשת גם בשדה
delete_time
במקרה של שיחת מחיקה. הזינו את הערך הזה בפורמטyyyy-mm-ddTHH:mm:ssZ
עדכון נקודת הקצה
כדי לשנות ישות, יש להגיש בקשת HTTP POST לנקודת הקצה הבאה ולכלול מטענים של עדכונים ותוספות. ניתן לבצע עד 1,000 ישויות בקריאה אחת ל-API.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities:batchPush
לדוגמה, אם אתם רוצים לעדכן ישויות בפרויקט עם מזהה "delivery-provider-id" נקודת הקצה תהיה:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities:batchpush
מחיקת נקודת הקצה
כדי למחוק ישות במלאי שלכם, עליכם לשלוח בקשת HTTP DELETE בנקודת הקצה הבאה.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
לדוגמה, כדי למחוק פרויקט "Menusection" פרויקט עם המזהה "menusection_122" מפרויקט "delivery-provider-id" עליך לבצע קריאה ל-API של HTTP DELETE כדי:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
סביבת ארגז חול
כדי להשתמש ב-API המצטבר לעדכון ארגז החול, יש לפעול לפי ההנחיות המפורטות בנקודות הקצה שלמעלה, אבל לשלוח בקשות אל /v2/sandbox/apps/
במקום אל /v2/apps/
.
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities:batchPush
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
עדכון הישויות
כל בקשת POST חייבת לכלול את הפרמטרים של הבקשה יחד עם המטען הייעודי של JSON המכיל את הנתונים המובְנים של כל סוג ישות שמופיע בסכימת המלאי.
עדכון המטען הייעודי
קובץ ה-JSON אמור להופיע באותו אופן שבו הוא יופיע בפיד המקובץ, יחד עם ההבדלים הבאים:
- גוף המטען לא יכול להיות גדול מ-5 MB. בדומה לפידים של אצווה, מומלץ להסיר רווחים לבנים כדי להתאים יותר נתונים.
- הכתובת תופיע במעטפה:
{ "requests": [ { "entity": { "data":"ENTITY_DATA", "name": "apps/project_id>/entities/type/entity_id" }, "update_time":"UPDATE_TIMESTAMP" }, ], "vertical": "FOODORDERING" }
במטען הייעודי (payload) שלמעלה, מחליפים את הפרטים הבאים:
- ENTITY_DATA: הישות בפורמט JSON טורית כמחרוזת. יש להעביר את הישות בפורמט JSON-LD כמחרוזת בשדה
data
. - UPDATE_TIMESTAMP (אופציונלי): חותמת זמן של מועד העדכון של הישות במערכות שלכם. הערך לא יכול להיות עתידי. חותמת הזמן המוגדרת כברירת מחדל היא
כש-Google מקבלת את הבקשה. בעת שליחת ישות באמצעות בקשה מצטברת, שדה גרסת הישות משתמש גם בשדה
update_time
במקרה של בקשת הוספה/עדכון.
דוגמאות
דוגמה 1: עדכון מסעדה
נניח שצריך לעדכן בדחיפות את מספר הטלפון של מסעדה. העדכון שלכם כולל את קובץ ה-JSON של כל המסעדה.
כדאי להשתמש בפיד אצווה שנראה כך:
{ "@type": "Restaurant", "@id": "restaurant12345", "name": "Some Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501234567", "streetAddress": "345 Spear St", "addressLocality": "San Francisco", "addressRegion": "CA", "postalCode": "94105", "addressCountry": "US", "latitude": 37.472842, "longitude": -122.217144 }
העדכון המצטבר לפי HTTP POST אמור כך:
POST v2/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant12345", "data": { "@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 } } } "vertical": "FOODORDERING" }
דוגמה 2: עדכון מספר מסעדות
כדי לעדכן שתי ישויות במסעדה בקריאה אחת ל-API, בקשת ה-HTTP POST תהיה כך:
POST v2/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant12345", "data": { "@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 } } }, { "entity": { "name": "apps/provider-project/entities/restaurant/restaurant123", "data": { "@type": "Restaurant", "@id": "restaurant123", "name": "Some Other Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501231235", "streetAddress": "385 Spear St", "addressLocality": "San Mateo", "addressRegion": "CA", "postalCode": "94115", "addressCountry": "US" } } } ] "vertical": "FOODORDERING" }
דוגמה 3: עדכון מחיר בפריט בתפריט
נניח שצריך לשנות את המחיר של פריט בתפריט. כמו בדוגמה 1, העדכון חייב להכיל את ה-JSON עבור כל הישות ברמה העליונה (התפריט), והפיד משתמש בסכימת המלאי v1.
כדאי להשתמש בפיד אצווה שנראה כך:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
העדכון המצטבר באמצעות POST אמור כך:
POST v2/sandbox/apps/provider-project/entities:batchPush Host: actions.googleapis.com Content-Type: application/ld+json { "requests": [ { "entity": { "name": "apps/provider-project/entities/menuitemoffer/menuitemoffer6680262", "data": { "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 1.00, "priceCurrency": "USD" }, "vertical": "FOODORDERING" } } ] "vertical": "FOODORDERING" }
הוספת ישות
כדי להוסיף ישויות, הימנעו משימוש בעדכוני מלאי. במקום זאת, השתמשו בתהליך פידים באצווה כפי שמתואר בסכימת המלאי של גרסה 2.
הסרת ישות
כדי להסיר ישויות ברמה העליונה, יש להשתמש בנקודת קצה שונה מעט, ולהשתמש ב-HTTP DELETE במקום ב-HTTP POST בבקשה.
מחיקת ישות ברמה העליונה
חשבו על מצב שבו תרצו למחוק מסעדה בפיד. אתם צריכים גם למחוק את השירותים והתפריטים שלה.
נקודת קצה לדוגמה של ישות בתפריט עם המזהה "provider/restaurant/תפריט/nr"
DELETE v2/apps/delivery-provider-id/entities/menu/provider%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
נקודת קצה לדוגמה לישות מסעדה עם המזהה "https://www.provider.com/restaurant/nr"
DELETE v2/apps/delivery-provider-id/entities/restaurant/provider%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
נקודת קצה לדוגמה של ישות שירות עם המזהה "https://www.provider.com/restaurant/service/nr"
DELETE v2/apps/delivery-provider-id/entities/service/provider%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
הסרת ישויות משנה
אין להשתמש ב-HTTP DELETE כדי להסיר ישות משנה בתוך ישות ברמה עליונה, למשל: פריט בתפריט. במקום זאת, צריך להתייחס להסרת ישויות משנה כעדכון של ישות ברמה העליונה שבה ישות המשנה הוסרה מהרשימה הרלוונטית או מההפניה האחורית.
קודי תגובה של API
קריאה מוצלחת לא מעידה על כך שהפיד תקין או נכון, אלא רק על כך שקריאת ה-API בוצעה. שיחות מוצלחות מקבלות קוד תגובה 200 HTTP, בנוסף לגוף תגובה ריק:
{}
במקרה של כשלים, קוד התגובה של ה-HTTP לא יהיה 200, וגוף התגובה מציין מה השתבש.
לדוגמה, אם המשתמש הגדיר את הערך "vertical" במעטפה ל-FAKE_VERTICAL
, תופיע ההודעה הבאה:
{
"error": {
"code": 400,
"message": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\"",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "entity.vertical",
"description": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\""
}
]
}
]
}
}
דוגמת קוד
הנה כמה דוגמאות לשימוש ב-API של עדכון מצטבר בשפות שונות. הדוגמאות האלה מתבססות על ספריות האימות של Google, ונעזרים בפיד באמצעות סכימת המלאי v1. פתרונות חלופיים זמינים במאמר שימוש ב-OAuth 2.0 לאפליקציות בשרת לשרת.
עדכון הישויות
Node.js
הקוד הזה משתמש בספריית האימות של Google עבור Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'your/entity/id' const PROJECT_ID = 'type/your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to update or add an entity */ async function updateEntity(entity) { const token = await getAuthToken() request.post({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities:batchPush`, body: { requests: [ { entity: { data: JSON.stringify(entity) name: `apps/${PROJECT_ID}/entities/${ENTITY_ID}` } } ], vertical: 'FOODORDERING' }, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } updateEntity(entity)
Python
הקוד הזה משתמש בספריית האימות של Google ל-Python.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib PROJECT_ID = 'your-project-id' ENTITY_ID = 'type/your/entity/id' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities:batchPush' % ( PROJECT_ID) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) # Retrieving the entity update_file = open("entity.json") #JSON file containing entity data in json format. data = update_file.read() entity = {} entity['data'] = data #entity JSON-LD serialized as string entity['name'] = 'apps/%s/entities/%s' % (PROJECT_ID, urllib.quote(ENTITY_ID, '') ) # Populating the request request = {} request['entity'] = entity requestArray = [request] # Populating the payload payload = {} payload['requests'] = requestArray payload['vertical'] = 'FOODORDERING' response = authed_session.post(ENDPOINT, json=payload) print(response.text) #if successful, will be '{}'
Java
הקוד הזה משתמש בספריית האימות של Google ל-Java.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "type/your-entity-id"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to update or add an entity. * @param entityId The id of the entity to update. * @param entity the json of the entity to be updated. */ public void updateEntity(String entityId, JSONObject data) { String authToken = getAuthToken(); String endpoint = String.format("https://actions.googleapis.com/v2/apps/%s/entities/:batchPush", PROJECT_ID); JSONObject entity = new JSONObject(); entity.put("data", data.toString()); entity.put("name", String.format("apps/%s/entities/%s", PROJECT_ID, URLEncoder.encode(ENTITY_ID, "UTF-8"))); JSONObject request = new JSONObject(); request.put("entity", entity); JSONArray requestArray = new JSONArray(); requestArray.put(request); JSONObject payload = new JSONObject(); payload.put("requests", requestArray); payload.put("vertical", FOODORDERING); // Execute POST request executePostRequest(endpoint, authToken, payload); }
הסרת ישויות
Node.js
הקוד הזה משתמש בספריית האימות של Google עבור Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' const PROJECT_ID = 'your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to delete an entity */ async function deleteEntity(entityId) { const token = await getAuthToken() request.delete({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities/${encodeURIComponent(entityId)}?entity.vertical=FOODORDERING`, body: {}, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } deleteEntity(ENTITY_ID)
Python
הקוד הזה משתמש בספריית האימות של Google ל-Python.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib # Service config PROJECT_ID = 'your-project-id' ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' DELETE_TIME = '2018-04-07T14:30:00-07:00' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING&delete_time=%s' % ( PROJECT_ID, urllib.quote(ENTITY_ID, ''), urllib.quote(DELETE_TIME, '')) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) response = authed_session.delete(ENDPOINT) print(response.text) #if successful, will be '{}'
Java
הקוד הזה משתמש בספריית האימות של Google ל-Java.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "restaurant/http://www.provider.com/somerestaurant"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to delete an entity. * @param entityId The id of the entity to delete. */ public void deleteEntity(String entityId) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); // Execute DELETE request System.out.println(executeDeleteRequest(endpoint, authToken)); }
תרחישים לדוגמה
התרחישים הבאים הם דוגמאות לעדכונים מצטברים, לעדכוני פיד מלאים ולתוכן ברמה גבוהה בקריאה ל-API:
תרחיש | ישות לעדכון | תיאור ואפקטים |
---|---|---|
השבתת שירות | Service |
עליכם להשבית שירות מסיבה בלתי צפויה. עדכונים מצטברים: מעדכנים את הישות פידים מלאים: חשוב לעדכן את הישות מהפידים המלאים
כך ש- |
פריט ספציפי חסר במלאי | MenuItemOffer |
עדכונים מצטברים: יש לשלוח את הישות המקיפה MenuItemOffer
עם הערך inventoryLevel כ-0 ל-MenuItem
הנתון וכל הנתונים האחרים ללא שינוי. |
שינוי מחיר של פריט בתפריט | MenuItemOffer |
עדכונים מצטברים: יש לשלוח את הישות הכוללת (MenuItemOffer ) עם price בתור המחיר המעודכן של
MenuItem , וכל שאר הנתונים ללא שינוי. |
הוספת ישות חדשה ברמה העליונה רלוונטי רק לישויות מהסוגים |
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 ריק.
|
SLO בזמן העיבוד של עבודות אצווה ועדכונים מצטברים
ישות המעודכנת או נמחקת דרך אצווה תעובד בתוך שעתיים במצב המאמץ הטוב ביותר, בעוד שיישות שעודכנה באמצעות עדכון מצטבר תעובד בתוך 5 דקות. ישות לא פעילה תימחק בתוך 7 ימים.
תוכלו לשלוח אל Google את הפרטים הבאים:
- עבודות אצווה מרובות ביום לשמירה על עדכניות המלאי שלך, או
- עבודת אצווה אחת ביום וממשקי API מצטברים כדי לשמור על עדכניות המלאי שלכם.