效能提升秘訣

本文說明提升應用程式成效的幾個技巧。在某些情況下,我們會使用其他 API 或一般 API 的範例來說明這些技巧背後的概念。然而,同樣的概念也適用於 Google Wallet API。

使用 gzip 壓縮

要減少每個要求占用的頻寬,最簡單的方法就是使用 gzip 壓縮檔。雖然此方法需要額外的 CPU 作業時間解壓縮,但相對可省下可觀的網路成本。

如果要接收以 gzip 編碼的回應,您必須執行下列兩項操作:設定 Accept-Encoding 標頭,並修改您的使用者代理程式來加入字串 gzip。以下是一個啟用 gzip 壓縮的正確 HTTP 標頭格式範例:

Accept-Encoding: gzip
User-Agent: my program (gzip)

使用部分資源

另一種提高 API 呼叫成效的方式,就是只收發您有興趣的資料。這麼做可避免讓您的應用程式傳輸、剖析及儲存不需要的欄位,進而更有效地使用網路、CPU 以及記憶體等資源。

部分要求分為兩種類型:

  • 部分回應:您可以在這類要求中,指定要在回應中加入哪些欄位 (使用 fields 要求參數)。
  • 修補:透過這類更新要求,您可以只傳送想要變更的欄位 (使用 PATCH HTTP 動詞)。

接下來的章節將會詳細說明如何提交部分要求。

部分回應

根據預設,伺服器會在處理要求後傳回完整的資源表示法。為改善成效,您可以要求伺服器只傳送您真正需要的欄位,並改為取得「部分回應」

如果要請求部分回應,請使用 fields 要求參數來指定您想要傳回的欄位。您可以將此參數搭配任何會傳回回應資料的要求使用。

請注意,fields 參數只會影響回應資料;不會影響您需要傳送的資料 (如果有的話)。如果要減少您在修改資源時傳送的資料量,請使用修補要求。

範例

以下範例顯示 fields 參數與某個通用 (虛構) 的「Demo」API 的搭配用法。

簡易要求:此 HTTP GET 要求會省略 fields 參數,並傳回完整的資源。

https://www.googleapis.com/demo/v1

完整資源回應:完整資源資料包括下列欄位 (為節省篇幅,此處省略許多其他欄位)。

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

要求部分回應:以下是對相同資源發出的要求,其中使用了 fields 參數,以大幅減少傳回的資料量。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

部分回應:在上方的要求回應中,伺服器傳回的回應只包含種類資訊,以及經過簡化的項目陣列 (只包含個別項目的 HTML 標題和長度特性資訊)。

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

請注意,回應是一個 JSON 物件,且此物件只包含選定的欄位及其所含的父項物件。

以下將詳述如何設定 fields 參數的格式,接著再進一步說明回應中實際傳回的內容。

Fields 參數語法摘要

fields 要求參數值的格式約略以 XPath 語法為基礎。支援的語法簡述如下,其他範例如下節所示。

  • 使用以逗號分隔的清單來選取多個欄位。
  • 使用 a/ba 欄位的巢狀結構內選取 b 欄位;使用 a/b/cb 的巢狀結構內選取 c 欄位。

    例外狀況:如果 API 回應使用「data」包裝函式,也就是在 data 物件中建立看起來像 data: { ... } 的巢狀回應,請勿在 fields 規格中加入「data」。將 data 物件加入類似 data/a/b 的 fields 規格會造成錯誤。請改為只使用 fields 規格,例如 a/b

  • 透過在括號「( )」中放入運算式,使用子選擇器來要求一組指定的陣列或物件子欄位。

    例如:fields=items(id,author/email) 只會傳回項目陣列中各個元素的項目 ID 以及作者的電子郵件地址。您也可以指定單一子欄位,其中 fields=items(id) 等於 fields=items/id

  • 必要時,在欄位選取項目中使用萬用字元。

    例如:fields=items/pagemap/* 可選取網頁地圖中的所有物件。

使用 fields 參數的其他範例

以下範例包含 fields 參數值會如何影響回應的說明。

附註:和所有查詢參數值一樣,fields 參數值也必須使用網址編碼。為方便閱讀,本文中的範例會省略編碼。

找出您要傳回的欄位,或「選取欄位」
fields 要求參數值是以逗號分隔的欄位清單,每個欄位是根據回應的根來指定。因此,如果您執行的是清單作業,回應會是一個集合,其中通常包含資源陣列。如果您執行的作業傳回單一資源,欄位會根據該資源來指定。如果您選取的欄位是一個陣列 (或陣列的一部分),則伺服器會傳回該陣列中所有元素的選定部分。

以下提供幾個集合層級的範例:
示例 效果
items 傳回項目陣列中的所有元素,包括每個元素中的所有欄位,但不包含其他欄位。
etag,items 同時傳回 etag 欄位和項目陣列中的所有元素。
items/title 只傳回項目陣列中所有元素的 title 欄位。

每當傳回巢狀欄位時,回應會包含其所含父項物件。父欄位不會包含任何其他的子欄位 (除非已同時明確地選擇這些欄位)。
context/facets/label 只傳回 facets 陣列所有成員的 label 欄位,其本身是以巢狀結構嵌入 context 物件中。
items/pagemap/*/title 針對項目陣列中的每個元素,只傳回屬於 pagemap 子項之所有物件的 title 欄位 (如果有的話)。

以下提供幾個資源層級的範例:
示例 效果
title 傳回所要求資源的 title 欄位。
author/uri 傳回所要求資源中 author 物件的 uri 子欄位。
links/*/href
傳回屬於 links 子項之所有物件的 href 欄位。
使用「子選取項目」,只要求特定欄位的部分內容。
根據預設,如果您的要求指定特定的欄位,伺服器會傳回整個物件或陣列元素。您可以指定只包含特定子欄位的回應。方法很簡單,只要使用「( )」子選取項目語法即可,如下列範例所示。
範例 效果
items(title,author/uri) 只傳回項目陣列中每個元素的 title 值以及作者的 uri 值。

處理部分回應

伺服器處理包含 fields 查詢參數的有效要求後,會傳回一個 HTTP 200 OK 狀態碼,以及所要求的資料。如果 fields 查詢參數發生錯誤或無效,伺服器會傳回 HTTP 400 Bad Request 狀態碼和錯誤訊息,指出使用者選擇欄位時發生的錯誤 (例如 "Invalid field selection a/b")。

以下是上方簡介一節中的部分回應範例。此要求使用 fields 參數來指定要傳回的欄位。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

部分回應的樣式如下所示:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

附註:如果 API 支援用於資料分頁的查詢參數 (例如 maxResultsnextPageToken),請使用這些參數將每個查詢的結果減少到方便管理的大小。否則,可能無法有效提升部分回應的效能。

修補 (部分更新)

修改資源時,您也可以避免傳送不必要的資料。如果是僅為要變更的特定欄位傳送更新資料,請使用 HTTP PATCH 動詞。相較於舊版的 GData 部分更新執行方式,在本文中,「修補」一詞的語意變得更加簡單。

下面的簡短範例將會示範如何使用修補功能,在進行小規模更新時將您需要傳送的資料量減到最小。

範例

此範例將會示範如何使用一段簡短的修補要求,只更新一個通用 (虛構) 的「Demo」API 資源標題。這項資源同時包含註解、一組特性、狀態以及許多其他欄位,但此要求只會傳送 title 欄位,因為這是唯一需要修改的欄位:

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

回應:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

伺服器會傳回 200 OK 狀態碼,以及更新後資源的完整表示法。由於修補要求只包含 title 欄位,因此這個值是唯一與以往不同的值。

附註:如果您將部分回應 fields 參數與修補一起使用,就可以進一步提高更新要求的效率。修補請求只能減少要求的大小,而部分回應則能減少回應的大小。因此,要減少雙向傳送的資料量,請將修補要求與 fields 參數搭配使用。

修補要求的語意

修補要求的主體只包含您想要修改的資源欄位。您必須在指定欄位時加入任何其內含的父項物件,而這些欄位內含的父項物件將會連同部分回應一併傳回。修改後的資料會在傳送時合併至父物件的資料中 (如果有父物件存在的話)。

  • 新增:若要新增一個還不存在的欄位,請指定新的欄位及其欄位值。
  • 修改:若要變更現有欄位的值,請指定該欄位,並設為新的值。
  • 刪除:如要刪除欄位,請指定欄位並設為 null。例如 "comment": null。您也可以將可變動的物件設為 null,以便將整個物件刪除。如果您使用的是 Java API 用戶端程式庫,請改用 Data.NULL_STRING;詳情請參閱 JSON null 的相關說明。

有關陣列的注意事項:含有陣列的修補要求會以您提供的陣列取代現有的陣列。您無法個別修改、新增或刪除陣列中的項目。

在「讀取 - 修改 - 寫入」週期中使用修補功能

建議您可以從擷取附帶想要修改的資料的部分回應著手,特別是當資源使用 ETag 時。這是因為您必須提供 If-Match HTTP 標頭目前的 ETag 值,才能成功更新資源。取得資料之後,您便可以接著修改需要變更的值,並將修改過的部分表示法連同修補要求一併傳回。以下是一個假設 Demo 資源使用 ETag 的範例:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

以下是部分回應:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

以下修補要求是以該回應為建構依據。此要求同時使用 fields 參數來限制修補回應傳回的資料,如下所示:

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

伺服器會在回應中提供 200 OK HTTP 狀態碼,以及更新後資源的部分表示法:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

直接建構修補要求

部分修補要求必須以您先前擷取的資料做為建構依據。舉例來說,如果您想要在陣列中新增一個項目,卻又不想失去任何現有的陣列元素,則您必須先取得現有的資料。同樣地,當 API 使用 ETag 時,您必須將先前的 ETag 值連同您的要求一起送出,才能成功更新資源。

附註:使用 ETag 時,您可以使用 "If-Match: *" HTTP 標頭強制通過修補。這麼一來,您就不需要在寫入之前先進行讀取。

然而,在其他情況下,您可以直接建構修補要求,而不需要先擷取現有的資料。舉例來說,您可以輕鬆建構一個用來更新欄位值或新增欄位的修補要求。範例如下:

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

此要求會將註解欄位設為新的值,或是以新的值覆寫掉註解欄位現有的值。同樣地,如果有 volume 特性存在,則會覆寫掉該值;否則就會建立該特性。如果有設定好的精確度欄位存在,則會移除該欄位。

處理修補回應

API 會在處理完有效的修補要求之後,傳回 200 OK HTTP 回應代碼以及修改後資源的完整表示法。如果 API 有使用 ETag 的話,伺服器會在成功處理完修補要求時更新 ETag 的值,就像 PUT 一樣。

修補要求會傳回整個資源表示法,除非您使用 fields 參數來減少傳回的資料量。

如果 修補 要求產生的新資源狀態具有無效的語法或語意,則伺服器會傳回 400 Bad Request 或 422 Unprocessable Entity HTTP 狀態碼,且資源狀態維持不變。舉例來說,如果您嘗試刪除必填欄位的值,則伺服器會傳回錯誤。

當 PATCH HTTP 動詞未受支援時可使用的替代標示方法

如果您的防火牆禁止使用 HTTP PATCH 要求,請執行 HTTP POST 要求,並將替換標頭設定為 PATCH,如下所示:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

修補和更新之間的差異

就實務層面而言,為使用了 HTTP PUT 動詞的更新要求傳送資料時,您只需要傳送必填或選填欄位;如果您傳送了由伺服器設定的欄位值,這些值將會遭到忽略。雖然這看起來像是執行部分更新的另一種方法,但此方法有一些限制存在。使用 HTTP PUT 動詞進行更新時,如果您沒有提供必要參數,則要求將會失敗;此外,如果您沒有提供選用參數,則要求將會清除先前設定的資料。

這也是在此情況下使用修補更加安全的原因。您只需要為您想要變更的欄位提供資料,而您省略的欄位將不會被清除。此規則唯一的例外便是重複元素或陣列:如果您全數省略,它們將會保持原狀;如果您提供了任何重複元素或陣列,則整組元素或陣列都會替換成您提供的組合。

對 Google 錢包批次要求

Google Wallet API 支援批次 API 呼叫,可減少用戶端必須建立連線的連線數量。如要進一步瞭解批次要求和回應結構,請參閱批次詳細資料一文。

下列程式碼範例示範如何批次處理要求。Java 和 PHP 範例使用 Google 電子錢包程式庫來簡化類別和物件建立流程。

Java

如要開始在 Java 中整合,請參閱 GitHub 上完整的程式碼範例

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 */
public void batchCreateObjects(String issuerId, String classSuffix) throws IOException {
  // Create the batch request client
  BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));

  // The callback will be invoked for each request in the batch
  JsonBatchCallback<GiftCardObject> callback =
      new JsonBatchCallback<GiftCardObject>() {
        // Invoked if the request was successful
        public void onSuccess(GiftCardObject response, HttpHeaders responseHeaders) {
          System.out.println("Batch insert response");
          System.out.println(response.toString());
        }

        // Invoked if the request failed
        public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
          System.out.println("Error Message: " + e.getMessage());
        }
      };

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++) {
    // Generate a random object suffix
    String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
    GiftCardObject batchObject =
        new GiftCardObject()
            .setId(String.format("%s.%s", issuerId, objectSuffix))
            .setClassId(String.format("%s.%s", issuerId, classSuffix))
            .setState("ACTIVE")
            .setHeroImage(
                new Image()
                    .setSourceUri(
                        new ImageUri()
                            .setUri(
                                "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                    .setContentDescription(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString()
                                    .setLanguage("en-US")
                                    .setValue("Hero image description"))))
            .setTextModulesData(
                    List.of(
                            new TextModuleData()
                                    .setHeader("Text module header")
                                    .setBody("Text module body")
                                    .setId("TEXT_MODULE_ID")))
            .setLinksModuleData(
                new LinksModuleData()
                    .setUris(
                        Arrays.asList(
                            new Uri()
                                .setUri("http://maps.google.com/")
                                .setDescription("Link module URI description")
                                .setId("LINK_MODULE_URI_ID"),
                            new Uri()
                                .setUri("tel:6505555555")
                                .setDescription("Link module tel description")
                                .setId("LINK_MODULE_TEL_ID"))))
            .setImageModulesData(
                    List.of(
                            new ImageModuleData()
                                    .setMainImage(
                                            new Image()
                                                    .setSourceUri(
                                                            new ImageUri()
                                                                    .setUri(
                                                                            "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                                                    .setContentDescription(
                                                            new LocalizedString()
                                                                    .setDefaultValue(
                                                                            new TranslatedString()
                                                                                    .setLanguage("en-US")
                                                                                    .setValue("Image module description"))))
                                    .setId("IMAGE_MODULE_ID")))
            .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
            .setLocations(
                    List.of(
                            new LatLongPoint()
                                    .setLatitude(37.424015499999996)
                                    .setLongitude(-122.09259560000001)))
            .setCardNumber("Card number")
            .setPin("1234")
            .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD"))
            .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00"));

    service.giftcardobject().insert(batchObject).queue(batch, callback);
  }

  // Invoke the batch API calls
  batch.execute();
}

PHP

如要開始在 PHP 中整合,請參閱完整的 GitHub 程式碼範例

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for the pass class.
 */
public function batchCreateObjects(string $issuerId, string $classSuffix)
{
  // Update the client to enable batch requests
  $this->client->setUseBatch(true);
  $batch = $this->service->createBatch();

  // Example: Generate three new pass objects
  for ($i = 0; $i < 3; $i++) {
    // Generate a random object suffix
    $objectSuffix = preg_replace('/[^\w.-]/i', '_', uniqid());

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
    $batchObject = new GiftCardObject([
      'id' => "{$issuerId}.{$objectSuffix}",
      'classId' => "{$issuerId}.{$classSuffix}",
      'state' => 'ACTIVE',
      'heroImage' => new Image([
        'sourceUri' => new ImageUri([
          'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        ]),
        'contentDescription' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => 'Hero image description'
          ])
        ])
      ]),
      'textModulesData' => [
        new TextModuleData([
          'header' => 'Text module header',
          'body' => 'Text module body',
          'id' => 'TEXT_MODULE_ID'
        ])
      ],
      'linksModuleData' => new LinksModuleData([
        'uris' => [
          new Uri([
            'uri' => 'http://maps.google.com/',
            'description' => 'Link module URI description',
            'id' => 'LINK_MODULE_URI_ID'
          ]),
          new Uri([
            'uri' => 'tel:6505555555',
            'description' => 'Link module tel description',
            'id' => 'LINK_MODULE_TEL_ID'
          ])
        ]
      ]),
      'imageModulesData' => [
        new ImageModuleData([
          'mainImage' => new Image([
            'sourceUri' => new ImageUri([
              'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            ]),
            'contentDescription' => new LocalizedString([
              'defaultValue' => new TranslatedString([
                'language' => 'en-US',
                'value' => 'Image module description'
              ])
            ])
          ]),
          'id' => 'IMAGE_MODULE_ID'
        ])
      ],
      'barcode' => new Barcode([
        'type' => 'QR_CODE',
        'value' => 'QR code value'
      ]),
      'locations' => [
        new LatLongPoint([
          'latitude' => 37.424015499999996,
          'longitude' =>  -122.09259560000001
        ])
      ],
      'cardNumber' => 'Card number',
      'pin' => '1234',
      'balance' => new Money([
        'micros' => 20000000,
        'currencyCode' => 'USD'
      ]),
      'balanceUpdateTime' => new DateTime([
        'date' => '2020-04-12T16:20:50.52-04:00'
      ])
    ]);

    $batch->add($this->service->giftcardobject->insert($batchObject));
  }

  // Make the batch request
  $batchResponse = $batch->execute();

  print "Batch insert response\n";
  foreach ($batchResponse as $key => $value) {
    if ($value instanceof Google_Service_Exception) {
      print_r($value->getErrors());
      continue;
    }
    print "{$value->getId()}\n";
  }
}

Python

如要開始在 Python 中整合,請參閱 GitHub 上完整的程式碼範例

def batch_create_objects(self, issuer_id: str, class_suffix: str):
    """Batch create Google Wallet objects from an existing class.

    The request body will be a multiline string. See below for information.

    https://cloud.google.com/compute/docs/api/how-tos/batch#example

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for this pass class.
    """
    batch = self.client.new_batch_http_request()

    # Example: Generate three new pass objects
    for _ in range(3):
        # Generate a random object suffix
        object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')

        # See link below for more information on required properties
        # https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
        batch_object = {
            'id': f'{issuer_id}.{object_suffix}',
            'classId': f'{issuer_id}.{class_suffix}',
            'state': 'ACTIVE',
            'heroImage': {
                'sourceUri': {
                    'uri':
                        'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Hero image description'
                    }
                }
            },
            'textModulesData': [{
                'header': 'Text module header',
                'body': 'Text module body',
                'id': 'TEXT_MODULE_ID'
            }],
            'linksModuleData': {
                'uris': [{
                    'uri': 'http://maps.google.com/',
                    'description': 'Link module URI description',
                    'id': 'LINK_MODULE_URI_ID'
                }, {
                    'uri': 'tel:6505555555',
                    'description': 'Link module tel description',
                    'id': 'LINK_MODULE_TEL_ID'
                }]
            },
            'imageModulesData': [{
                'mainImage': {
                    'sourceUri': {
                        'uri':
                            'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                    },
                    'contentDescription': {
                        'defaultValue': {
                            'language': 'en-US',
                            'value': 'Image module description'
                        }
                    }
                },
                'id': 'IMAGE_MODULE_ID'
            }],
            'barcode': {
                'type': 'QR_CODE',
                'value': 'QR code'
            },
            'locations': [{
                'latitude': 37.424015499999996,
                'longitude': -122.09259560000001
            }],
            'cardNumber': 'Card number',
            'pin': '1234',
            'balance': {
                'micros': 20000000,
                'currencyCode': 'USD'
            },
            'balanceUpdateTime': {
                'date': '2020-04-12T16:20:50.52-04:00'
            }
        }

        batch.add(self.client.giftcardobject().insert(body=batch_object))

    # Invoke the batch API calls
    response = batch.execute()

    print('Batch complete')

C#

如要開始在 C# 中整合,請參閱 GitHub 上完整的程式碼範例

/// <summary>
/// Batch create Google Wallet objects from an existing class.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
public async void BatchCreateObjects(string issuerId, string classSuffix)
{
  // The request body will be a multiline string
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch//example
  string data = "";

  HttpClient httpClient = new HttpClient();
  httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer",
    credentials.GetAccessTokenForRequestAsync().Result
  );

  // Example: Generate three new pass objects
  for (int i = 0; i < 3; i++)
  {
    // Generate a random object suffix
    string objectSuffix = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_");

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
    GiftCardObject batchObject = new GiftCardObject
    {
      Id = $"{issuerId}.{objectSuffix}",
      ClassId = $"{issuerId}.{classSuffix}",
      State = "ACTIVE",
      HeroImage = new Image
      {
        SourceUri = new ImageUri
        {
          Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
        },
        ContentDescription = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "Hero image description"
          }
        }
      },
      TextModulesData = new List<TextModuleData>
      {
        new TextModuleData
        {
          Header = "Text module header",
          Body = "Text module body",
          Id = "TEXT_MODULE_ID"
        }
      },
      LinksModuleData = new LinksModuleData
      {
        Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
        {
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "http://maps.google.com/",
            Description = "Link module URI description",
            Id = "LINK_MODULE_URI_ID"
          },
          new Google.Apis.Walletobjects.v1.Data.Uri
          {
            UriValue = "tel:6505555555",
            Description = "Link module tel description",
            Id = "LINK_MODULE_TEL_ID"
          }
        }
      },
      ImageModulesData = new List<ImageModuleData>
      {
        new ImageModuleData
        {
          MainImage = new Image
          {
            SourceUri = new ImageUri
            {
              Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
            },
            ContentDescription = new LocalizedString
            {
              DefaultValue = new TranslatedString
              {
                Language = "en-US",
                Value = "Image module description"
              }
            }
          },
          Id = "IMAGE_MODULE_ID"
        }
      },
      Barcode = new Barcode
      {
        Type = "QR_CODE",
        Value = "QR code"
      },
      Locations = new List<LatLongPoint>
      {
        new LatLongPoint
        {
          Latitude = 37.424015499999996,
          Longitude = -122.09259560000001
        }
      },
      CardNumber = "Card number",
      Pin = "1234",
      Balance = new Money
      {
        Micros = 20000000,
        CurrencyCode = "USD"
      },
      BalanceUpdateTime = new Google.Apis.Walletobjects.v1.Data.DateTime
      {
        Date = "2020-04-12T16:20:50.52-04:00"
      }
    };

    data += "--batch_createobjectbatch\n";
    data += "Content-Type: application/json\n\n";
    data += "POST /walletobjects/v1/giftCardObject/\n\n";

    data += JsonConvert.SerializeObject(batchObject) + "\n\n";
  }
  data += "--batch_createobjectbatch--";

  // Invoke the batch API calls
  HttpRequestMessage batchObjectRequest = new HttpRequestMessage(
      HttpMethod.Post,
      "https://walletobjects.googleapis.com/batch");

  batchObjectRequest.Content = new StringContent(data);
  batchObjectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(
      "multipart/mixed");
  // `boundary` is the delimiter between API calls in the batch request
  batchObjectRequest.Content.Headers.ContentType.Parameters.Add(
      new NameValueHeaderValue("boundary", "batch_createobjectbatch"));

  HttpResponseMessage batchObjectResponse = httpClient.Send(
      batchObjectRequest);

  string batchObjectContent = await batchObjectResponse
      .Content
      .ReadAsStringAsync();

  Console.WriteLine("Batch insert response");
  Console.WriteLine(batchObjectContent);
}

Node.js

如要開始在節點中整合,請參閱完整的 GitHub 程式碼範例

/**
 * Batch create Google Wallet objects from an existing class.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for this pass class.
 */
async batchCreateObjects(issuerId, classSuffix) {
  // See below for more information
  // https://cloud.google.com/compute/docs/api/how-tos/batch#example
  let data = '';
  let batchObject;
  let objectSuffix;

  // Example: Generate three new pass objects
  for (let i = 0; i < 3; i++) {
    // Generate a random object suffix
    objectSuffix = uuidv4().replace('[^\w.-]', '_');

    // See link below for more information on required properties
    // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
    batchObject = {
      'id': `${issuerId}.${objectSuffix}`,
      'classId': `${issuerId}.${classSuffix}`,
      'state': 'ACTIVE',
      'heroImage': {
        'sourceUri': {
          'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
        },
        'contentDescription': {
          'defaultValue': {
            'language': 'en-US',
            'value': 'Hero image description'
          }
        }
      },
      'textModulesData': [
        {
          'header': 'Text module header',
          'body': 'Text module body',
          'id': 'TEXT_MODULE_ID'
        }
      ],
      'linksModuleData': {
        'uris': [
          {
            'uri': 'http://maps.google.com/',
            'description': 'Link module URI description',
            'id': 'LINK_MODULE_URI_ID'
          },
          {
            'uri': 'tel:6505555555',
            'description': 'Link module tel description',
            'id': 'LINK_MODULE_TEL_ID'
          }
        ]
      },
      'imageModulesData': [
        {
          'mainImage': {
            'sourceUri': {
              'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
            },
            'contentDescription': {
              'defaultValue': {
                'language': 'en-US',
                'value': 'Image module description'
              }
            }
          },
          'id': 'IMAGE_MODULE_ID'
        }
      ],
      'barcode': {
        'type': 'QR_CODE',
        'value': 'QR code'
      },
      'locations': [
        {
          'latitude': 37.424015499999996,
          'longitude': -122.09259560000001
        }
      ],
      'cardNumber': 'Card number',
      'pin': '1234',
      'balance': {
        'micros': 20000000,
        'currencyCode': 'USD'
      },
      'balanceUpdateTime': {
        'date': '2020-04-12T16:20:50.52-04:00'
      }
    };

    data += '--batch_createobjectbatch\n';
    data += 'Content-Type: application/json\n\n';
    data += 'POST /walletobjects/v1/giftCardObject\n\n';

    data += JSON.stringify(batchObject) + '\n\n';
  }
  data += '--batch_createobjectbatch--';

  // Invoke the batch API calls
  let response = await this.client.context._options.auth.request({
    url: 'https://walletobjects.googleapis.com/batch',
    method: 'POST',
    data: data,
    headers: {
      // `boundary` is the delimiter between API calls in the batch request
      'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch'
    }
  });

  console.log('Batch insert response');
  console.log(response);
}

查看

如要在 Go 中開始整合作業,請參閱 GitHub 上的完整程式碼範例 GitHub 上的程式碼範例

// Batch create Google Wallet objects from an existing class.
func (d *demoGiftcard) batchCreateObjects(issuerId, classSuffix string) {
	data := ""
	for i := 0; i < 3; i++ {
		objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")

		giftcardObject := new(walletobjects.GiftCardObject)
		giftcardObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
		giftcardObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
		giftcardObject.State = "ACTIVE"
		giftcardObject.CardNumber = "Card number"

		giftcardJson, _ := json.Marshal(giftcardObject)
		batchObject := fmt.Sprintf("%s", giftcardJson)

		data += "--batch_createobjectbatch\n"
		data += "Content-Type: application/json\n\n"
		data += "POST /walletobjects/v1/giftCardObject\n\n"
		data += batchObject + "\n\n"
	}
	data += "--batch_createobjectbatch--"

	res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))

	if err != nil {
		fmt.Println(err)
	} else {
		b, _ := io.ReadAll(res.Body)
		fmt.Printf("Batch insert response:\n%s\n", b)
	}
}