En esta sección, se describe cómo enviar actualizaciones urgentes de las entidades de tu inventario a Google. La API de actualización incremental te permite enviar actualizaciones y borrar entidades en tu inventario de producción o zona de pruebas casi en tiempo real.
Esta función está diseñada principalmente para actualizaciones que no puedes prever, como cierres de emergencia. Como regla, cualquier cambio enviado a través de la API de Incremental Update debe ser un cambio que no deba implementarse en más de una hora. Si el cambio no necesita reflejarse de inmediato, puedes usar la transferencia por lotes. Las actualizaciones incrementales se procesan en no más de cinco minutos.
Requisitos previos
Los siguientes elementos son obligatorios para implementar actualizaciones incrementales:
- Se crea una cuenta de servicio con el rol de editor para tu proyecto de Acciones. Para obtener más detalles, consulta Crea y configura un proyecto.
- Se alojan y transfieren los feeds de datos de la zona de pruebas o de producción. Para obtener más detalles, consulta Transferencia por lotes.
- (Opcional, pero recomendado) Instala la biblioteca cliente de Google en el lenguaje que elijas para facilitar el uso de OAuth 2.0 cuando llames a la API. Las muestras de código que se incluyen a continuación usan estas bibliotecas. De lo contrario, deberás controlar los intercambios de tokens de forma manual, como se describe en Usa OAuth 2.0 para acceder a las APIs de Google.
Extremos
En las siguientes solicitudes, reemplaza lo siguiente:
- PROJECT_ID: Es el ID del proyecto de Google Cloud asociado con el proyecto que creaste en Crea y configura un proyecto.
- TYPE: Es el tipo de entidad (propiedad
@type
) del objeto de tu feed de datos que deseas actualizar. - ENTITY_ID (solo borrar extremo): ID de la entidad que se borrará. Asegúrate de codificar en formato URL el ID de tu entidad.
- DELETE_TIME (solo borrar extremo): campo opcional para indicar la hora en que se borró la entidad en tus sistemas (el valor predeterminado es cuando se recibe la solicitud). El valor del tiempo no debe ser futuro. Cuando se envía una entidad a través de una llamada incremental, el control de versiones de entidades también usa el campo
delete_time
en el caso de una llamada de eliminación. Aplica el formato deyyyy-mm-ddTHH:mm:ssZ
a este valor
Actualizar extremo
Para modificar una entidad, realiza una solicitud HTTP POST al siguiente extremo y, además, incluye una carga útil de actualizaciones y adiciones. Puedes realizar actualizaciones en hasta 1,000 entidades con una sola llamada a la API.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities:batchPush
Por ejemplo, si quieres actualizar entidades en un proyecto con un ID “delivery-provider-id”, el extremo sería el siguiente:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities:batchpush
Borrar extremo
Para borrar una entidad de tu inventario, realiza una solicitud HTTP DELETE al siguiente extremo.
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Por ejemplo, para borrar una entidad "MenuSection" con el ID "menuSección_122" de tu proyecto "delivery-provider-id", deberás realizar una llamada a la API de HTTP DELETE para lo siguiente:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Entorno de zona de pruebas
Para usar la API de actualización incremental en tu inventario de la zona de pruebas, sigue las instrucciones de los Extremos anteriores, pero realiza solicitudes a /v2/sandbox/apps/
en lugar 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
Actualiza entidades
Cada solicitud POST debe incluir los parámetros de la solicitud junto con la carga útil JSON que contiene los datos estructurados de cualquier tipo de entidad que figure en el esquema del inventario.
Actualiza la carga útil
El JSON debería aparecer igual que en el feed por lotes, con las siguientes diferencias:
- El cuerpo de la carga útil no debe superar los 5 MB de tamaño. Al igual que con los feeds por lotes, te sugerimos que quites los espacios en blanco para agregar más datos.
- El sobre es el siguiente:
{ "requests": [ { "entity": { "data":"ENTITY_DATA", "name": "apps/project_id>/entities/type/entity_id" }, "update_time":"UPDATE_TIMESTAMP" }, ], "vertical": "FOODORDERING" }
En la carga útil anterior, reemplaza lo siguiente:
- ENTITY_DATA: Entidad en formato JSON serializada como una string. La entidad JSON-LD se debe pasar como una cadena en el campo
data
. - UPDATE_TIMESTAMP (opcional): Es la marca de tiempo del momento en que se actualizó la entidad en tus sistemas. El valor del tiempo no debe ser futuro. La marca de tiempo predeterminada es el momento en que Google recibe la solicitud. Cuando se envía una entidad a través de una solicitud incremental, el control de versiones de la entidad también usa el campo
update_time
en el caso de una solicitud de adición o actualización.
Ejemplos
Ejemplo 1: Actualización de un restaurante
Supongamos que necesitas actualizar el número de teléfono de un restaurante de forma urgente. Tu actualización contiene el archivo JSON para todo el restaurante.
Considera un feed por lotes que se vea de la siguiente manera:
{ "@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 }
Entonces, tu actualización incremental por HTTP POST sería la siguiente:
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" }
Ejemplo 2: Actualización de varios restaurantes
Para actualizar dos entidades de restaurantes en una sola llamada a la API, la solicitud HTTP POST sería la siguiente:
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" }
Ejemplo 3: Actualiza el precio de un producto de menú
Supongamos que necesitas cambiar el precio de un producto del menú. Al igual que en el ejemplo 1, tu actualización debe contener el archivo JSON para toda la entidad de nivel superior (el menú), y el feed usa el esquema de inventario v1.
Considera un feed por lotes que se vea de la siguiente manera:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
Entonces, tu actualización incremental a través de POST sería la siguiente:
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" }
Agrega una entidad
Para agregar entidades, evita usar actualizaciones de inventario. En su lugar, usa el proceso de feeds por lotes como se describe en el esquema de inventario v2.
Quita una entidad
Para quitar entidades de nivel superior, usa un extremo ligeramente modificado y usa HTTP DELETE en lugar de HTTP POST en la solicitud.
Borra una entidad de nivel superior
Considera la situación en la que quieres borrar un restaurante de un feed. También debes borrar sus servicios y menús.
Este es un extremo de muestra para una entidad de menú con el 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 extremo de muestra para una entidad de restaurante con el 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 extremo de muestra para una entidad de servicio con el 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
}
Quita subentidades
No uses HTTP DELETE para quitar una subentidad dentro de una entidad de nivel superior, como un elemento de menú dentro de un menú. En cambio, trata la eliminación de las subentidades como una actualización a una entidad de nivel superior en la que la subentidad se quita de la lista relevante o reverseReference.
Códigos de respuesta de la API
Una llamada exitosa no significa que el feed sea válido o correcto, solo que se realizó la llamada a la API. Las llamadas exitosas reciben un código de respuesta HTTP 200, junto con un cuerpo de respuesta vacío:
{}
Para las fallas, el código de respuesta HTTP no será 200, y el cuerpo de la respuesta indica qué salió mal.
Por ejemplo, si el usuario estableció el valor "vertical" del sobre en FAKE_VERTICAL
, recibirás el siguiente mensaje:
{
"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\""
}
]
}
]
}
}
Muestra de código
A continuación, se muestran algunos ejemplos de cómo usar la API de Incremental Update en varios lenguajes. En estas muestras, se usan las bibliotecas de Google Auth y se supone un feed con el esquema de inventario v1. Si quieres ver soluciones alternativas, consulta Usa OAuth 2.0 para aplicaciones de servidor a servidor.
Actualiza entidades
Node.js
Este código usa la biblioteca de autenticación de Google para 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
Este código usa la biblioteca de autenticación de Google para 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
Este código usa la biblioteca de autenticación de Google para 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); }
Cómo quitar entidades
Node.js
Este código usa la biblioteca de autenticación de Google para 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
Este código usa la biblioteca de autenticación de Google para 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
Este código usa la biblioteca de autenticación de Google para 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)); }
Casos de uso
Los siguientes casos de uso son ejemplos de actualizaciones incrementales, actualizaciones de feed completo y contenido en un nivel alto en la llamada a la API:
Situación | Entidad que se actualizará | Descripción y efectos |
---|---|---|
Inhabilita un servicio | Service |
Debes inhabilitar un servicio por una razón imprevista. Actualizaciones incrementales: Para actualizar la entidad Feeds completos: Asegúrate de actualizar la entidad de los feeds completos para que |
El artículo específico está agotado | MenuItemOffer |
Actualizaciones incrementales: Envía la entidad MenuItemOffer de encapsulación con inventoryLevel configurado en 0 para el MenuItem determinado y todos los demás datos sin cambios. |
Cambio de precio del elemento de menú | MenuItemOffer |
Actualizaciones incrementales: Envía la entidad MenuItemOffer encapsulada con price establecido en el precio actualizado para el MenuItem determinado y todos los demás datos sin cambios. |
Agregar nueva entidad de nivel superior Solo se aplica a entidades de los tipos |
Menu , Restaurant y Service |
Por ejemplo, necesitas agregar un nuevo menú a un restaurante. Feeds completos: Agrega la entidad a tus feeds de datos y espera la transferencia por lotes. |
Borrar la entidad de nivel superior de forma permanente Solo se aplica a entidades de los tipos |
Menu , Restaurant y Service |
Actualizaciones incrementales: Envía una eliminación explícita. Feeds completos: Asegúrate de quitar la entidad de los feeds completos antes de la próxima recuperación que realice Google. De lo contrario, se volverá a agregar. |
Agrega una nueva área de entrega a un Service específico |
ServiceArea |
Feeds incrementales: Envía la entidad ServiceArea en cuestión con todos sus campos intactos, como lo harías normalmente en los feeds completos, con el área de entrega nueva especificada en polygon , geoRadius o postalCode . |
Actualiza la hora estimada de llegada a Service |
ServiceHours |
Feeds incrementales: Envía el ServiceHours igual que en los feeds, excepto que su leadTimeMin se actualiza en consecuencia. |
Actualiza los precios de entrega en Service |
Fee |
Feeds incrementales: Envía el valor de entrega completo el Fee con price actualizado. |
Actualiza los horarios de comida para llevar o entrega a domicilio en Service |
ServiceHours |
Feeds incrementales: Envía el ServiceHours igual que en los feeds, excepto que sus propiedades opens y closes se actualicen en consecuencia. |
Service (cambiar el importe mínimo del pedido) |
Fee |
Feeds incrementales: Se debe enviar Fee completo con minPrice actualizado. |
Borrar un elemento MenuItem de forma permanente |
Menu |
Feeds incrementales: Envía el valor de MenuItem igual que en los feeds, pero con parentMenuSectionId vacío.
|
SLO de tiempo de procesamiento para trabajos por lotes y actualizaciones incrementales
Una entidad que se actualice o se borre a través de un lote se procesará dentro de las 2 horas en el modo de mejor esfuerzo, mientras que una entidad que se actualice a través de una actualización incremental se procesará en 5 minutos. Una entidad inactiva se borra dentro de 7 días.
Puedes enviarle a Google lo siguiente:
- Varios trabajos por lotes por día para mantener tu inventario actualizado
- Un trabajo por lotes por día y APIs incrementales para mantener tu inventario actualizado.