En esta sección, se describe cómo puedes enviar a Google actualizaciones urgentes de tus feeds. La API de actualizaciones incrementales te permite actualizar y borrar entidades en tus feeds casi en tiempo real.
Esta función está orientada principalmente a actualizaciones que no puedes prever, como cierres de emergencia. Como regla general, cualquier cambio enviado a través de la API de actualizaciones incrementales debe ser un cambio que se publique en no más de una semana. Si tu cambio no necesita reflejarse de inmediato, puedes usar una actualización por lotes. Las actualizaciones incrementales se procesan en no más de cinco minutos.
Crear
Para implementar actualizaciones incrementales, haz lo siguiente:
- Sigue los pasos descritos en Crea y configura un proyecto para crear un proyecto.
- Sigue los pasos que se describen en Configura una cuenta de servicio para crear una cuenta de servicio. Ten en cuenta que debes ser “propietario” del proyecto para agregar una función de “Editor” en la cuenta de servicio
- (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 incluidas a continuación usan estas bibliotecas. De lo contrario, deberás manejar los intercambios de tokens de forma manual, como se describe en Usar OAuth 2.0 para acceder a las API de Google.
Extremo
Para notificar a Google sobre una actualización, realiza una solicitud HTTP POST a la API de Actualizaciones incrementales y, además, incluye una carga útil de actualizaciones y adiciones. El esquema de inventario que use determina el extremo al que debe realizar su solicitud:
Inventario de la v2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push
Inventario de la versión 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push
Para quitar una entidad, realiza una solicitud HTTP DELETE al siguiente extremo que corresponda al esquema de inventario que usas:
Inventario de la v2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Inventario de la versión 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
En las solicitudes anteriores, reemplaza lo siguiente:
- PROJECT_ID: Es el ID del proyecto de Google Cloud asociado al proyecto que creaste en Crea y configura un proyecto.
- TYPE (solo esquema de inventario v2): El tipo de entidad (propiedad
@type
) del objeto en su feed de datos que desea actualizar. - ENTITY_ID: ID de la entidad incluida en la carga útil. Asegúrate de que la URL codifique tu ID de entidad.
- DELETE_TIME (solo borrar extremos): 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 de tiempo no debe ser futuro. Cuando envías una entidad a través de una llamada incremental, el control de versiones de la entidad también usa el campo
delete_time
en el caso de una llamada de eliminación. Formatea este valor comoyyyy-mm-ddTHH:mm:ssZ
Por ejemplo, tienes un proyecto con un ID de "delivery-provider-id" que usa el esquema de inventario v2. Quieres realizar cambios en el restaurante con un tipo de entidad de restaurante de "MenuSection" y un ID de entidad de "menuSection_122". El extremo para las actualizaciones de tus datos sería el siguiente:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push
Para quitar esta misma entidad, debes hacer esta llamada a la API de HTTP DELETE:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Solicitudes de la zona de pruebas
Para las solicitudes de zona de pruebas, sigue las instrucciones de Extremo anteriores, pero realiza solicitudes a /v2/sandbox/apps/
en lugar de a /v2/apps/
. Por ejemplo, una solicitud de eliminación de zona de pruebas para el esquema de inventario v2 se estructura de la siguiente manera:
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Actualizaciones y adiciones
Tus feeds de lotes diarios también deben contener los cambios enviados a través de esta API. De lo contrario, las actualizaciones por lotes reemplazarán los cambios incrementales.
Carga útil
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 se enumera en el esquema de inventario.
El JSON debe aparecer de la misma manera que lo haría en el feed por lotes, con las siguientes diferencias:
- El cuerpo de la carga útil no debe superar los 5 MB. Al igual que con los feeds de lotes, te sugerimos que quites los espacios en blanco para que se adapten más datos.
- El sobre es el siguiente:
{ "entity": { "data":"ENTITY_DATA", "vertical":"FOODORDERING" }, "update_time":"UPDATE_TIMESTAMP" }
En la carga útil anterior, reemplaza lo siguiente:
- ENTITY_DATA: Entidad en formato JSON serializado como una string. La entidad JSON-LD debe pasarse como una string en el campo
data
. - UPDATE_TIMESTAMP (opcional): Marca de tiempo de cuando se actualizó la entidad en tus sistemas. El valor de tiempo no debe ser futuro. La marca de tiempo predeterminada corresponde al momento en que Google recibe la solicitud. Cuando envías 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 para agregar o actualizar.
Actualiza una entidad
Ejemplo 1: Actualiza un restaurante
Supongamos que necesitas actualizar el número de teléfono de un restaurante con urgencia. Tu actualización contiene el JSON para todo el restaurante.
Considere un feed por lotes similar al siguiente:
{ "@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 }
La actualización incremental por HTTP POST sería la siguiente:
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" } }
Ejemplo 2: Cómo actualizar el precio de un elemento de menú
Supongamos que necesitas cambiar el precio de un elemento de menú. Al igual que en el ejemplo 1, tu actualización debe contener el JSON para toda la entidad de nivel superior (el menú) y el feed usa el esquema de inventario v1.
Considere un feed por lotes similar al siguiente:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
La actualización incremental a través de POST sería la siguiente:
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" } }
Agrega una entidad
Para agregar entidades, evite usar actualizaciones de inventario. En su lugar, usa el proceso de los feeds por lotes como se describe en el esquema de inventario de la versión 2.
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.
No uses HTTP DELETE para quitar una subentidad dentro de una entidad de nivel superior, como un elemento de menú. En su lugar, trata la eliminación de subentidades como una actualización a una entidad de nivel superior en la que la subentidad se quita de la lista o el parámetro relevante.
Ejemplo 1: Borra una entidad de nivel superior
Considera una situación en la que deseas borrar un restaurante en un feed que usa el esquema de inventario v1. También debes borrar sus servicios y menús.
Un extremo de muestra para una entidad de menú con el ID https://www.provider.com/restaurant/menu/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Un extremo de muestra para una entidad de restaurante con el ID https://www.provider.com/restaurant/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Un extremo de muestra para una entidad de servicio con ID https://www.provider.com/restaurant/service/nr":
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Ejemplo 2: Quita las subentidades
Para quitar una subentidad dentro de una entidad de nivel superior, envía la entidad de nivel superior con la subentidad quitada del campo correspondiente. En el siguiente ejemplo, se supone que el feed usa el esquema de inventario v1.
Por ejemplo, para quitar un área de servicio, actualízalo con el área quitada de la lista 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"
}
}
Códigos de respuesta de la API
Una llamada correcta no significa que el feed sea válido o correcto, sino 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 indicará qué salió mal.
Por ejemplo, si el usuario configuró el valor de la 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\""
}
]
}
]
}
}
Ejemplo de código
A continuación, se muestran algunos ejemplos de cómo usar la API de actualizaciones incrementales en varios lenguajes. Estas muestras usan las bibliotecas de Google Auth y suponen un feed que usa el esquema de inventario v1. Si quieres obtener 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 = '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
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 = '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
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 = "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); }
Quita 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 completas y el contenido en un nivel alto en la llamada a la API:
Situación | Entidad de nivel superior | Descripción y efectos |
---|---|---|
Inhabilita un servicio | DisabledService |
Debe inhabilitar un servicio por una razón imprevista. Actualizaciones incrementales: Se cambió la entidad Feeds completos: Asegúrate de actualizar la entidad de los feeds completos para que |
Un artículo específico está agotado | Menu |
Actualizaciones incrementales: Envía la entidad Menu de encapsulamiento con offer.inventoryLevel establecido en 0 para el MenuItem determinado y todos los demás datos sin cambios. |
Cambio en el precio del elemento del menú | Menu |
Actualizaciones incrementales: Envía la entidad Menu de encapsulamiento con offer.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 tipos |
Menu , Restaurant , Service |
Por ejemplo, debes agregar un menú nuevo a un restaurante. Actualizaciones incrementales: Se envía la nueva entidad de menú, junto con la entidad de restaurante con su campo |
Borrar la entidad de nivel superior de forma permanente Solo se aplica a entidades de tipos |
Menu , Restaurant , Service |
Actualizaciones incrementales: Envía una eliminación explícita. Feeds completos: Asegúrate de quitar la entidad de los feeds completos antes de que Google vuelva a realizarla. De lo contrario, la entidad volverá a agregarse. |
Agregue un área de entrega nueva en un Service específico |
Service |
Feeds incrementales: Envía la entidad Service en cuestión con todos sus campos intactos, como lo harías normalmente en los feeds completos, con el nuevo área de entrega especificado en areaServed de las Service . |
Actualizar la hora de entrega estimada de entrega en Service |
Service |
Feeds incrementales: Envía el Service de la misma manera que en los feeds, excepto que su hoursAvailable.deliveryHours se actualiza según corresponda. |
Actualiza los precios de entrega en Service |
Service |
Feeds incrementales: Envía el Service completo con offers.priceSpecification.price actualizado. |
Actualiza el horario de entrega o comida para llevar en Service |
Service |
Feeds incrementales: Envía el Service de la misma manera que en los feeds, excepto que su hoursAvailable se actualiza según corresponda. |
Service (cambiar el importe mínimo de pedido) |
Service |
Feeds incrementales: Envía el Service completo con Service.offers.priceSpecification.eligibleTransactionVolume actualizado |
Borrar MenuItem definitivamente |
Menu |
Feeds incrementales: Envía el Menu del mismo modo que en los feeds, pero quita este MenuItem de la lista hasMenuItems . |
SLO en el tiempo de procesamiento para trabajos por lotes y actualizaciones incrementales
Una entidad agregada mediante una actualización por lotes o incremental se procesará en 1 o 2 días. Una entidad actualizada o borrada a través de un lote se procesará en 2 horas, mientras que una entidad actualizada a través de una actualización incremental se procesará en 5 minutos. Una entidad inactiva se borra en 7 días.
Puedes enviar a Google:
- Varios trabajos por lotes por día para mantener tu inventario actualizado
- Un trabajo por lotes por día y API incrementales para mantener tu inventario actualizado.