Mises à jour d'inventaire incrémentielles de la version 1

Cette section explique comment envoyer à Google les mises à jour de vos flux dans le temps. Cette API vous permet de mettre à jour et de supprimer les entités de vos flux quasiment en temps réel.

Cette fonctionnalité est principalement destinée aux mises à jour que vous ne pouvez pas prévoir, comme les fermetures en cas d'urgence. En règle générale, toute modification soumise via l'API Progressive Updates doit être mise en œuvre dans un délai maximal d'une semaine. Si votre modification n'a pas besoin d'être reflétée immédiatement, vous pouvez utiliser une mise à jour par lot. Les mises à jour incrémentielles sont traitées en cinq minutes maximum.

Configuration

Pour implémenter des mises à jour incrémentielles:

  1. Suivez les étapes décrites dans Créer et configurer un projet.
  2. Suivez les étapes décrites dans Configurer un compte de service pour créer un compte de service. Notez que vous devez être le "propriétaire" du projet pour ajouter un rôle d'éditeur au compte de service.
  3. (Facultatif, mais recommandé) Installez la bibliothèque cliente Google dans le langage de votre choix pour faciliter l'utilisation du protocole OAuth 2.0 lorsque vous appelez l'API. Les exemples de code inclus ci-dessous utilisent ces bibliothèques. Sinon, vous devrez gérer manuellement les échanges de jetons, comme décrit dans la section Utiliser OAuth 2.0 pour accéder aux API Google.

Endpoint

Pour avertir Google d'une mise à jour, envoyez une requête HTTP POST à l'API Progressive Updates et incluez une charge utile de mises à jour et d'ajouts. Le schéma d'inventaire que vous utilisez détermine le point de terminaison auquel envoyer votre requête:

Inventaire v2

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push

Inventaire v1

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push

Pour supprimer une entité, envoyez une requête HTTP DELETE au point de terminaison suivant qui correspond au schéma d'inventaire que vous utilisez:

Inventaire v2

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

Inventaire v1

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

Dans les requêtes ci-dessus, remplacez les éléments suivants:

  • PROJECT_ID: ID du projet Google Cloud associé au projet que vous avez créé dans Créer et configurer un projet.
  • TYPE (schéma d'inventaire v2 uniquement): type d'entité (propriété @type) de l'objet de votre flux de données que vous souhaitez mettre à jour.
  • ENTITY_ID : ID de l'entité incluse dans la charge utile. Veillez à encoder en URL l'ID de votre entité.
  • DELETE_TIME (supprimer le point de terminaison uniquement): champ facultatif indiquant l'heure à laquelle l'entité a été supprimée sur vos systèmes (la valeur par défaut correspond au moment où la requête est reçue). La valeur temporelle ne doit pas se situer dans le futur. Lors de l'envoi d'une entité via un appel incrémentiel, la gestion des versions des entités utilise également le champ delete_time dans le cas d'un appel de suppression. Mettez en forme cette valeur au format yyyy-mm-ddTHH:mm:ssZ

Par exemple, vous avez un projet dont l'ID est "delivery-provider-id" qui utilise le schéma d'inventaire v2. Vous souhaitez modifier le restaurant dont le type d'entité est "MenuSection" et l'ID d'entité "menuSection_122". Le point de terminaison pour la mise à jour de vos données est le suivant:

https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push

Pour supprimer cette même entité, vous devez effectuer l'appel d'API HTTP DELETE suivant:

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

Requêtes sandbox

Pour les requêtes en bac à sable, suivez les conseils de la section Point de terminaison ci-dessus, mais envoyez des requêtes à /v2/sandbox/apps/ au lieu de /v2/apps/. Par exemple, une requête de suppression de bac à sable pour le schéma d'inventaire v2 est structurée comme suit:

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

Mises à jour et ajouts

Vos flux quotidiens par lot doivent également contenir toutes les modifications envoyées via cette API. Sinon, les mises à jour par lot écraseront vos modifications incrémentielles.

Charge utile

Chaque requête POST doit inclure les paramètres de requête ainsi que la charge utile JSON contenant les données structurées de tout type d'entité listé dans le schéma d'inventaire.

Le fichier JSON doit s'afficher de la même manière que le flux par lot, avec les différences suivantes:

  • La taille de la charge utile ne doit pas dépasser 5 Mo. Comme pour les flux par lot, nous vous suggérons de supprimer les espaces dans le but d'ajuster davantage de données.
  • L'enveloppe est la suivante:
{
  "entity": {
    "data":"ENTITY_DATA",
    "vertical":"FOODORDERING"
  },
  "update_time":"UPDATE_TIMESTAMP"
}

Dans la charge utile ci-dessus, remplacez les éléments suivants:

  • ENTITY_DATA : entité au format JSON sérialisée sous forme de chaîne. L'entité JSON-LD doit être transmise en tant que chaîne dans le champ data.
  • UPDATE_TIMESTAMP (facultatif): horodatage de la mise à jour de l'entité dans vos systèmes. La valeur temporelle ne doit pas se situer dans le futur. L'horodatage par défaut correspond au moment où Google reçoit la requête. Lors de l'envoi d'une entité via une requête incrémentielle, la gestion des versions de l'entité utilise également le champ update_time dans le cas d'une requête d'ajout/de mise à jour.

Mettre à jour une entité

Exemple 1: Mettre à jour un restaurant

Supposons que vous ayez un besoin urgent de modifier le numéro de téléphone d'un restaurant. Votre mise à jour contient le code JSON pour l'ensemble du restaurant.

Prenons l'exemple d'un flux de données par lot qui se présente comme suit:

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

Votre mise à jour incrémentielle par HTTP POST serait alors la suivante:

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

Exemple 2: Mettre à jour le prix d'un élément de menu

Supposons que vous deviez modifier le prix d'un élément de menu. Comme dans l'exemple 1, votre mise à jour doit contenir le fichier JSON de l'intégralité de l'entité de premier niveau (le menu), et le flux utilise le schéma d'inventaire v1.

Prenons l'exemple d'un flux de données par lot qui se présente comme suit:

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

Votre mise à jour incrémentielle via POST se présenterait comme suit:

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

Ajouter une entité

Pour ajouter des entités, évitez d'utiliser les mises à jour de l'inventaire. Utilisez plutôt le processus de flux par lot, comme décrit dans le schéma d'inventaire v2.

Supprimer une entité

Pour supprimer des entités de niveau supérieur, utilisez un point de terminaison légèrement modifié et utilisez HTTP DELETE au lieu de HTTP POST dans la requête.

N'utilisez pas HTTP DELETE pour supprimer une sous-entité d'une entité de niveau supérieur, telle qu'un élément de menu. Considérez plutôt la suppression des sous-entités comme une mise à jour d'une entité de niveau supérieur dans laquelle la sous-entité est supprimée de la liste ou du paramètre concernés.

Exemple 1: Suppression d'une entité de niveau supérieur

Imaginons que vous souhaitiez supprimer un restaurant d'un flux qui utilise le schéma d'inventaire v1. Vous devez également supprimer ses services et ses menus.

Exemple de point de terminaison pour une entité de menu associée à l'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

Exemple de point de terminaison pour une entité de restaurant ayant l'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

Exemple de point de terminaison pour une entité de service avec l'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
}

Exemple 2: Supprimer des sous-entités

Pour supprimer une sous-entité d'une entité de niveau supérieur, vous devez envoyer l'entité de niveau supérieur en supprimant la sous-entité du champ correspondant. L'exemple suivant suppose que le flux utilise le schéma d'inventaire v1.

Par exemple, pour supprimer une zone desservie, mettez à jour le service en le supprimant de la liste 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"
  }
}

Codes de réponse de l'API

Un appel réussi ne signifie pas que le flux est valide ou correct, mais seulement que l'appel d'API a été effectué. Les appels réussis reçoivent un code de réponse HTTP 200 avec un corps de réponse vide:

{}

En cas d'échec, le code de réponse HTTP ne sera pas 200 et le corps de la réponse indiquera le problème.

Par exemple, si l'utilisateur a défini la valeur "vertical" dans l'enveloppe sur FAKE_VERTICAL, le message ci-dessous s'affiche:

{
  "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\""
          }
        ]
      }
    ]
  }
}

Exemple de code

Vous trouverez ci-dessous des exemples d'utilisation de l'API Cumulative Updates dans différents langages. Ces exemples utilisent les bibliothèques Google Auth et supposent un flux à l'aide du schéma d'inventaire v1. Pour découvrir d'autres solutions, consultez la page Utiliser OAuth 2.0 pour l'authentification serveur à serveur.

Mettre à jour des entités

Node.js

Ce code utilise la bibliothèque d'authentification Google pour 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)

Python

Ce code utilise la bibliothèque d'authentification Google pour 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 '{}'

Java

Ce code utilise la bibliothèque d'authentification Google pour 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);
}

Suppression d'entités

Node.js

Ce code utilise la bibliothèque d'authentification Google pour 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

Ce code utilise la bibliothèque d'authentification Google pour 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

Ce code utilise la bibliothèque d'authentification Google pour 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));
}

Cas d'utilisation

Les cas d'utilisation suivants sont des exemples de mises à jour incrémentielles, de mises à jour complètes de flux et de contenu dans les grandes lignes de l'appel d'API:

Scénario Entité de niveau supérieur Description et effets
Désactiver un service DisabledService

Vous devez désactiver un service pour une raison imprévue.

Mises à jour incrémentielles : envoyez l'entité Service en question avec @type modifiée sur DisabledService, mais conservez les autres propriétés.

Flux complets:mettez à jour l'entité à partir des flux complets en définissant @type sur DisabledService avant la prochaine récupération par Google. Sinon, l'entité sera réactivée.

Un article spécifique n'est pas disponible Menu Mises à jour incrémentielles : envoyez l'entité Menu encapsulant avec offer.inventoryLevel défini sur 0 pour le MenuItem donné, et toutes les autres données inchangées.
Modification du prix d'un élément de menu Menu Mises à jour incrémentielles:envoyez l'entité Menu encapsulant avec offer.price défini sur le prix mis à jour pour le MenuItem donné, et toutes les autres données telles quelles.

Ajouter une entité de niveau supérieur

Uniquement applicable aux entités de type Menu, Restaurant et Service.

Menu, Restaurant, Service

Par exemple, vous devez ajouter un nouveau menu à un restaurant.

Mises à jour incrémentielles : l'entité de menu ainsi que l'entité de restaurant avec son champ hasMenu sont mises à jour en conséquence.

Supprimer définitivement l'entité de niveau supérieur

Uniquement applicable aux entités de type Menu, Restaurant et Service.

Menu, Restaurant, Service

Mises à jour incrémentielles : envoyez une suppression explicite.

Flux complets : veillez à supprimer l'entité des flux complets avant la prochaine récupération par Google, sinon elle sera de nouveau ajoutée.

Ajouter une zone de livraison dans une Service spécifique Service Flux partiels:envoyez l'entité Service en question avec tous ses champs intacts, comme vous le feriez normalement dans les flux complets, avec une nouvelle zone de livraison spécifiée dans areaServed autour du Service.
Mettre à jour l'heure d'arrivée prévue pour la livraison à Service Service Flux partiels : envoyez l'élément Service de la même manière que dans les flux, sauf si la valeur hoursAvailable.deliveryHours est mise à jour en conséquence.
Mettre à jour les frais de livraison dans le pays suivant : Service Service Flux partiels:envoyez l'intégralité de l'élément Service en mettant à jour offers.priceSpecification.price.
Modifier les horaires de livraison ou de vente à emporter dans le pays suivant : Service Service Flux partiels:envoyez l'élément Service de la même manière que dans les flux, sauf si la valeur hoursAvailable est mise à jour en conséquence.
Service (modifier le montant minimal de commande) Service Flux partiels : envoyez l'élément Service complet avec Service.offers.priceSpecification.eligibleTransactionVolume mis à jour.
Supprimer MenuItem définitivement Menu Flux partiels : envoyez l'élément Menu de la même manière que dans les flux, mais en supprimant cet élément MenuItem de la liste hasMenuItems.

SLO sur le temps de traitement des tâches par lot et des mises à jour incrémentielles

Une entité ajoutée via une mise à jour par lot ou incrémentielle sera traitée dans un à deux jours. Une entité mise à jour ou supprimée via un lot sera traitée dans deux heures, tandis qu'une entité mise à jour via une mise à jour incrémentielle sera traitée dans cinq minutes. Une entité obsolète est supprimée dans sept jours.

Vous pouvez envoyer à Google:

  • Plusieurs tâches par lot pour maintenir votre inventaire à jour, OU
  • Une tâche par lot et des API incrémentielles pour maintenir votre inventaire à jour.