Дополнительные обновления инвентаря v1

В этом разделе описывается, как отправлять в Google срочные обновления ваших каналов. API добавочных обновлений позволяет обновлять и удалять объекты в ваших каналах практически в реальном времени.

Эта функция в первую очередь предназначена для обновлений, которые вы не можете предвидеть, например для аварийного закрытия. Как правило, любое изменение, отправленное через API добавочных обновлений, должно быть изменением, которое должно быть введено в действие не позднее, чем через одну неделю. Если изменение не требует немедленного отражения, вместо этого можно использовать пакетное обновление. Инкрементные обновления обрабатываются не более чем за пять минут.

Настраивать

Чтобы реализовать инкрементные обновления, выполните следующие действия:

  1. Выполните действия, описанные в разделе Создание и настройка проекта, чтобы создать проект.
  2. Выполните действия, описанные в разделе «Настройка учетной записи службы», чтобы создать учетную запись службы. Обратите внимание, что вам необходимо быть «владельцем» проекта, чтобы добавить роль «редактора» для сервисной учетной записи.
  3. (Необязательно, но рекомендуется) Установите клиентскую библиотеку Google на выбранном вами языке, чтобы упростить использование OAuth 2.0 при вызове API. В приведенных ниже примерах кода используются эти библиотеки. В противном случае вам придется обрабатывать обмен токенами вручную, как описано в разделе Использование OAuth 2.0 для доступа к API Google .

Конечная точка

Чтобы уведомить Google об обновлении, отправьте запрос HTTP POST к API добавочных обновлений и включите полезную нагрузку обновлений и дополнений . Используемая вами схема инвентаризации определяет, к какой конечной точке будет отправлен ваш запрос:

инвентарь v2

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

инвентарь v1

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

Чтобы удалить объект, отправьте HTTP-запрос DELETE к следующей конечной точке, соответствующей используемой вами схеме инвентаризации:

инвентарь v2

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

инвентарь v1

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

В приведенных выше запросах замените следующее:

  • PROJECT_ID : идентификатор проекта Google Cloud, связанный с проектом, который вы создали в разделе «Создание и настройка проекта» .
  • TYPE (только для схемы инвентаризации версии 2): тип сущности (свойство @type ) объекта в фиде данных, который вы хотите обновить.
  • ENTITY_ID : идентификатор объекта, включенного в полезную нагрузку. Убедитесь, что URL-адрес кодирует идентификатор вашего объекта.
  • DELETE_TIME (только удаление конечной точки): необязательное поле для обозначения времени удаления объекта в ваших системах (по умолчанию — момент получения запроса). Временная стоимость не должна находиться в будущем. При отправке объекта посредством инкрементного вызова управление версиями объекта также использует поле delete_time в случае вызова удаления. Отформатируйте это значение как yyyy-mm-ddTHH:mm:ssZ

Например, у вас есть проект с идентификатором «delivery-provider-id», который использует схему инвентаризации версии 2. Вы хотите внести изменения в ресторан с типом объекта ресторана «MenuSection» и идентификатором объекта «menuSection_122». Конечная точка для обновлений ваших данных будет следующей:

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

Чтобы удалить тот же объект, вы должны выполнить вызов HTTP DELETE API:

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

Запросы песочницы

Для запросов к песочнице следуйте инструкциям в разделе Конечная точка выше, но отправляйте запросы к /v2/sandbox/apps/ вместо /v2/apps/ . Например, запрос на удаление из песочницы для схемы инвентаризации версии 2 структурирован следующим образом:

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

Обновления и дополнения

Ваши ежедневные пакетные каналы также должны содержать все изменения, отправленные через этот API. В противном случае пакетные обновления перезапишут дополнительные изменения.

Полезная нагрузка

Каждый запрос POST должен включать параметры запроса вместе с полезными данными JSON, содержащими структурированные данные любого типа объекта, указанного в схеме инвентаризации.

JSON должен выглядеть так же, как и в пакетном канале, со следующими отличиями:

  • Размер тела полезной нагрузки не должен превышать 5 МБ. Как и в случае с пакетными фидами, мы предлагаем удалять пробелы, чтобы вместить больше данных.
  • Конверт выглядит следующим образом:
{
  "entity": {
    "data":"ENTITY_DATA",
    "vertical":"FOODORDERING"
  },
  "update_time":"UPDATE_TIMESTAMP"
}

В приведенной выше полезной нагрузке замените следующее:

  • ENTITY_DATA : объект в формате JSON, сериализованный в виде строки. Сущность JSON-LD должна быть передана в виде строки в поле data .
  • UPDATE_TIMESTAMP (необязательно): отметка времени обновления объекта в ваших системах. Временная стоимость не должна находиться в будущем. Временная метка по умолчанию — это момент, когда Google получает запрос. При отправке объекта посредством добавочного запроса управление версиями объекта также использует поле update_time в случае запроса на добавление/обновление.

Обновление сущности

Пример 1: Обновление ресторана

Предположим, вам срочно нужно обновить номер телефона ресторана. Ваше обновление содержит JSON для всего ресторана.

Рассмотрим пакетную подачу, которая выглядит следующим образом:

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

Тогда ваше дополнительное обновление с помощью HTTP POST будет следующим:

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

Пример 2. Обновление цены на пункт меню.

Предположим, вам нужно изменить цену пункта меню. Как и в примере 1, ваше обновление должно содержать JSON для всего объекта верхнего уровня (меню), а канал использует схему инвентаризации v1.

Рассмотрим пакетную подачу, которая выглядит следующим образом:

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

Тогда ваше дополнительное обновление через POST будет следующим:

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

Добавление объекта

Чтобы добавлять объекты, избегайте использования обновлений инвентаря. Вместо этого используйте процесс пакетной подачи, как описано для схемы инвентаризации версии 2 .

Удаление объекта

Чтобы удалить сущности верхнего уровня, вы используете слегка измененную конечную точку и используете в запросе HTTP DELETE вместо HTTP POST.

Не используйте HTTP DELETE для удаления подобъекта внутри объекта верхнего уровня, например пункта меню внутри меню. Вместо этого рассматривайте удаление подобъектов как обновление объекта верхнего уровня, в котором подобъект удаляется из соответствующего списка или параметра.

Пример 1. Удаление объекта верхнего уровня

Рассмотрим ситуацию, когда вы хотите удалить ресторан из фида, использующего схему инвентаризации версии 1. Вы также должны удалить его службы и меню.

Пример конечной точки для сущности меню с идентификатором «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

Пример конечной точки для объекта ресторана с идентификатором 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

Пример конечной точки для объекта службы с идентификатором 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
}

Пример 2: Удаление подобъектов

Чтобы удалить подсущность из сущности верхнего уровня, вы отправляете сущность верхнего уровня с удаленной подсущностью из соответствующего поля. В следующем примере предполагается, что в фиде используется схема инвентаризации версии 1.

Например, чтобы удалить зону обслуживания, обновите службу, убрав зону обслуживания из списка 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"
  }
}

Коды ответа API

Успешный вызов не означает, что фид действителен или правилен, а означает лишь то, что был выполнен вызов API. Успешные вызовы получают код ответа HTTP 200 вместе с пустым телом ответа:

{}

В случае сбоев код ответа HTTP не будет равен 200, а в тексте ответа указывается, что пошло не так.

Например, если пользователь установил значение «вертикальное» в конверте на FAKE_VERTICAL , вы получите сообщение ниже:

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

Пример кода

Ниже приведены некоторые примеры использования API добавочных обновлений на разных языках. В этих примерах используются библиотеки Google Auth и предполагается, что канал использует схему инвентаризации v1. Альтернативные решения см. в разделе Использование OAuth 2.0 для межсерверных приложений .

Обновление объектов

Node.js

Этот код использует библиотеку аутентификации Google для 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)

Питон

Этот код использует библиотеку аутентификации Google для 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 '{}'

Ява

Этот код использует библиотеку аутентификации Google для 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);
}

Удаление объектов

Node.js

Этот код использует библиотеку аутентификации Google для 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)

Питон

Этот код использует библиотеку аутентификации Google для 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 '{}'

Ява

Этот код использует библиотеку аутентификации Google для 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));
}

Варианты использования

Следующие варианты использования являются примерами дополнительных обновлений, полных обновлений канала и контента на высоком уровне в вызове API:

Сценарий Сущность верхнего уровня Описание и эффекты
Отключение службы DisabledService

Вам необходимо отключить услугу по непредвиденной причине.

Дополнительные обновления: отправьте рассматриваемую сущность Service с измененным @type на DisabledService , но оставьте другие свойства такими же.

Полные каналы. Обязательно обновите объект из полных каналов, чтобы для параметра @type было установлено DisabledService до следующей загрузки Google, иначе объект будет повторно включен.

Конкретного товара нет в наличии Menu Дополнительные обновления: отправьте инкапсулирующий объект Menu с offer.inventoryLevel , равным 0 для данного MenuItem , и всеми остальными данными без изменений.
Изменение цены на позиции меню Menu Дополнительные обновления: отправьте инкапсулирующий объект Menu с offer.price в котором для параметра Offer.price установлена ​​обновленная цена для данного MenuItem , а все остальные данные не будут изменены.

Добавить новую сущность верхнего уровня

Применимо только для объектов типов Menu , Restaurant и Service .

Menu , Restaurant , Service

Например, вам нужно добавить новое меню в ресторан.

Дополнительные обновления: Отправьте новый объект меню вместе с объектом ресторана, поле которого hasMenu будет обновлено соответствующим образом.

Удалить объект верхнего уровня навсегда

Применимо только для объектов типов Menu , Restaurant и Service .

Menu , Restaurant , Service

Инкрементные обновления: отправьте явное удаление .

Полные фиды. Обязательно удалите объект из полных фидов до следующей загрузки Google, иначе объект будет добавлен повторно.

Добавить новую зону доставки в конкретную Service Service Инкрементальные каналы: отправьте соответствующий объект Service со всеми его полями, как обычно, в полных каналах, с новой областью доставки, указанной в areaServed Service .
Обновить расчетное время доставки в Service Service Инкрементальные каналы: отправьте Service так же, как и в каналах, за исключением того, что ее hoursAvailable.deliveryHours обновляются соответствующим образом.
Обновить цены на доставку в Service Service Дополнительные фиды: отправьте полный Service с обновленным offers.priceSpecification.price .
Обновите часы доставки или самовывоза в Service Service Инкрементные каналы: Отправьте Service так же, как и в каналах, за исключением того, что ее hoursAvailable обновляются соответствующим образом.
Service (изменение минимальной суммы заказа) Service Дополнительные фиды: отправьте полную Service с обновленным Service.offers.priceSpecification.eligibleTransactionVolume
Удалить MenuItem навсегда Menu Дополнительные каналы: отправьте Menu так же, как в каналах, но с удалением этого MenuItem из списка hasMenuItems .

SLO по времени обработки пакетных заданий и дополнительных обновлений

Объект, добавленный посредством пакетного или инкрементного обновления, будет обработан в течение 1–2 дней. Сущность, обновленная или удаленная в пакетном режиме, будет обработана за 2 часа, тогда как сущность, обновленная посредством добавочного обновления, будет обработана за 5 минут. Устаревший объект удаляется через 7 дней.

Вы можете отправить Google:

  • Несколько пакетных заданий в день для поддержания актуальности ваших запасов, ИЛИ
  • Одно пакетное задание в день и дополнительные API для поддержания актуальности ваших запасов.