Обновления в реальном времени

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

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

Предварительные условия

Перед внедрением обновлений в реальном времени необходимы следующие элементы:

  1. Maps Booking API включен:
    • В GCP перейдите в API и сервисы > Библиотека.
    • Найдите «API бронирования Карт Google»
      Найдите API бронирования Google Maps
    • Найдите экземпляр песочницы («Google Maps Booking API (Dev)») и нажмите « Включить» .
    • Найдите рабочий экземпляр («Google Maps Booking API») и нажмите « Включить» .
      Включить API бронирования Google Maps
  2. В вашем проекте GCP создается сервисная учетная запись с ролью редактора. Более подробную информацию см. в разделе Настройка учетной записи .
  3. Фиды производственных или изолированных данных размещаются и принимаются. Дополнительные сведения см. в разделе Пакетный прием .
  4. Для аутентификации API рекомендуется установить клиентскую библиотеку Google на выбранном вами языке. Используйте https://www.googleapis.com/auth/mapsbooking в качестве области действия OAuth. В приведенных ниже примерах кода используются эти библиотеки. В противном случае вам придется обрабатывать обмен токенами вручную, как описано в разделе Использование OAuth 2.0 для доступа к API Google .

Обзор

API обновлений в реальном времени поддерживает два типа операций. Первая операция — upsert для обновления существующих сущностей. Вторая операция — удаление для удаления объектов из вашего инвентаря. Обе операции выполняются над диапазоном объектов, перечисленных в теле запроса. Вы можете обновлять до 1000 объектов за один вызов API. API принимает все входящие запросы и помещает их в очередь для дальнейшей обработки. Поэтому запросы RTU обрабатываются асинхронно.

API обновлений в реальном времени работает в двух средах: песочнице и рабочей среде. Среда «песочница» используется для тестирования запросов API и производственной среды для обновления контента, видимого пользователям сквозного заказа. Имена хостов обеих сред:

  • Песочница - partnerdev-mapsbooking.googleapis.com
  • Производство - mapsbooking.googleapis.com

Конечные точки

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

  • UPSERT - /v1alpha/inventory/partners/ PARTNER_ID /feeds/owg.v2/record:batchPush
  • УДАЛИТЬ - /v1alpha/inventory/partners/ PARTNER_ID /feeds/owg.v2/record:batchDelete

Параметр PARTNER_ID можно найти в Центре действий , который отображается как идентификатор партнера на странице «Учетная запись и пользователи» , как показано на снимке экрана ниже.

Идентификатор партнера на партнерском портале

Если взять 10000001 в качестве значения PARTNER_ID в качестве примера на скриншоте выше, полные URL-адреса для отправки запросов API в песочнице и производстве будут выглядеть так, как показано в примерах ниже.

# Sandbox UPSERT
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Sandbox DELETE
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete
# Production UPSERT
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Production DELETE
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete

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

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

Обновление полезных данных запроса

Тело запроса представляет собой объект JSON со списком записей. Каждая запись соответствует обновляемому объекту. Он состоит из поля data_record с полезной нагрузкой объекта, закодированной в Base64, и generation_timestamp , указывающего время обновления объекта:

  {
   
"records": [
     
{
       
"data_record":"BASE_64_ENCODED_ENTITY",
       
"generation_timestamp":"UPDATE_TIMESTAMP"
     
}
   
]
 
}

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

  • BASE_64_ENCODED_ENTITY : строка JSON объекта в кодировке Base64. Декодированный объект JSON должен иметь ту же структуру, что и в спецификации фида, например:

    {"@type":"MenuSection","name":"My Updated Menu Section","menuId":{"@id":"10824","displayOrder":1},"@id":"853705"}
  • UPDATE_TIMESTAMP : обязательно укажите временную метку создания объекта в ваших серверных системах. Эта отметка времени используется для обеспечения правильного порядка обновлений инвентаря. Если это поле не включено, в нем будет указано время, когда Google получит запрос. При обновлении сущности через batchPush запрос поле generation_timestamp используется для управления версиями сущности . См. ожидаемый формат значений времени в схеме реляционной инвентаризации.

Каждый запрос на обновление в режиме реального времени должен соответствовать следующим условиям:

  • Размер тела полезной нагрузки не должен превышать 5 МБ. Как и в случае с пакетными фидами, мы предлагаем удалять пробелы, чтобы вместить больше данных.
  • В batchPush запросе может быть до 1000 объектов.

Примеры

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

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

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

{
 
"@type": "Restaurant",
 
"@id": "restaurant12345",
 
"name": "Some Restaurant",
 
"url": "https://www.provider.com/somerestaurant",
 
"telephone": "+16501234570",
 
"streetAddress": "345 Spear St",
 
"addressLocality": "San Francisco",
 
"addressRegion": "CA",
 
"postalCode": "94105",
 
"addressCountry": "US",
 
"latitude": 37.472842,
 
"longitude": -122.217144
}
 

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

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": {
       
"@type": "Restaurant",
       
"@id": "restaurant12345",
       
"name": "Some Restaurant",
       
"url": "https://www.provider.com/somerestaurant",
       
"telephone": "+16501234570",
       
"streetAddress": "345 Spear St",
       
"addressLocality": "San Francisco",
       
"addressRegion": "CA",
       
"postalCode": "94105",
       
"addressCountry": "US",
       
"latitude": 37.472842,
       
"longitude": -122.217144
     
}
     
"generation_timestamp": "2022-08-19T17:11:10.750Z"
   
}
 
]
}
   

Тот же пример с полезной нагрузкой в ​​кодировке Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM0NTcwIiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0="
     
"generation_timestamp": "2022-08-19T17:11:10.750Z"
   
}
 
]
}
   

Пример 2. Обновление нескольких ресторанов

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

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": {
       
"@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
     
},
     
"generation_timestamp": "2022-08-19T17:11:10.850Z"
   
},
   
{
     
"data_record": {
       
"@type": "Restaurant",
       
"@id": "restaurant123",
       
"name": "Some Other Restaurant",
       
"url": "https://www.provider.com/someotherrestaurant",
       
"telephone": "+16501231235",
       
"streetAddress": "385 Spear St",
       
"addressLocality": "San Mateo",
       
"addressRegion": "CA",
       
"postalCode": "94115",
       
"addressCountry": "US"
     
},
     
"generation_timestamp": "2022-08-19T17:11:10.850Z"
   
}
 
]
}
   

Тот же пример с полезной нагрузкой в ​​кодировке Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM1NTU1Iiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0=",
     
"generation_timestamp": "2022-08-19T17:11:10.850Z"
   
},
   
{
     
"data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzIiwibmFtZSI6IlNvbWUgT3RoZXIgUmVzdGF1cmFudCIsInVybCI6Imh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9zb21lcmVzdGF1cmFudCIsInRlbGVwaG9uZSI6IisxNjUwMTIzMTIzNSIsInN0cmVldEFkZHJlc3MiOiIzODUgU3BlYXIgU3QiLCJhZGRyZXNzTG9jYWxpdHkiOiJTYW4gTWF0ZW8iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMTUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIn0=",
     
"generation_timestamp": "2022-08-19T17:11:10.850Z"
   
}
 
]
}
   

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

Предположим, вам нужно изменить цену пункта меню.

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

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

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

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": {
       
"@type": "MenuItemOffer",
       
"@id": "menuitemoffer6680262",
       
"sku": "offer-cola",
       
"menuItemId": "menuitem896532",
       
"price": 2,
       
"priceCurrency": "USD"
     
},
     
"generation_timestamp": "2022-08-19T17:20:10Z"
   
}
 
]
}
   

Тот же пример с полезной нагрузкой в ​​кодировке Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtT2ZmZXIiLCJAaWQiOiJtZW51aXRlbW9mZmVyNjY4MDI2MiIsInNrdSI6Im9mZmVyLWNvbGEiLCJtZW51SXRlbUlkIjoibWVudWl0ZW04OTY1MzIiLCJwcmljZSI6MiwicHJpY2VDdXJyZW5jeSI6IlVTRCJ9",
     
"generation_timestamp": "2022-08-19T17:20:10Z"
   
}
 
]
}

   

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

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

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

Чтобы удалить объекты из вашего инвентаря, используйте конечную точку DELETE и отправляйте запросы HTTP POST. Каждый запрос POST должен включать параметр PARTNER_ID вместе с полезными данными JSON, содержащими идентификатор любого объекта в вашем инвентаре.

Удаление полезных данных запроса

Тело запроса на удаление структурировано аналогично запросу на обновление . Также есть список записей с полями data_record и delete_time :

  {
   
"records": [
     
{
       
"data_record":"BASE_64_ENCODED_REFERENCE",
       
"delete_time": "DELETE_TIMESTAMP"
     
}
   
]
 
}

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

  • BASE_64_ENCODED_REFERENCE : строка JSON в кодировке Base64, содержащая ссылку на удаляемый объект. Ссылка состоит только из типа и идентификатора сущности, например JSON-представление ссылки на MenuSection :

    {"@type":"MenuSection","@id":"853705"}
  • DELETE_TIMESTAMP : обязательно укажите временную метку удаления объекта в вашей серверной системе. Эта временная метка используется для определения порядка, в котором удаление будет применено к инвентарю.

В запросе batchDelete может быть до 1000 объектов.

Примеры

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

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

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": {
       
"@type": "MenuItem",
       
"@id": "item_1234"
     
},
     
"delete_time": "2022-08-21T15:23:00.000Z"
   
},
   
{
     
"data_record": {
       
"@type": "MenuItem",
       
"@id": "item_5678"
     
},
     
"delete_time": "2022-08-21T15:23:00.000Z"
   
}
 
]
}
   

Тот же пример с полезной нагрузкой в ​​кодировке Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV8xMjM0In0="
     
"delete_time": "2022-08-21T15:23:00.000Z"
   
},
   
{
     
"data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV81Njc4In0="
     
"delete_time": "2022-08-21T15:23:00.000Z"
   
},
 
]
}
   

Пример 2. Удаление объекта Restaurant

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

Пример запроса на удаление объекта ресторана с идентификатором https://www.provider.com/restaurant/12345 :

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": {
       
"@type": "Restaurant",
       
"@id": "https://www.provider.com/restaurant/12345"
     
},
     
"delete_time": "2022-08-19T17:11:10.750Z"
   
}
 
]
}
   

Тот же пример с полезной нагрузкой в ​​кодировке Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
 
"records": [
   
{
     
"data_record": "ewogICJAdHlwZSI6ICJSZXN0YXVyYW50IiwKICAiQGlkIjogImh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9yZXN0YXVyYW50LzEyMzQ1Igp9"
     
"delete_time": "2022-08-19T17:11:10.750Z"
   
}
 
]
}
   

Коды проверки и ответа API

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

  • Уровень запроса . Эти проверки проверяют, соответствует ли полезная нагрузка схеме обновления или удаления , и каждая data_record содержит поля @id и @type . Эти проверки являются синхронными, и результаты возвращаются в теле ответа API. Код ответа 200 и пустое тело JSON {} означают, что эти проверки пройдены и объекты в этом запросе поставлены в очередь для обработки. Код ответа, отличный от 200, означает, что одна или несколько из этих проверок не удались и весь запрос был отклонен (включая все объекты в полезных данных). Например, если в data_record не указан @type , будет возвращен следующий ответ об ошибке:

    {
     
    "error": {
       
    "code": 400,
       
    "message": "Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n",
       
    "status": "INVALID_ARGUMENT",
       
    "details": [
         
    {
           
    "@type": "type.googleapis.com/google.rpc.DebugInfo",
           
    "detail": "[ORIGINAL ERROR] generic::invalid_argument: Failed to parse one or more rtu records. Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n [google.rpc.error_details_ext] { message: \"Record:{\\\"@id\\\":\\\"2717/86853/DELIVERY\\\",\\\"applicableServiceType\\\":[\\\"DELIVERY\\\",\\\"TAKEOUT\\\"],\\\"menuId\\\":[{\\\"@id\\\":\\\"2717/DELIVERY\\\",\\\"displayOrder\\\":1},{\\\"@id\\\":\\\"2717/TAKEOUT\\\",\\\"displayOrder\\\":2}],\\\"name\\\":\\\"Salad\\\",\\\"offeredById\\\":[\\\"2717\\\"]} has following errors: \\nThe entity type could not be extracted from the entity value.\\n\" }"
         
    }
       
    ]
     
    }
    }
  • Уровень сущности — каждая сущность в полезных данных проверяется на соответствие реляционной схеме . О проблемах, возникших на этом этапе проверки, не сообщается в ответе API. О них сообщается только на панели отчетов RTU .

API-квоты

Обновления API в реальном времени имеют квоту в 1500 запросов каждые 60 секунд или в среднем 25 запросов в секунду. При превышении квоты Google отвечает следующим сообщением об ошибке:

{
 
"error": {
   
"code": 429,
   
"message": "Insufficient tokens for quota ...",
   
"status": "RESOURCE_EXHAUSTED",
   
"details": [...]
 
}
}

Чтобы справиться с этим, повторите вызов снова с экспоненциально большими интервалами, пока он не увенчается успехом. Если вы регулярно исчерпываете квоту, рассмотрите возможность включения большего количества сущностей в один запрос API. Вы можете включить до 1000 сущностей в один вызов API.

Примеры кода

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

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

Этот код использует библиотеку аутентификации Google для Node.js.

/* Sample code for Real-time update batchPush implementation.
 *
 * Required libraries:
 * - google-auth-library
 */


const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod
: 'https://mapsbooking.googleapis.com',
  sandbox
: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchPush`
;

/**
 * Send a Real-time update request to update/insert entities
 */

async
function batchUpsert(entities) {
 
/**
   * Sign JWT token using private key from service account secret file
   * provided. The client can be created without providing a service account
   * secret file by implementing Application Default Credentials.
   * https://github.com/googleapis/google-auth-library-nodejs
   */

 
const client = new JWT({
    email
: serviceAccountJson.client_email,
    key
: serviceAccountJson.private_key,
    scopes
: ['https://www.googleapis.com/auth/mapsbooking'],
 
});
 
const request = {records: toPushRecords(entities)};
 
const body = JSON.stringify(request);
 
try {
   
const response = await client.request({
      method
: 'POST',
      url
,
      data
: body,
      headers
: {'Content-Type': 'application/json'}
   
});
    console
.log('request body:', body);
    console
.log('response status:', response.status);
    console
.log(
       
'response data:', response.data);  // successful response returns '{}'
 
} catch (error) {
    console
.log('error:', error);
 
}
}

/**
 * Maps array of entities to records for batch push requests
 */

const toPushRecords = (entities) => {
 
return entities.map((entity) => {
   
// Using dateModified to set generation_timestamp. Defaulting to the
   
// current timestamp for records that do not have dateModified.
   
const generation_timestamp =
        entity
.dateModified ? entity.dateModified : new Date().toISOString();
   
return {data_record: btoa(JSON.stringify(entity)), generation_timestamp};
 
});
};

// Call batchUpsert with example entities. dateModified is optional and is
// used to hold the actual timestamp when the entity was updated/created.
batchUpsert
([
 
{
   
'@type': 'MenuItemOffer',
   
'@id': '6680261',
   
'menuItemId': '18931508',
   
'price': 15.5,
   
'priceCurrency': 'USD',
   
'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
   
'inventoryLevel': 0,
   
'dateModified': '2022-06-19T15:43:50.970Z'
 
},
 
{
   
'@type': 'MenuItemOffer',
   
'@id': '6680262',
   
'menuItemId': '18931509',
   
'price': 25.5,
   
'priceCurrency': 'USD',
   
'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
   
'inventoryLevel': 0,
   
'dateModified': '2022-06-19T15:43:50.970Z'
 
}
]);

Этот код использует библиотеку аутентификации Google для Python.

"""Sample code for the Real-time update batchPush implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID
= '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE
= 'service-account-creds.json'

_HOST_MAP
= {
   
'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
   
'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV
= 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME
= 'owg.v2'

_ENDPOINT
= '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchPush'.format(
    _HOST_MAP
[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_upsert(entities):
 
"""Makes a batchPush request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to update or add.
  """


 
# Creates credentials by providing a json file. Credentials can also be
 
# provided by implementing Application Default Credentials.
 
# https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials
= service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE
,
      scopes
=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session
= AuthorizedSession(credentials)

 
# JSON request object
  batch_request
= {'records': [create_push_record(x) for x in entities]}
  response
= authorized_session.post(_ENDPOINT, json=batch_request)
 
print('request body:', json.dumps(batch_request))
 
print('response status:', response.status_code)
 
print('response data:', response.text)  # successful response returns '{}'


def create_push_record(entity):
 
"""Creates a record from an entity for batchPush requests.

  Args:
      entity: The entity object to create the record from.

  Returns:
      The constructed record for the batchPush request payload.
  """

  data_bytes
= json.dumps(entity).encode('utf-8')
  base64_bytes
= base64.b64encode(data_bytes)
 
# Using dateModified to set generation_timestamp. Defaulting to the
 
# current timestamp for records that do not have dateModified.
  generation_timestamp
= entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
 
).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
 
return {
     
'generation_timestamp': generation_timestamp,
     
'data_record': base64_bytes.decode('utf-8')
 
}


# Call batch_upsert with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was updated/created.
batch_upsert
([{
   
'@type': 'MenuItemOffer',
   
'@id': '6680261',
   
'menuItemId': '18931508',
   
'price': 15.5,
   
'priceCurrency': 'USD',
   
'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
   
'inventoryLevel': 0,
   
'dateModified': '2022-06-19T15:43:50.970Z'
}, {
   
'@type': 'MenuItemOffer',
   
'@id': '6680262',
   
'menuItemId': '18931509',
   
'price': 25.5,
   
'priceCurrency': 'USD',
   
'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
   
'inventoryLevel': 0,
   
'dateModified': '2022-06-19T15:43:50.970Z'
}])

Этот код использует библиотеку аутентификации Google для Java.

Модели исходного кода клиента в пакетах rtusamples.inventory и rtusamples.realtime были созданы с помощью шагов, описанных в разделе Создание клиентских библиотек .

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */

package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.MenuItemOffer;
import rtusamples.inventory.MenuItemOfferType;
import rtusamples.inventory.ServiceTypeElement;
import rtusamples.realtime.BatchPushGenericRecordRequest;
import rtusamples.realtime.GenericRecord;

/** Sample code for Real-time update batchPush implementation. */
public final class BasicPush {
 
// ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
 
// available on the Partner Portal.
 
private static final long PARTNER_ID = 12345678;

 
// ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
 
// from the Google Cloud Console.
 
private static final String JSON_KEY_FULL_PATH =
     
"<path to your JSON credentials>/credentials.json";

 
// ACTION REQUIRED: Change this to the endpoint that is needed.
 
private static final String ENDPOINT =
     
//    "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
     
"https://mapsbooking.googleapis.com"; // for prod

 
// Feed name for Order with Google including the version.
 
private static final String FEED_NAME = "owg.v2";

 
private static final ObjectMapper objectMapper = new ObjectMapper();

 
private static final DateTimeFormatter TIMESTAMP_FORMATTER =
     
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

 
private static final Charset UTF_8 = Charset.forName("UTF-8");

 
public static void main(String[] args) throws Exception {

   
/**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */

   
// GoogleCredentials sourceCredentials =
   
//     GoogleCredentials.getApplicationDefault()
   
//         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

   
// ImpersonatedCredentials credentials =
   
//     ImpersonatedCredentials.create(
   
//         sourceCredentials,
   
//         "fo-test@projectname.iam.gserviceaccount.com",
   
//         null,
   
//         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
   
//         300);

   
GoogleCredentials credentials =
       
GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
           
.createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

   
// Create example MenuItemOffer entities, dateModified is optional and is used to hold
   
// the actual timestamp when the entity was updated/created.
   
MenuItemOffer menuItemOfferPizza = new MenuItemOffer();
    menuItemOfferPizza
.setID("6680261");
    menuItemOfferPizza
.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferPizza
.setMenuItemID("18931508");
    menuItemOfferPizza
.setPrice(15.5);
    menuItemOfferPizza
.setPriceCurrency("USD");
    menuItemOfferPizza
.setApplicableServiceType(
       
new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferPizza
.setInventoryLevel(0.0);
    menuItemOfferPizza
.setDateModified("2022-10-07T13:00:00.000Z");

   
MenuItemOffer menuItemOfferSalad = new MenuItemOffer();
    menuItemOfferSalad
.setID("6680262");
    menuItemOfferSalad
.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferSalad
.setMenuItemID("18931509");
    menuItemOfferSalad
.setPrice(25.5);
    menuItemOfferSalad
.setPriceCurrency("USD");
    menuItemOfferSalad
.setApplicableServiceType(
       
new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferSalad
.setInventoryLevel(0.0);
    menuItemOfferSalad
.setDateModified("2022-10-07T13:00:00.000Z");

   
// Example array of MenuItemOffer entities to update.
   
List<MenuItemOffer> menuItemOffers = Arrays.asList(menuItemOfferPizza, menuItemOfferSalad);

   
// Create list of GenericRecord from menuItemOffers.
   
List<GenericRecord> menuItemOfferGenericRecords =
        menuItemOffers
.stream()
           
.map(
               
(menuItemOffer) ->
                    toBatchPushRecord
(menuItemOffer, menuItemOffer.getDateModified()))
           
.collect(Collectors.toList());

   
// List of records to be updated/created.
   
List<GenericRecord> recordsToBeUpdated = new ArrayList<>();

   
// Add list of menuItemOffer generic records.
    recordsToBeUpdated
.addAll(menuItemOfferGenericRecords);

   
// Request object that contains all records.
   
BatchPushGenericRecordRequest batchPushRequest = new BatchPushGenericRecordRequest();
    batchPushRequest
.setRecords(recordsToBeUpdated.toArray(new GenericRecord[0]));

   
// Execute batchPush request.
   
BasicPush basicPush = new BasicPush();
    basicPush
.batchPush(batchPushRequest, credentials);
 
}

 
public void batchPush(
     
BatchPushGenericRecordRequest batchPushRequest, GoogleCredentials credentials)
     
throws IOException {

    credentials
.refreshIfExpired();
   
AccessToken token = credentials.getAccessToken();

   
String requestBody = objectMapper.writeValueAsString(batchPushRequest);
   
HttpClient client = HttpClient.newHttpClient();
   
HttpRequest request =
       
HttpRequest.newBuilder()
           
.uri(
                URI
.create(
                   
String.format(
                       
"%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchPush",
                        ENDPOINT
, PARTNER_ID, FEED_NAME)))
           
.header("Content-Type", "application/json")
           
.header("Authorization", String.format("Bearer %s", token.getTokenValue()))
           
.POST(BodyPublishers.ofString(requestBody))
           
.build();

   
HttpResponse<String> response = null;
   
try {
      response
= client.send(request, BodyHandlers.ofString());
     
System.out.println("Request body:" + requestBody);
     
System.out.println("Response status:" + response.statusCode());
     
System.out.println("Response body:" + response.body());
   
} catch (IOException | InterruptedException e) {
      e
.printStackTrace();
   
}
 
}

 
public static <T> GenericRecord toBatchPushRecord(T entity, String dateModified) {
   
GenericRecord genericRecord = new GenericRecord();
   
try {
     
String json = objectMapper.writeValueAsString(entity);
      genericRecord
.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
     
// Using dateModified to set generation_timestamp. Defaulting to the
     
// current timestamp for records that do not have dateModified.
     
String generationTimestamp =
         
Optional.ofNullable(dateModified)
             
.orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord
.setGenerationTimestamp(generationTimestamp);
   
} catch (JsonProcessingException e) {
     
System.out.println(e.getMessage());
   
}
   
return genericRecord;
 
}
}

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

Этот код использует библиотеку аутентификации Google для Node.js.

/* Sample code for Real-time update batchDelete implementation.
 *
 * Required libraries:
 * - google-auth-library
 */


const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod
: 'https://mapsbooking.googleapis.com',
  sandbox
: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchDelete`
;


/**
 * Send a Real-time update request to delete entities
 */

async
function batchDelete(entities) {
 
try {
   
/**
     * Sign JWT token using private key from service account secret file
     * provided. The client can be created without providing a service account
     * secret file by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-nodejs
     */

   
const client = new JWT({
      email
: serviceAccountJson.client_email,
      key
: serviceAccountJson.private_key,
      scopes
: ['https://www.googleapis.com/auth/mapsbooking'],
   
});
   
const request = {
      records
: toDeleteRecords(entities)
   
};
   
const body = JSON.stringify(request);
   
try {
     
const response = await client.request({
        method
: 'POST',
        url
,
        data
: body,
        headers
: {'Content-Type': 'application/json'}
     
});
      console
.log('request body:', body);
      console
.log('response status:', response.status);
      console
.log('response data:', response.data);  // successful response returns '{}'
   
} catch (error) {
      console
.log('error:', error);
   
}
 
}

 
/**
   * Maps array of entities to records for batch delete requests
   */

 
const toDeleteRecords = (entities) => {
   
return entities.map((entity) => {
     
// Using dateModified to set delete_time. Defaulting to the current
     
// timestamp for records that do not have dateModified.
     
const delete_time =
          entity
.dateModified ? entity.dateModified : new Date().toISOString();
     
return {data_record: btoa(JSON.stringify(entity)), delete_time};
   
});
 
};

 
// Call batchDelete with example entities. dateModified is optional and is
 
// used to hold the actual timestamp when the entity was deleted.
  batchDelete
([
   
{
     
'@type': 'Menu',
     
'@id': '853706',
     
'dateModified': '2022-06-19T15:43:50.970Z'
   
},
   
{
     
'@type': 'Menu',
     
'@id': '853705',
     
'dateModified': '2022-06-19T15:13:00.280Z'
   
}
 
]);

Этот код использует библиотеку аутентификации Google для Python.

"""Sample code for the Real-time update batchDelete implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID
= '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE
= 'service-account-creds.json'

_HOST_MAP
= {
   
'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
   
'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV
= 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME
= 'owg.v2'

_ENDPOINT
= '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchDelete'.format(
    _HOST_MAP
[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_delete(entities):
 
"""Makes a batch delete request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to delete.
  """


 
# Creates credentials by providing a json file. Credentials can also be
 
# provided by implementing Application Default Credentials.
 
# https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials
= service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE
,
      scopes
=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session
= AuthorizedSession(credentials)

 
# JSON request object
  batch_request
= {'records': [create_delete_record(x) for x in entities]}
  response
= authorized_session.post(_ENDPOINT, json=batch_request)
 
print('request body:', json.dumps(batch_request))
 
print('response status:', response.status_code)
 
print('response data:', response.text)  # successful response returns '{}'


def create_delete_record(entity):
 
"""Creates a record from an entity for batchDelete requests.

  Args:
    entity: The entity object to create the record from.

  Returns:
    The constructed record for the batchDelete request payload.
  """

  data_bytes
= json.dumps(entity).encode('utf-8')
  base64_bytes
= base64.b64encode(data_bytes)
 
# Using dateModified to set delete_time. Defaulting to the current
 
# timestamp for records that do not have dateModified.
  delete_time
= entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
 
).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
 
return {
     
'delete_time': delete_time,
     
'data_record': base64_bytes.decode('utf-8')
 
}


# Call batch_delete with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was deleted.
batch_delete
([{
   
'@type': 'Menu',
   
'@id': '853706',
   
'dateModified': '2022-06-19T13:10:00.000Z'
}, {
   
'@type': 'Menu',
   
'@id': '853705',
   
'dateModified': '2022-06-19T13:30:10.000Z'
}])

Этот код использует библиотеку аутентификации Google для Java.

Модели исходного кода клиента в пакетах rtusamples.inventory и rtusamples.realtime были созданы с помощью шагов, описанных в разделе Создание клиентских библиотек .

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */

package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.Menu;
import rtusamples.inventory.MenuType;
import rtusamples.realtime.BatchDeleteGenericRecordsRequest;
import rtusamples.realtime.GenericDeleteRecord;

/** Sample code for the Real-time update batchDelete implementation. */
public final class BasicDelete {
 
// ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
 
// available on the Partner Portal.
 
private static final long PARTNER_ID = 123456789;

 
// ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
 
// from the Google Cloud Console.
 
private static final String JSON_KEY_FULL_PATH =
     
"<path to your JSON credentials>/credentials.json";

 
// ACTION REQUIRED: Change this to the endpoint that is needed.
 
private static final String ENDPOINT =
     
"https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
 
// "https://mapsbooking.googleapis.com" // for prod

 
// Feed name for Order with Google including the version.
 
private static final String FEED_NAME = "owg.v2";

 
private static final ObjectMapper objectMapper = new ObjectMapper();

 
private static final DateTimeFormatter TIMESTAMP_FORMATTER =
     
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

 
private static final Charset UTF_8 = Charset.forName("UTF-8");

 
public static void main(String[] args) throws Exception {

   
/**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */

   
// GoogleCredentials sourceCredentials =
   
//     GoogleCredentials.getApplicationDefault()
   
//         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

   
// ImpersonatedCredentials credentials =
   
//     ImpersonatedCredentials.create(
   
//         sourceCredentials,
   
//         "fo-test@projectname.iam.gserviceaccount.com",
   
//         null,
   
//         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
   
//         300);

   
GoogleCredentials credentials =
       
GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
           
.createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

   
// Create example Menu entities, dateModified is optional and is used to hold
   
// the actual timestamp when the entity was deleted.
   
Menu menuLunch = new Menu();
    menuLunch
.setID("853705");
    menuLunch
.setType(MenuType.MENU);
    menuLunch
.setDateModified("2022-09-19T13:10:00.000Z");

   
Menu menuDinner = new Menu();
    menuDinner
.setID("853706");
    menuDinner
.setType(MenuType.MENU);
    menuDinner
.setDateModified("2022-09-19T13:13:10.000Z");

   
// Example array of Menu entities to update.
   
List<Menu> menus = Arrays.asList(menuLunch, menuDinner);

   
// Create list of GenericDeleteRecord from menus.
   
List<GenericDeleteRecord> menuGenericDeleteRecords =
        menus
.stream()
           
.map((menu) -> toBatchDeleteRecord(menu, menu.getDateModified()))
           
.collect(Collectors.toList());

   
// List of records to be deleted.
   
List<GenericDeleteRecord> recordsToBeDeleted = new ArrayList<>();

   
// Add list of menu generic records.
    recordsToBeDeleted
.addAll(menuGenericDeleteRecords);

   
// Request object that contains all records.
   
BatchDeleteGenericRecordsRequest batchDeleteRequest = new BatchDeleteGenericRecordsRequest();
    batchDeleteRequest
.setRecords(recordsToBeDeleted.toArray(new GenericDeleteRecord[0]));

   
// Execute batchDelete request.
   
BasicDelete basicDelete = new BasicDelete();
    basicDelete
.batchDelete(batchDeleteRequest, credentials);
 
}

 
public void batchDelete(
     
BatchDeleteGenericRecordsRequest batchDeleteRequest, GoogleCredentials credentials)
     
throws IOException {

    credentials
.refreshIfExpired();
   
AccessToken token = credentials.getAccessToken();

   
String requestBody = objectMapper.writeValueAsString(batchDeleteRequest);
   
HttpClient client = HttpClient.newHttpClient();
   
HttpRequest request =
       
HttpRequest.newBuilder()
           
.uri(
                URI
.create(
                   
String.format(
                       
"%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchDelete",
                        ENDPOINT
, PARTNER_ID, FEED_NAME)))
           
.header("Content-Type", "application/json")
           
.header("Authorization", String.format("Bearer %s", token.getTokenValue()))
           
.POST(BodyPublishers.ofString(requestBody))
           
.build();

   
HttpResponse<String> response = null;
   
try {
      response
= client.send(request, BodyHandlers.ofString());
     
System.out.println("Request body:" + requestBody);
     
System.out.println("Response status:" + response.statusCode());
     
System.out.println("Response body:" + response.body());
   
} catch (IOException | InterruptedException e) {
      e
.printStackTrace();
   
}
 
}

 
public static <T> GenericDeleteRecord toBatchDeleteRecord(T entity, String dateModified) {
   
GenericDeleteRecord genericRecord = new GenericDeleteRecord();
   
try {
     
String json = objectMapper.writeValueAsString(entity);
      genericRecord
.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
     
// Using dateModified to set delete_time. Defaulting to the current
     
// timestamp for records that do not have dateModified.
     
String deleteTime =
         
Optional.ofNullable(dateModified)
             
.orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord
.setDeleteTime(deleteTime);
   
} catch (JsonProcessingException e) {
     
System.out.println(e.getMessage());
   
}
   
return genericRecord;
 
}
}

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

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

Сценарий Объект для обновления Описание и эффекты
Отключение службы Service

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

Обновления в режиме реального времени: обновите рассматриваемую сущность Service , установив для ее свойства isDisabled значение true , но оставив другие свойства такими же.

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

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

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

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

Menu , Restaurant , Service

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

Полные каналы: добавьте объект в свои каналы данных и дождитесь пакетной обработки.

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

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

Menu , Restaurant , Service

Обновления в режиме реального времени: отправьте явное удаление .

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

Добавить новую зону доставки в конкретную Service ServiceArea Пакетные каналы: отправьте рассматриваемый объект ServiceArea со всеми его полями без изменений, как обычно в полных каналах, с новой областью доставки, указанной в polygon , geoRadius или postalCode .
Обновить расчетное время доставки в Service ServiceHours Пакетные каналы: отправляйте ServiceHours так же, как и в каналах, за исключением того, что его leadTimeMin обновляется соответствующим образом.
Обновить цены на доставку в Service Fee Пакетные каналы: Отправьте полную Fee доставки с обновленной price .
Обновите часы доставки или самовывоза в Service ServiceHours Пакетные каналы: отправляйте ServiceHours так же, как и в каналах, за исключением того, что его свойства opens и closes обновляются соответствующим образом.
Service (изменение минимальной суммы заказа) Fee Пакетные фиды: отправьте полную Fee с обновленной minPrice .
Удалить MenuItem навсегда Menu Пакетные каналы: отправьте MenuItem так же, как и в каналах, но с пустым parentMenuSectionId .

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

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

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

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