Cette section explique comment envoyer à Google des mises à jour urgentes de vos entités d'inventaire. L'API Incremental Update vous permet d'envoyer des mises à jour et de supprimer des entités dans votre inventaire de bac à sable ou de production en quasi-temps réel.
Cette fonctionnalité est principalement destinée aux mises à jour que vous ne pouvez pas prévoir, comme les fermetures d'urgence. En règle générale, toute modification envoyée via l'API Incremental Update doit être mise en ligne dans un délai maximum d'une heure. Si votre modification n'a pas besoin d'être reflétée immédiatement, vous pouvez utiliser l'ingestion par lot à la place. Les mises à jour incrémentielles sont traitées en moins de cinq minutes.
Prérequis
Vous devez disposer des éléments suivants avant d'implémenter des mises à jour incrémentielles:
- Un compte de service est créé avec le rôle Éditeur pour votre projet Actions. Pour en savoir plus, consultez la section Créer et configurer un projet.
- Les flux de données de production ou de bac à sable sont hébergés et ingérés. Pour en savoir plus, consultez la section Ingérer des données par lot.
- (Facultatif, mais recommandé) Installez la bibliothèque cliente Google dans la langue de votre choix pour faciliter l'utilisation d'OAuth 2.0 lors de l'appel de l'API. Les exemples de code 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.
Points de terminaison
Dans les requêtes ci-dessous, remplacez les éléments suivants:
- PROJECT_ID: ID de projet Google Cloud associé au projet que vous avez créé dans Créer et configurer un projet.
- TYPE: type d'entité (propriété
@type
) de l'objet de votre flux de données que vous souhaitez mettre à jour. - ENTITY_ID (point de terminaison de suppression uniquement): ID de l'entité à supprimer. Veillez à encoder votre ID d'entité en URL.
- DELETE_TIME (point de terminaison de suppression uniquement): champ facultatif permettant d'indiquer le moment où l'entité a été supprimée sur vos systèmes (par défaut, lors de la réception de la requête). La valeur de l'heure ne doit pas se situer dans le futur. Lorsque vous envoyez une entité via un appel incrémentiel, la gestion des versions des entités utilise également le champ
delete_time
en cas d'appel de suppression. Formater cette valeur au formatyyyy-mm-ddTHH:mm:ssZ
Mettre à jour le point de terminaison
Pour modifier une entité, envoyez une requête HTTP POST au point de terminaison suivant et incluez une charge utile de modifications et d'ajouts. Vous pouvez mettre à jour jusqu'à 1 000 entités dans un même appel d'API.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities:batchPush
Par exemple, si vous souhaitez mettre à jour des entités dans un projet avec l'ID "delivery-provider-id", le point de terminaison sera le suivant:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities:batchpush
Supprimer un point de terminaison
Pour supprimer une entité de votre inventaire, envoyez une requête HTTP DELETE au point de terminaison suivant.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Par exemple, pour supprimer une entité "MenuSection" dont l'ID est "menuSection_122" de votre projet "delivery-provider-id", vous devez effectuer un appel d'API HTTP DELETE à l'adresse:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Environnement de bac à sable
Pour utiliser l'API Incremental Update dans votre inventaire bac à sable, suivez les instructions des points de terminaison ci-dessus, mais envoyez des requêtes à /v2/sandbox/apps/
au lieu de /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
Mettre à jour des entités
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.
Modifier la charge utile
Le fichier JSON doit se présenter de la même manière que dans le flux par lot, avec les différences suivantes:
- Le corps 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 blancs afin de pouvoir insérer plus de données.
- L'enveloppe est la suivante:
{ "requests": [ { "entity": { "data":"ENTITY_DATA", "name": "apps/project_id>/entities/type/entity_id" }, "update_time":"UPDATE_TIMESTAMP" }, ], "vertical": "FOODORDERING" }
Dans la charge utile ci-dessus, remplacez les éléments suivants:
- ENTITY_DATA: entité au format JSON sérialisée en tant que chaîne. L'entité JSON-LD doit être transmise sous forme de chaîne dans le champ
data
. - UPDATE_TIMESTAMP (facultatif): code temporel de la mise à jour de l'entité dans vos systèmes. La valeur de l'heure ne doit pas se situer dans le futur. L'horodatage par défaut correspond au moment où Google reçoit la requête. Lorsque vous envoyez une entité via une requête incrémentielle, le gestion des versions des entités utilise également le champ
update_time
en cas de requête d'ajout/de mise à jour.
Exemples
Exemple 1: Modifier un restaurant
Supposons que vous deviez modifier de toute urgence le numéro de téléphone d'un restaurant. Votre mise à jour contient le fichier JSON de l'ensemble du restaurant.
Prenons l'exemple d'un flux 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 se présente alors comme suit:
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" }
Exemple 2: Modifier plusieurs restaurants
Pour mettre à jour deux entités de restaurant en un seul appel d'API, la requête HTTP POST se présente comme suit:
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" }
Exemple 3: Modifier 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 code JSON de l'ensemble de l'entité de niveau supérieur (le menu), et le flux utilise le schéma d'inventaire v1.
Prenons l'exemple d'un flux 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ésente alors comme suit:
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" }
Ajouter une entité
Pour ajouter des entités, évitez d'utiliser des mises à jour d'inventaire. Utilisez plutôt le processus de flux par lot, comme décrit pour le schéma d'inventaire v2.
Supprimer une entité
Pour supprimer des entités de premier niveau, vous devez utiliser un point de terminaison légèrement modifié et HTTP DELETE au lieu de HTTP POST dans la requête.
Supprimer une entité racine
Imaginons que vous souhaitiez supprimer un restaurant d'un flux. Vous devez également supprimer ses services et ses menus.
Exemple de point de terminaison pour une entité de menu avec l'ID "provider/restaurant/menu/nr":
DELETE v2/apps/delivery-provider-id/entities/menu/provider%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Exemple de point de terminaison pour une entité de restaurant avec l'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
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/service/provider%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Supprimer des sous-entités
N'utilisez pas la méthode HTTP DELETE pour supprimer une sous-entité dans une entité de niveau supérieur, comme un élément de menu dans un menu. Traitez 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 de la reverseReference appropriées.
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, ainsi qu'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 ce qui s'est mal passé.
Par exemple, si l'utilisateur a défini la valeur "vertical" dans l'enveloppe sur FAKE_VERTICAL
, vous recevrez le message ci-dessous:
{
"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 quelques exemples d'utilisation de l'API de mise à jour incrémentielle dans différentes langues. Ces exemples utilisent les bibliothèques Google Auth et supposent un flux utilisant le schéma d'inventaire v1. Pour connaître d'autres solutions, consultez la page Utiliser OAuth 2.0 pour les applications de serveur à serveur.
Mettre à jour des entités
Node.js
Ce code utilise la bibliothèque Google Auth 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 = '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
Ce code utilise la bibliothèque Google Auth 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 = '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
Ce code utilise la bibliothèque Google Auth pour 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); }
Supprimer des entités
Node.js
Ce code utilise la bibliothèque Google Auth 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 Google Auth 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 Google Auth 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 du flux et du contenu à un niveau élevé dans l'appel d'API:
Scénario | Entité à mettre à jour | Description et effets |
---|---|---|
Désactiver un service | Service |
Vous devez désactiver un service pour une raison imprévue. Mises à jour incrémentielles:mettez à jour l'entité Flux complets:veillez à mettre à jour l'entité à partir des flux complets pour que |
Article spécifique non disponible | MenuItemOffer |
Mises à jour incrémentielles:envoyez l'entité MenuItemOffer encapsulante avec inventoryLevel défini sur 0 pour le MenuItem donné, et toutes les autres données inchangées. |
Changement de prix d'un élément de menu | MenuItemOffer |
Mises à jour incrémentielles:envoyez l'entité MenuItemOffer encapsulante avec price défini sur le prix mis à jour pour le MenuItem donné, et toutes les autres données inchangées. |
Ajouter une entité de niveau supérieur Ne s'applique qu'aux entités de types |
Menu , Restaurant , Service |
Par exemple, vous devez ajouter un nouveau menu à un restaurant. Flux complets:ajoutez l'entité dans vos flux de données et attendez l'ingestion par lot. |
Supprimer définitivement une entité de niveau supérieur Ne s'applique qu'aux entités de types |
Menu , Restaurant , Service |
Mises à jour incrémentielles:envoyez une suppression explicite. Flux complets:assurez-vous de 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 |
ServiceArea |
Flux incrémentaux:envoyez l'entité ServiceArea en question avec tous ses champs intacts, comme vous le feriez normalement dans les flux complets, avec une nouvelle zone de diffusion spécifiée dans polygon , geoRadius ou postalCode . |
Modifier l'heure d'arrivée estimée de la livraison dans Service |
ServiceHours |
Flux incrémentaux:envoyez le ServiceHours de la même manière que dans les flux, à l'exception de son leadTimeMin , qui est mis à jour en conséquence. |
Mettre à jour les tarifs de livraison dans Service |
Fee |
Flux incrémentiels:envoyez une diffusion complète Fee avec price mis à jour. |
Modifier les horaires de livraison ou de vente à emporter dans Service |
ServiceHours |
Flux incrémentaux:envoyez le ServiceHours de la même manière que dans les flux, à l'exception de ses propriétés opens et closes , qui sont mises à jour en conséquence. |
Service (modifier le montant minimal de la commande) |
Fee |
Flux incrémentaux:envoyez un Fee complet avec minPrice mis à jour. |
Supprimer définitivement un MenuItem |
Menu |
Flux incrémentaux:envoyez le MenuItem de la même manière que dans les flux, mais avec parentMenuSectionId vide.
|
Contrat de niveau de service sur le temps de traitement des jobs par lot et des mises à jour incrémentielles
Une entité mise à jour ou supprimée via un lot sera traitée sous deux heures en mode "Mieux que possible", tandis qu'une entité mise à jour via une mise à jour incrémentielle sera traitée en cinq minutes. Une entité obsolète est supprimée au bout de sept jours.
Vous pouvez envoyer à Google:
- Plusieurs tâches par lot par jour pour mettre à jour votre inventaire OU
- Une tâche par lot par jour et des API incrémentielles pour mettre à jour votre inventaire.