Questa sezione descrive come inviare aggiornamenti tempestivi dei tuoi feed a Google. L'API Incremental Updates consente di aggiornare ed eliminare le entità nei feed quasi in tempo reale.
Questa funzionalità è pensata principalmente per gli aggiornamenti che non puoi prevedere, come le chiusure per emergenze. Di norma, qualsiasi modifica inviata tramite l'API Incremental Updates deve essere una modifica che deve essere pubblicata entro al massimo una settimana. Se la modifica non deve essere applicata immediatamente, puoi utilizzare un aggiornamento collettivo. Gli aggiornamenti incrementali vengono elaborati in non più di cinque minuti.
Configurazione
Per implementare gli aggiornamenti incrementali:
- Per creare un progetto, segui i passaggi descritti nella sezione Creare e configurare un progetto.
- Segui i passaggi descritti in Configurare un account di servizio per creare un account di servizio. Tieni presente che devi essere un "proprietario" del progetto per aggiungere un ruolo "Editor" per l'account di servizio
- (Facoltativo, ma consigliato) Installa la libreria client Google nella lingua che preferisci per facilitare l'utilizzo di OAuth 2.0 quando chiami l'API. Gli esempi di codice inclusi di seguito utilizzano queste librerie. In caso contrario, dovrai gestire manualmente gli scambi di token come descritto in Utilizzare OAuth 2.0 per accedere alle API di Google.
Endpoint
Per notificare a Google un aggiornamento, invia una richiesta POST HTTP all'API Incremental Updates e includi un payload di aggiornamenti e aggiunte. Lo schema di inventario che utilizzi determina a quale endpoint inviare la richiesta:
https://actions.googleapis.com/v2/apps/PROJECT_ID /entities/TYPE /ENTITY_ID :push
https://actions.googleapis.com/v2/apps/PROJECT_ID /entities/ENTITY_ID :push
Per rimuovere un'entità, invia una richiesta HTTP DELETE al seguente endpoint corrispondente allo schema di inventario che utilizzi:
https://actions.googleapis.com/v2/apps/PROJECT_ID /entities/TYPE /ENTITY_ID ?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
https://actions.googleapis.com/v2/apps/PROJECT_ID /entities/ENTITY_ID ?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Nelle richieste precedenti, sostituisci quanto segue:
- PROJECT_ID: l'ID progetto Google Cloud associato al progetto che hai creato in Creare e configurare un progetto.
- TYPE (solo schema di inventario v2): il tipo di entità (proprietà
@type
) dell'oggetto nel feed di dati che vuoi aggiornare. - ENTITY_ID: ID dell'entità inclusa nel payload. Assicurati di codificare in URL l'ID entità.
- DELETE_TIME (solo endpoint di eliminazione): campo facoltativo per indicare il momento in cui l'entità è stata eliminata nei tuoi sistemi (il valore predefinito è il momento in cui viene ricevuta la richiesta). Il valore dell'ora non deve essere nel futuro. Quando invii un'entità tramite una chiamata incrementale, il controllo delle versioni delle entità utilizza anche il campo
delete_time
in caso di chiamata di eliminazione. Formatta questo valore comeyyyy-mm-ddTHH:mm:ssZ
Ad esempio, hai un progetto con ID "delivery-provider-id" che utilizza lo schema di inventario v2. Vuoi apportare modifiche al ristorante con un tipo di entità ristorante "MenuSection" e un ID entità "menuSection_122". L'endpoint per gli aggiornamenti dei dati è il seguente:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push
Per rimuovere la stessa entità, devi effettuare questa chiamata API HTTP DELETE:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Richieste di sandbox
Per le richieste della sandbox, segui le indicazioni riportate in Endpoint sopra, ma invia le richieste a /v2/sandbox/apps/
anziché a /v2/apps/
. Ad esempio, una richiesta di eliminazione della sandbox per lo schema di inventario v2 è strutturata come segue:
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID /entities/TYPE /ENTITY_ID ?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Aggiornamenti e aggiunte
I feed batch giornalieri devono contenere anche eventuali modifiche inviate tramite questa API. In caso contrario, gli aggiornamenti batch sovrascriveranno le modifiche incrementali.
Payload
Ogni richiesta POST deve includere i parametri di richiesta insieme al payload JSON contenente i dati strutturati di qualsiasi tipo di entità elencato nello schema dell'inventario.
Il file JSON dovrebbe avere lo stesso aspetto del feed batch, con le seguenti differenze:
- Il corpo del payload non deve superare i 5 MB. Analogamente ai feed batch, ti consigliamo di rimuovere gli spazi vuoti per adattare più dati.
- La busta è la seguente:
{ "entity": { "data":"ENTITY_DATA ", "vertical":"FOODORDERING" }, "update_time":"UPDATE_TIMESTAMP " }
Nel payload riportato sopra, sostituisci quanto segue:
- ENTITY_DATA: entità in formato JSON serializzata come stringa. L'entità JSON-LD deve essere passata come stringa nel campo
data
. - UPDATE_TIMESTAMP (facoltativo): timestamp dell'aggiornamento dell'entità nei tuoi sistemi. Il valore dell'ora non deve essere nel futuro. Il timestamp predefinito è il momento in cui Google riceve la richiesta. Quando invii un'entità tramite una richiesta incrementale, il controllo delle versioni delle entità utilizza anche il campo
update_time
nel caso di una richiesta di aggiunta/aggiornamento.
Aggiornamento di un'entità
Esempio 1: aggiornamento di un ristorante
Supponiamo che tu debba aggiornare urgentemente il numero di telefono di un ristorante. L'update contiene il JSON per l'intero ristorante.
Considera un feed batch simile al seguente:
{ "@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 }
L'aggiornamento incrementale tramite POST HTTP sarà il seguente:
POST v2/apps/provider-project/entities/Restaurant/restaurant12345:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "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" } }
Esempio 2: aggiornamento del prezzo di un elemento del menu
Supponiamo che tu debba modificare il prezzo di una voce del menu. Come nell'esempio 1, l'update deve contenere il JSON per l'intera entità di primo livello (il menu) e il feed deve utilizzare lo schema di inventario v1.
Considera un feed batch simile al seguente:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
L'aggiornamento incrementale tramite POST sarà il seguente:
POST v2/apps/provider-project/entities/MenuItemOffer/menuitemoffer6680262:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "data": { "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 1.00, "priceCurrency": "USD" }, "vertical": "FOODORDERING" } }
Aggiunta di un'entità
Per aggiungere entità, evita di utilizzare gli aggiornamenti dell'inventario. Utilizza invece la procedura per i feed batch come descritta per lo schema di inventario v2.
Rimozione di un'entità
Per rimuovere le entità di primo livello, utilizza un endpoint leggermente modificato e usa HTTP DELETE anziché HTTP POST nella richiesta.
Non utilizzare HTTP DELETE per rimuovere una sottoentità all'interno di un'entità di primo livello, ad esempio un elemento del menu all'interno di un menu. Tratta invece la rimozione delle entità secondarie come un aggiornamento di un'entità di primo livello in cui l'entità secondaria viene rimossa dall' elenco o dal parametro pertinente.
Esempio 1: eliminazione di un'entità di primo livello
Considera una situazione in cui vuoi eliminare un ristorante in un feed che utilizza lo schema di inventario v1. Devi anche eliminare i relativi servizi e menu.
Un endpoint di esempio per un'entità menu con ID "https://www.provider.com/restaurant/menu/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Un endpoint di esempio per un'entità ristorante con ID "https://www.provider.com/restaurant/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Un endpoint di esempio per un'entità di servizio con ID "https://www.provider.com/restaurant/service/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Esempio 2: rimozione di entità secondarie
Per rimuovere una entità secondaria da un'entità di primo livello, invia l'entità di primo livello con l'entità secondaria rimossa dal campo corrispondente. L'esempio seguente presuppone che il feed utilizzi lo schema di inventario v1.
Ad esempio, per rimuovere un'area coperta dal servizio, aggiorna il servizio con l'area coperta dal servizio
rimuovere dall'elenco areaServed
.
POST v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr:push
Host: actions.googleapis.com
Content-Type: application/ld+json
{
"entity": {
// Note: "data" is not serialized as a string in our example for readability.
"data": {
"@type": "Service",
"provider": {
"@type": "Restaurant",
"@id": "https://www.provider.com/restaurant/nr"
},
"areaServed": [
{
"@type": "GeoCircle",
"geoMidpoint": {
"@type": "GeoCoordinates",
"latitude": "42.362757",
"longitude": "-71.087109"
},
"geoRadius": "10000"
}
// area2 is removed.
]
...
},
"vertical": "FOODORDERING"
}
}
Codici di risposta dell'API
Una chiamata riuscita non indica che il feed sia valido o corretto, ma solo che la chiamata all'API è stata effettuata. Le chiamate riuscite ricevono un codice di risposta HTTP 200, insieme a un corpo di risposta vuoto:
{}
In caso di errori, il codice di risposta HTTP non sarà 200 e il corpo della risposta indicarà cosa è andato storto.
Ad esempio, se l'utente ha impostato il valore "verticale" nell'involucro su
FAKE_VERTICAL
, riceverai il messaggio riportato di seguito:
{
"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\""
}
]
}
]
}
}
Esempio di codice
Di seguito sono riportati alcuni esempi di utilizzo dell'API Incremental Updates in vari linguaggi. Questi esempi utilizzano le librerie di autenticazione Google e presuppongono un feed che utilizza lo schema di inventario v1. Per soluzioni alternative, consulta Utilizzo di OAuth 2.0 per applicazioni da server a server.
Aggiornamento delle entità
Questo codice utilizza la libreria di autenticazione di Google per 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 update or add an entity */ async function updateEntity(entityId, 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/${encodeURIComponent(entityId)}:push`, body: { entity: { data: JSON.stringify(entity), vertical: 'FOODORDERING', } }, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } updateEntity(ENTITY_ID, entity)
Questo codice utilizza la libreria di autenticazione di Google per 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 = 'restaurant/http://www.provider.com/somerestaurant' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s:push' % ( PROJECT_ID, urllib.quote(ENTITY_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() # Populating the entity with wrapper entity = {} entity['data'] = data #entity JSON-LD serialized as string entity['vertical'] = 'FOODORDERING' request = {} request['entity'] = entity response = authed_session.post(ENDPOINT, json=request) print(response.text) #if successful, will be '{}'
Questo codice utilizza la libreria di autenticazione di Google per Java.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "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 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 entity) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s:push", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); JSONObject data = new JSONObject(); data.put("data", entity.toString()); data.put("vertical", "FOODORDERING"); JSONObject jsonBody = new JSONObject(); jsonBody.put("entity", data); // Execute POST request executePostRequest(endpoint, authToken, jsonBody); }
Rimozione di entità
Questo codice utilizza la libreria di autenticazione di Google per 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)
Questo codice utilizza la libreria di autenticazione di Google per 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 '{}'
Questo codice utilizza la libreria di autenticazione di Google per 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)); }
Casi d'uso
I seguenti casi d'uso sono esempi di aggiornamenti incrementali, aggiornamenti completi del feed e contenuti a un livello elevato nella chiamata dell'API:
Scenario | Entità di primo livello | Descrizione ed effetti |
---|---|---|
Disattivazione di un servizio | DisabledService |
Devi disattivare un servizio per un motivo imprevisto. Aggiornamenti incrementali: invia l'entità Feed completi: assicurati di aggiornare l'entità dei feed completi impostando |
Articolo specifico non disponibile | Menu |
Aggiornamenti incrementali: invia l'entità Menu
incapsulante con offer.inventoryLevel impostato su 0 per il valore MenuItem fornito e tutti gli altri dati invariati. |
Variazione di prezzo della voce di menu | Menu |
Aggiornamenti incrementali: invia l'entità Menu
incapsulante con offer.price impostato sul prezzo aggiornato per il dato
MenuItem e tutti gli altri dati invariati. |
Aggiungere una nuova entità di primo livello Applicabile solo per entità di tipo |
Menu , Restaurant , Service |
Ad esempio, devi aggiungere un nuovo menu a un ristorante. Aggiornamenti incrementali: invia la nuova entità menu insieme all'entità del ristorante con il relativo campo |
Eliminare definitivamente l'entità di primo livello Applicabile solo per entità di tipo |
Menu , Restaurant , Service |
Aggiornamenti incrementali: invia un'eliminazione esplicita. Feed completi: assicurati di rimuovere l'entità dai feed completi prima del successivo recupero da parte di Google, altrimenti l'entità verrà aggiunta di nuovo. |
Aggiungere una nuova area di consegna in un Service specifico |
Service |
Feed incrementali: invia l'entità Service in questione con tutti i suoi campi invariati, come faresti normalmente nei feed completi, con la nuova area di pubblicazione specificata entro areaServed del Service . |
Aggiorna l'orario di arrivo stimato della consegna in Service |
Service |
Feed incrementali: invia il valore Service come indicato nei feed, tranne per il fatto che il valore hoursAvailable.deliveryHours viene aggiornato di conseguenza. |
Aggiorna i prezzi di consegna in Service |
Service |
Feed incrementali: invia Service completo con
offers.priceSpecification.price aggiornato. |
Aggiornare gli orari di consegna o asporto a Service |
Service |
Feed incrementali: invia il valore Service come indicato nei feed, tranne per il fatto che il valore hoursAvailable viene aggiornato di conseguenza. |
Service (modifica importo ordine minimo) |
Service |
Feed incrementali: invia Service completo con
Service.offers.priceSpecification.eligibleTransactionVolume
aggiornato |
Eliminare definitivamente MenuItem |
Menu |
Feed incrementali: invia il Menu come nei feed, ma con questo MenuItem rimosso dall'elenco hasMenuItems . |
SLO sul tempo di elaborazione per i job batch e gli aggiornamenti incrementali
Un'entità aggiunta tramite un aggiornamento batch o incrementale verrà elaborata tra 1-2 giorni. Un'entità aggiornata o eliminata tramite un batch verrà elaborata in 2 ore, mentre un'entità aggiornata tramite un aggiornamento incrementale verrà elaborata in 5 minuti. Un'entità obsoleta viene eliminata dopo 7 giorni.
Puoi inviare a Google:
- Più job batch al giorno per mantenere aggiornato l'inventario OPPURE
- Un job batch al giorno e API incrementali per mantenere aggiornato l'inventario.