Aggiornamenti dell'inventario incrementale v2

Questa sezione descrive come inviare a Google aggiornamenti tempestivi delle entità dell'inventario. L'API Incremental Update ti consente di inviare aggiornamenti ed eliminare entità nell'inventario della sandbox o di produzione 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 di aggiornamento incrementale deve essere pubblicata entro un'ora. Se la modifica non deve essere applicata immediatamente, puoi utilizzare l'importazione collettiva. Gli aggiornamenti incrementali vengono elaborati in non più di cinque minuti.

Prerequisiti

Prima di implementare gli aggiornamenti incrementali, sono necessari i seguenti elementi:

  1. Viene creato un account di servizio con il ruolo di editor per il progetto Actions. Per maggiori dettagli, consulta Creare e configurare un progetto.
  2. I feed di dati di produzione o sandbox vengono ospitati e importati. Per maggiori dettagli, consulta Importazione in batch.
  3. (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

Nelle richieste riportate di seguito, sostituisci quanto segue:

  • PROJECT_ID: l'ID progetto Google Cloud associato al progetto che hai creato in Creare e configurare un progetto.
  • TYPE: il tipo di entità (proprietà @type) dell'oggetto nel feed di dati da aggiornare.
  • ENTITY_ID (solo endpoint di eliminazione): ID dell'entità da eliminare. 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 come yyyy-mm-ddTHH:mm:ssZ

Aggiorna endpoint

Per modificare un'entità, invia una richiesta POST HTTP al seguente endpoint e includi un payload di aggiornamenti e aggiunte. Puoi aggiornare fino a 1000 entità in una singola chiamata API.

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities:batchPush

Ad esempio, se vuoi aggiornare le entità in un progetto con un ID "delivery-provider-id", l'endpoint sarà il seguente:

https://actions.googleapis.com/v2/apps/delivery-provider-id/entities:batchpush

Elimina endpoint

Per eliminare una persona giuridica nel tuo inventario, invia una richiesta HTTP DELETE al seguente endpoint.

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME

Ad esempio, per eliminare un'entità "MenuSection" con ID "menuSection_122" dal progetto "delivery-provider-id", devi effettuare una chiamata API HTTP DELETE a:

https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING

Ambiente sandbox

Per utilizzare l'API Incremental Update nell'inventario della sandbox, segui le indicazioni riportate in Endpoint sopra, ma invia richieste a /v2/sandbox/apps/ anziché a /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

Aggiornamento delle entità

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.

Aggiorna il payload

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:
{
  "requests": [
    {
      "entity": {
        "data":"ENTITY_DATA",
        "name": "apps/project_id>/entities/type/entity_id"
      },
      "update_time":"UPDATE_TIMESTAMP"
    },
  ],
  "vertical": "FOODORDERING"
}

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.

Esempi

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/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"
}

Esempio 2: aggiornamento di più ristoranti

Per aggiornare due entità di ristorante in una singola chiamata API, la richiesta POST HTTP sarà la seguente:

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"
}

Esempio 3: aggiornamento del prezzo di un articolo 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/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"
}

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.

Eliminazione di un'entità di primo livello

Supponiamo che tu voglia eliminare un ristorante in un feed. Devi anche eliminare i relativi servizi e menu.

Un endpoint di esempio per un'entità menu con ID "provider/restaurant/menu/nr":

DELETE v2/apps/delivery-provider-id/entities/menu/provider%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/restaurant/provider%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/service/provider%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}

Rimozione di entità secondarie

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 pertinente o da reverseReference.

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 Update 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 = '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)

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 = '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 '{}'

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 = "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);
}

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à da aggiornare Descrizione ed effetti
Disattivazione di un servizio Service

Devi disattivare un servizio per un motivo imprevisto.

Aggiornamenti incrementali: aggiorna l'entità Service in discussione impostando la relativa proprietà isDisabled su true, ma mantieni invariate le altre proprietà.

Feed completi: assicurati di aggiornare l'entità dei feed completi impostando isDisabled su true prima del successivo recupero da parte di Google, altrimenti l'entità verrà riattivata.

Articolo specifico non disponibile MenuItemOffer Aggiornamenti incrementali: invia l'entità MenuItemOffer incapsulante con inventoryLevel impostato su 0 per il valore MenuItem fornito e tutti gli altri dati invariati.
Variazione di prezzo della voce di menu MenuItemOffer Aggiornamenti incrementali: invia l'entità MenuItemOffer incapsulante con 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 e Service.

Menu, Restaurant, Service

Ad esempio, devi aggiungere un nuovo menu a un ristorante.

Feed completi: aggiungi l'entità nei feed di dati e attendi l'importazione collettiva.

Eliminare definitivamente l'entità di primo livello

Applicabile solo per entità di tipo Menu, Restaurant e Service.

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 ServiceArea Feed incrementali: invia l'entità ServiceArea in questione con tutti i suoi campi invariati, come faresti normalmente nei feed completi, con la nuova area di caricamento specificata in polygon, geoRadius o postalCode.
Aggiorna l'orario di arrivo stimato della consegna in Service ServiceHours Feed incrementali: invia il valore ServiceHours come indicato nei feed, tranne per il fatto che il valore leadTimeMin viene aggiornato di conseguenza.
Aggiorna i prezzi di consegna in Service Fee Feed incrementali: invia la pubblicazione completa Fee con price aggiornato.
Aggiornare gli orari di consegna o asporto a Service ServiceHours Feed incrementali: invia il valore ServiceHours come indicato nei feed, tranne che le proprietà opens e closes vengono aggiornate di conseguenza.
Service (modifica importo ordine minimo) Fee Feed incrementali: invia Fee completo con minPrice aggiornato
Eliminare definitivamente un MenuItem Menu Feed incrementali: invia MenuItem come nei feed, ma con parentMenuSectionId vuoto.

SLO sul tempo di elaborazione per i job batch e gli aggiornamenti incrementali

Un'entità aggiornata o eliminata tramite un batch verrà elaborata entro 2 ore in modalità di massimo impegno, 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.