Atualizações incrementais de inventário v2

.

Esta seção descreve como enviar atualizações urgentes do seu inventário entidades ao Google. A API Incremental Update permite enviar atualizações e excluir entidades em seu inventário de sandbox ou de produção quase em tempo real.

Essa funcionalidade se destina principalmente a atualizações que você não pode prever, como fechamentos de emergência. Como regra geral, qualquer alteração enviada por meio do A API Incremental Update precisa ser uma mudança que precisa ser ativada em até por hora. Se sua alteração não precisar ser refletida imediatamente, você poderá usar a ingestão em lote. Atualizações incrementais são processadas em no máximo cinco minutos.

Pré-requisitos

Os itens a seguir são necessários antes da implementação de atualizações incrementais:

  1. Uma conta de serviço é criada com o papel de editor no projeto do Actions. Para mais detalhes, consulte Crie e configure um projeto.
  2. Os feeds de dados de produção ou de sandbox são hospedados e ingeridos. Para mais detalhes, consulte Ingestão em lote.
  3. (Opcional, mas recomendado) Instale a biblioteca de cliente do Google na linguagem de sua escolha para facilitar o uso do OAuth 2.0 ao chamar o API. Os exemplos de código abaixo usam essas bibliotecas. Caso contrário, precisa lidar com trocas de token manualmente, conforme descrito em Como usar o OAuth 2.0 para acessar as APIs do Google.

Endpoints

Nas solicitações abaixo, substitua o seguinte:

  • PROJECT_ID: ID do projeto do Google Cloud associado ao projeto que você criado em Criar e configurar um projeto.
  • TYPE: o tipo de entidade (propriedade @type) do objeto no feed de dados que você deseja atualizar.
  • ENTITY_ID (excluir apenas o endpoint): ID da entidade a ser excluída. Não se esqueça de URL codifica o ID da entidade.
  • DELETE_TIME (excluir apenas o endpoint): campo opcional para indicar o hora em que a entidade foi excluída nos seus sistemas (o padrão é quando a solicitação é recebidas). O valor de tempo não pode estar no futuro. Ao enviar uma entidade com uma chamada incremental de controle de versão de entidade também usa o campo delete_time no caso de uma chamada de exclusão. Formate isto valor como yyyy-mm-ddTHH:mm:ssZ

Atualizar endpoint

Para modificar uma entidade, faça uma solicitação HTTP POST para o seguinte endpoint e incluem um payload de atualizações e inclusões. Você pode fazer atualizações de até mil entidades em uma única chamada de API.

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

Por exemplo, se você quiser atualizar entidades em um projeto com um ID "delivery-provider-id" o endpoint será o seguinte:

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

Excluir endpoint

Para excluir uma entidade do seu inventário, faça uma solicitação DELETE HTTP para o ponto de extremidade a seguir.

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

Por exemplo, para excluir uma "MenuSection" entidade com o ID "menuSection_122" do seu "delivery-provider-id" projeto, você faria uma chamada de API DELETE HTTP para:

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

Ambiente de sandbox

Para usar a API Incremental Update no inventário de sandbox, siga as orientações nos Endpoints acima, mas fazer solicitações para /v2/sandbox/apps/ em vez de para /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

Como atualizar entidades

Cada solicitação POST deve incluir os parâmetros de solicitação junto com o JSON que contém os dados estruturados de qualquer tipo de entidade listado no esquema de inventário.

Atualizar payload

O JSON deve aparecer da mesma forma que no feed em lote, com o as seguintes diferenças:

  • O corpo do payload não pode exceder 5 MB. Da mesma forma que o batch feeds, sugerimos que você elimine os espaços em branco para ajustar mais dados.
  • O envelope é o seguinte:
{
  "requests": [
    {
      "entity": {
        "data":"ENTITY_DATA",
        "name": "apps/project_id>/entities/type/entity_id"
      },
      "update_time":"UPDATE_TIMESTAMP"
    },
  ],
  "vertical": "FOODORDERING"
}

No payload acima, substitua o seguinte:

  • ENTITY_DATA: entidade no formato JSON serializada como uma string. A A entidade JSON-LD precisa ser transmitida como uma string no campo data.
  • UPDATE_TIMESTAMP (opcional): carimbo de data/hora de quando a entidade foi atualizada em seus sistemas. O valor de tempo não pode estar no futuro. O carimbo de data/hora padrão é quando O Google recebe a solicitação. Ao enviar uma entidade por um método solicitação, o controle de versão da entidade também usa a update_time no caso de uma solicitação de adição/atualização.

Exemplos

Exemplo 1: atualizar um restaurante

Suponha que você precise atualizar o número de telefone de um restaurante com urgência. Seu "update" contém o JSON de todo o restaurante.

Considere um feed em lote como este:

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

A atualização incremental por HTTP POST seria assim:

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

Exemplo 2: atualizar vários restaurantes

Para atualizar duas entidades de restaurante em uma única chamada de API, a solicitação POST HTTP seria da seguinte forma:

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

Exemplo 3: atualizar o preço de um item de menu

Suponha que você precise mudar o preço de um item do menu. Como no Exemplo 1, atualização deve conter o JSON para toda a entidade de nível superior (o menu) e os usa o esquema de inventário v1.

Considere um feed em lote como este:

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

A atualização incremental via POST seria assim:

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

Como adicionar uma entidade

Para adicionar entidades, evite usar atualizações de inventário. Em vez disso, use os feeds em lote conforme descrito para o esquema de inventário v2.

Como remover uma entidade

Para remover entidades de nível superior, use um endpoint ligeiramente modificado, e usar HTTP DELETE em vez de HTTP POST na solicitação.

Excluir uma entidade de nível superior

Imagine que você queira excluir um restaurante de um feed. Você deve seus serviços e menus.

Um endpoint de exemplo para uma entidade de menu com ID "provider/restaurant/menu/nr":

DELETE v2/apps/delivery-provider-id/entities/menu/provider%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com

Um endpoint de exemplo para uma entidade de restaurante com 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

Um endpoint de amostra para uma entidade de serviço com 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
}

Como remover subentidades

Não use HTTP DELETE para remover uma subentidade dentro de uma entidade de nível superior, como um item de menu dentro de um menu. Em vez disso, trate a remoção de subentidades como uma para uma entidade de nível superior na qual a subentidade é removida da lista relevante ou reverseReference.

Códigos de resposta da API

Uma chamada bem-sucedida não significa que o feed é válido ou correto, apenas que o A chamada de API foi feita. Chamadas bem-sucedidas recebem um código de resposta HTTP 200, junto com um corpo de resposta vazio:

{}

No caso de falhas, o código de resposta HTTP não será 200, e o corpo da resposta indica o que deu errado.

Por exemplo, se o usuário definiu o campo "vertical" valor no envelope para FAKE_VERTICAL, você receberia esta mensagem:

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

Exemplo de código

Confira abaixo alguns exemplos de como usar a API Incremental Update em vários idiomas. Esses exemplos usam as bibliotecas do Google Auth e presumem que um feed usa o esquema de inventário v1. Para soluções alternativas, consulte Usar o OAuth 2.0 para aplicativos de servidor para servidor.

Como atualizar entidades

Node.js

Este código usa a biblioteca de autenticação do 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 a biblioteca de autenticação do 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 a biblioteca de autenticação do 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);
}

Como remover entidades

Node.js

Este código usa a biblioteca de autenticação do 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 a biblioteca de autenticação do 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 a biblioteca de autenticação do 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

Os casos de uso a seguir são exemplos de atualizações incrementais, atualizações completas de feed, e o conteúdo em alto nível na chamada de API:

Cenário Entidade a ser atualizada Descrição e efeitos
Desativar um serviço Service

Você precisar desativar um serviço por um motivo imprevisto.

Atualizações incrementais:atualize a entidade Service no definindo a propriedade isDisabled como true, mas mantenha as outras propriedades inalteradas.

Feeds completos:atualize a entidade dos feeds completos definir isDisabled como true antes dos a próxima busca feita pelo Google. Caso contrário, a entidade será reativada.

O item específico está esgotado MenuItemOffer Atualizações incrementais:envie o MenuItemOffer de encapsulamento. entidade com inventoryLevel definido como 0 para o dado MenuItem e todos os outros dados inalterados.
Mudança no preço do item de menu MenuItemOffer Atualizações incrementais:envie o MenuItemOffer de encapsulamento. entidade com price definido como o preço atualizado do MenuItem e todos os outros dados inalterados.

Adicionar nova entidade de nível superior

Aplicável apenas para a entidade dos tipos Menu, Restaurant e Service.

Menu, Restaurant, Service

Por exemplo, você precisa adicionar um novo cardápio a um restaurante.

Feeds completos:adicione a entidade aos seus feeds de dados e aguarde a ingestão em lote.

Excluir entidade de nível superior permanentemente

Aplicável apenas para a entidade dos tipos Menu, Restaurant e Service.

Menu, Restaurant, Service

Atualizações incrementais:envie uma exclusão explícita.

Feeds completos: remova a entidade dos feeds completos antes a próxima busca feita pelo Google. Caso contrário, a entidade será adicionada novamente.

Adicionar uma nova área de entrega em uma Service específica ServiceArea Feeds incrementais:envie a entidade ServiceArea em questão com todos os seus campos intactos, como faria normalmente nos feeds completos, com nova área de entrega especificado em polygon, geoRadius ou postalCode.
Atualize o horário previsto de chegada para Service ServiceHours Feeds incrementais:envie o ServiceHours igual ao nos feeds, exceto que leadTimeMin é atualizado de maneira adequada.
Atualize os preços de entrega para Service Fee Feeds incrementais:envie Fee de entrega completa com price atualizado.
Atualize os horários de entrega ou retirada em Service ServiceHours Feeds incrementais:envie o ServiceHours igual ao os feeds, com exceção de que suas propriedades opens e closes são atualizadas de maneira adequada.
Service (alterar o valor mínimo do pedido) Fee Feeds incrementais:envie Fee completo com minPrice atualizado
Excluir um MenuItem permanentemente Menu Feeds incrementais: envie o MenuItem da mesma forma que no feeds, mas com parentMenuSectionId vazio.

SLO no tempo de processamento de jobs em lote e atualizações incrementais

Uma entidade atualizada ou excluída em um lote será processada em até 2 horas no modo de melhor esforço, enquanto uma entidade atualizada por meio de uma atualização incremental será processada em 5 minutos. Uma entidade desatualizada é excluída em 7 dias.

Você pode enviar ao Google:

  • vários jobs em lote por dia para manter seu inventário atualizado OU
  • Um job em lote por dia e APIs incrementais para manter seu inventário atualizado.