실시간 업데이트

이 섹션에서는 시간에 민감한 인벤토리 업데이트를 전송하는 방법을 설명합니다. 항목을 Google에 제공합니다. 실시간 업데이트 API를 사용하면 프로덕션 인벤토리에서 거의 실시간으로 엔티티를 만들 수 있습니다.

이 기능은 예측 불가능한 업데이트에 주로 사용되므로 긴급 휴업, 메뉴에서 항목 삭제, 가격 업데이트 등 Google UI에 빠르게 반영되어야 합니다. 변경사항이 즉시 반영되지 않아도 되므로 일괄 수집을 사용하는 것이 좋습니다. 실시간 업데이트는 5분 이내로 할 수 있습니다.

기본 요건

실시간 업데이트를 구현하려면 다음 항목이 필요합니다.

  1. Maps Booking API가 사용 설정됨: <ph type="x-smartling-placeholder">
      </ph>
    • GCP에서 API 및 서비스 > 보관함
    • 'Google Maps Booking API'를 검색합니다.
      Google Maps Booking API 찾기
    • 샌드박스 인스턴스('Google Maps Booking API (Dev)')를 찾아 사용 설정
    • 프로덕션 인스턴스('Google Maps Booking API')를 찾아 클릭합니다. 사용 설정
      Google Maps Booking API 사용 설정
  2. GCP 프로젝트에 대한 편집자 역할로 서비스 계정이 생성됩니다. 대상 자세한 내용은 계정 설정
  3. 프로덕션 또는 샌드박스 데이터 피드가 호스팅되고 수집됩니다. 자세한 내용은 일괄 수집을 참조하세요.
  4. API 인증의 경우 Google 클라이언트 라이브러리를 선택의 기로에 서게 됩니다. OAuth로 'https://www.googleapis.com/auth/mapsbooking'을 사용합니다. 범위를 제공합니다 아래에 포함된 코드 샘플은 이러한 라이브러리를 사용합니다. 그렇지 않으면 이 페이지에 설명된 대로 토큰 교환을 수동으로 처리해야 합니다. OAuth 2.0을 사용하여 Google API에 액세스하기

개요

실시간 업데이트 API는 두 가지 유형의 작업을 지원합니다. 첫 번째 작업은 기존 항목 업데이트를 위한 upsert입니다. 이 두 번째 작업은 인벤토리에서 항목을 삭제하는 삭제입니다. 모두 작업은 요청 본문에 나열된 다양한 항목에서 수행됩니다. 나 한 API 호출로 최대 1,000개의 항목을 업데이트할 수 있습니다. API는 수신 요청을 모두 처리하고 추가 처리를 위해 큐에 배치합니다. 따라서 RTU 요청은 비동기식으로 처리됩니다.

실시간 업데이트 API는 샌드박스와 프로덕션 환경이라는 두 가지 환경에서 작동합니다. API 요청 및 프로덕션을 테스트하는 데 사용되는 샌드박스 환경 환경을 사용하여 주문 엔드 투 최종 사용자에게 표시되는 콘텐츠를 업데이트합니다. 호스트 이름 다음과 같습니다.

  • 샌드박스 - partnerdev-mapsbooking.googleapis.com
  • 프로덕션 - mapsbooking.googleapis.com

엔드포인트

실시간 업데이트 API는 수신 요청을 처리하기 위해 2개의 엔드포인트를 노출함 인벤토리 업데이트를 확인하세요.

  • UPSERT: /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
  • 삭제 - /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete

PARTNER_ID 매개변수는 작업 센터에서 확인할 수 있습니다. 아래 그림과 같이 계정 및 사용자 페이지에 파트너 ID로 표시됩니다. 확인할 수 있습니다.

파트너 포털의 파트너 ID

예를 들어 10000001PARTNER_ID 값으로 사용하면 샌드박스에서 API 요청을 보내기 위한 전체 URL과 아래 예와 같이 표시됩니다.

# 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
<ph type="x-smartling-placeholder">
# Production UPSERT
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
</ph>
# Production DELETE
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete

항목 업데이트

인벤토리의 항목을 업데이트하려면 UPSERT 엔드포인트를 사용합니다. HTTP POST 요청을 전송합니다 각 POST 요청에는 PARTNER_ID 매개변수와 구조화된 데이터일 수 있습니다.

요청 페이로드 업데이트 삽입

요청 본문은 레코드 목록이 포함된 JSON 객체입니다. 각 레코드 업데이트 중인 항목에 해당합니다. data_record 필드로 구성됩니다. Base64로 인코딩된 항목 페이로드와 generation_timestamp 다음은 항목 업데이트 시간을 나타냅니다.

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

위의 페이로드에서 다음을 바꿉니다.

  • BASE_64_ENCODED_ENTITY: 개체. 디코딩된 항목 JSON은 피드 사양. 예:

    {"@type":"MenuSection","name":"My Updated Menu Section","menuId":{"@id":"10824","displayOrder":1},"@id":"853705"}
  • UPDATE_TIMESTAMP: 항목이 백엔드 시스템에서 생성되었습니다. 이 타임스탬프는 다음을 위해 사용됩니다. 인벤토리 업데이트 순서를 올바르게 지정해야 합니다 이 필드가 포함되지 않으면 Google이 요청을 수신한 시간으로 설정됩니다. 업데이트 시 batchPush 요청을 통해 generation_timestamp 필드는 항목 버전 관리에 사용됩니다. 예상된 관계형 인벤토리의 시간 값 형식 사용할 수 있습니다

모든 실시간 업데이트 요청은 다음 조건을 충족해야 합니다.

  • 페이로드 본문의 크기는 5MB를 초과해서는 안 됩니다. Batch와 비슷한 피드에서 사용하는 경우 더 많은 데이터를 맞추기 위해 공백을 제거하는 것이 좋습니다.
  • batchPush 요청에는 최대 1,000개의 항목이 포함될 수 있습니다.

예 1: 식당 업데이트

급하게 식당의 전화번호를 업데이트해야 하는 경우 내 update에는 전체 식당의 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에 의한 실시간 업데이트는 다음과 같습니다.

JSON

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

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 요청이 다음과 같습니다.

JSON

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

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를 통한 실시간 업데이트는 다음과 같습니다.

JSON

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

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를 사용하세요. endpoint를 설정하고, HTTP POST 요청을 전송합니다. 각 POST 요청은 JSON 페이로드와 함께 PARTNER_ID 매개변수를 포함합니다. 포함된다는 사실을 기억하세요.

요청 페이로드 삭제

삭제 요청의 본문은 업데이트 요청을 참조하세요. data_recorddelete_time 필드가 있는 레코드 목록도 있습니다. <ph type="x-smartling-placeholder">

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_REFERENCE",
        "delete_time": "DELETE_TIMESTAMP"
      }
    ]
  }
</ph>

위의 페이로드에서 다음을 바꿉니다.

  • BASE_64_ENCODED_REFERENCE: 삭제되는 항목에 대한 참조입니다. 참조는 JSON 표현식과 같은 항목 유형 및 식별자의 MenuSection 참조는 다음과 같습니다.

    {"@type":"MenuSection","@id":"853705"}
  • DELETE_TIMESTAMP: 항목이 백엔드 시스템에서 삭제되었습니다. 이 타임스탬프는 인벤토리에 삭제를 적용할 순서를 결정합니다.

batchDelete 요청에는 최대 1,000개의 항목이 포함될 수 있습니다.

예 1: 두 개의 MenuItem 항목 삭제

단일 API 호출에서 두 개의 메뉴 항목을 제거하려는 경우 HTTP POST 요청은 다음과 같습니다.

JSON

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

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 항목 삭제

일괄 피드에서 식당을 삭제하려고 하는 상황을 생각해 보세요. 식당 항목만 삭제해야 합니다. 다음과 같은 하위 항목을 삭제하면 안 됩니다. 서비스와 메뉴는 자동으로 삭제되기 때문입니다.

ID가 있는 식당 항목을 삭제하기 위한 샘플 요청 https://www.provider.com/restaurant/12345:

JSON

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

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 호출에 대해 수행되는 두 가지 유형의 유효성 검사가 있습니다.

  • 요청 수준 - 이러한 유효성 검사는 페이로드가 upsert 또는 delete 스키마와 모든 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 업데이트의 할당량은 60초마다 요청 1,500개 또는 초당 평균 요청 수를 표시합니다 할당량을 초과하면 Google에서 다음과 같은 오류 메시지를 반환합니다.

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

이 문제를 해결하려면 호출이 성공할 때까지 기하급수적으로 큰 간격으로 다시 호출해 보세요. 정기적으로 할당량을 소진하는 경우 더 많은 항목을 포함해 보세요. 하나의 API 요청으로 구현됩니다. API 호출 한 번에 최대 1,000개의 항목을 포함할 수 있습니다.

코드 샘플

다음은 다양한 상황에서 실시간 업데이트 API를 사용하는 방법의 몇 가지 샘플입니다. 있습니다. 이 샘플은 Google 인증 라이브러리를 사용하여 서비스 계정 키 파일 생성 중 계정 설정 대안 솔루션은 다음을 참고하세요. 서버 간 애플리케이션에서 OAuth 2.0 사용하기 클라이언트 라이브러리 생성에서 사용할 수 있는 스키마를 사용하여 인벤토리의 소스 코드 및 실시간 업데이트 객체 유형을 생성해 보세요.

항목 업데이트

Node.js

이 코드는 Node.js용 Google 인증 라이브러리를 사용합니다.

/* 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'
  }
]);

Python

이 코드는 Python용 Google 인증 라이브러리를 사용합니다.

"""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'
}])

자바

이 코드는 Java용 Google 인증 라이브러리를 사용합니다.

rtusamples.inventoryrtusamples.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;
  }
}

항목 삭제

Node.js

이 코드는 Node.js용 Google 인증 라이브러리를 사용합니다.

/* 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'
    }
  ]);

Python

이 코드는 Python용 Google 인증 라이브러리를 사용합니다.

"""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'
}])

자바

이 코드는 Java용 Google 인증 라이브러리를 사용합니다.

rtusamples.inventoryrtusamples.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;
  }
}

사용 사례

다음은 실시간 업데이트, 일괄 피드 업데이트, 개략적인 내용은 다음과 같습니다.

시나리오 업데이트할 항목 설명 및 효과
서비스 사용 중지 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

실시간 업데이트: 명시적 삭제.

전체 피드: 전체 피드에서 항목을 삭제하기 전에 확인할 수 없습니다. 그렇지 않으면 해당 항목이 다시 추가됩니다.

특정 Service에 새 배송 지역 추가 ServiceArea 일괄 피드: 문제가 되는 ServiceArea 항목을 새로운 배송 지역이 포함된 전체 피드 내에서 일반적으로 하는 것처럼 입력란은 그대로 유지됩니다. polygon, geoRadius 또는 postalCode 내에 지정됩니다.
Service의 배송 예정 도착 시간 업데이트 ServiceHours 일괄 피드: ServiceHours를 피드(leadTimeMin가 업데이트됨) 변경할 수 있습니다
Service에서 배송비 업데이트 Fee 일괄 피드: 다음과 같이 전체 배송 Fee을 전송합니다. price이(가) 업데이트되었습니다.
Service에서 배달 또는 테이크아웃 영업시간 업데이트 ServiceHours 일괄 피드: ServiceHoursopenscloses 속성을 제외한 피드 변경할 수 있습니다
Service (최소 주문 금액 변경) Fee 일괄 피드: 다음과 같이 전체 Fee를 보냅니다. minPrice 업데이트됨
MenuItem 영구 삭제 Menu 일괄 피드: MenuItem를 피드가 있지만 parentMenuSectionId가 비어 있습니다.

일괄 작업 및 실시간 업데이트의 처리 시간

일괄 피드를 통해 업데이트되거나 삭제된 항목은 시간이 걸리는 반면, 실시간 업데이트를 통해 업데이트된 항목은 5분입니다. 가 오래된 항목 14일 후에 삭제됩니다

Google에 다음 정보를 보낼 수 있습니다.

  • 인벤토리를 최신 상태로 유지하기 위해 하루에 여러 개의 일괄 작업 또는
  • 하루에 한 개의 일괄 작업과 실시간 업데이트로 인벤토리를 최신 상태로 유지합니다.