Tips performa

Dokumen ini membahas beberapa teknik yang dapat Anda gunakan untuk meningkatkan performa aplikasi. Dalam beberapa kasus, contoh dari API lain atau API generik digunakan untuk mengilustrasikan ide yang disajikan. Namun, konsep yang sama berlaku untuk Google Wallet API.

Kompresi menggunakan gzip

Cara yang mudah dan nyaman untuk mengurangi bandwidth yang diperlukan untuk setiap permintaan adalah dengan mengaktifkan kompresi gzip. Meskipun penggunaan CPU tambahan memerlukan waktu untuk mengekstrak hasil, manfaatnya terhadap biaya jaringan biasanya sangat sepadan.

Untuk menerima respons yang dienkode ke gzip, Anda harus melakukan dua hal: Menetapkan header Accept-Encoding, dan mengubah agen pengguna agar berisi string gzip. Berikut adalah contoh header HTTP yang diformat dengan benar untuk mengaktifkan kompresi gzip:

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

Bekerja dengan resource parsial

Cara lain untuk meningkatkan performa panggilan API adalah dengan mengirim dan menerima hanya sebagian data yang Anda inginkan. Hal ini memungkinkan aplikasi Anda menghindari transfer, penguraian, dan penyimpanan kolom yang tidak dibutuhkan, sehingga dapat menggunakan resource termasuk jaringan, CPU, dan memori secara lebih efisien.

Ada dua jenis permintaan parsial:

  • Respons sebagian: Permintaan untuk menentukan kolom yang akan disertakan dalam respons (gunakan parameter permintaan fields).
  • Patch: Permintaan update yang hanya mengirimkan kolom yang ingin diubah (menggunakan kata kerja HTTP PATCH).

Detail selengkapnya tentang cara membuat permintaan sebagian akan disediakan di bagian berikut.

Respons sebagian

Secara default, server mengirimkan kembali representasi penuh resource setelah memproses permintaan. Untuk mendapatkan performa yang lebih baik, Anda dapat meminta server untuk hanya mengirim kolom yang benar-benar diperlukan dan mendapatkan respons sebagian.

Untuk meminta respons sebagian, gunakan parameter permintaan fields untuk menentukan kolom yang ingin ditampilkan. Anda dapat menggunakan parameter ini dengan permintaan apa pun yang menampilkan data respons.

Perhatikan bahwa parameter fields hanya memengaruhi data respons; hal itu tidak memengaruhi data yang perlu Anda kirim, jika ada. Untuk mengurangi jumlah data yang dikirim saat mengubah resource, gunakan permintaan patch.

Contoh

Contoh berikut menunjukkan penggunaan parameter fields dengan API "Demo" generik (fiksi).

Permintaan sederhana: Permintaan GET HTTP ini menghilangkan parameter fields dan menampilkan resource lengkap.

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

Respons resource lengkap: Data resource lengkap mencakup kolom berikut, beserta banyak kolom lainnya yang telah dihilangkan agar lebih singkat.

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

Permintaan respons parsial: Permintaan berikut untuk resource yang sama ini menggunakan parameter fields untuk mengurangi jumlah data yang ditampilkan secara signifikan.

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

Respons sebagian: Sebagai respons atas permintaan di atas, server mengirim kembali respons yang hanya berisi informasi jenis, beserta array item standar yang hanya menyertakan informasi karakteristik judul dan panjang HTML di setiap item.

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

Perhatikan bahwa responsnya adalah objek JSON yang hanya menyertakan kolom yang dipilih dan objek induk yang mencakupnya.

Detail tentang cara memformat parameter fields akan dibahas berikutnya, diikuti dengan detail selengkapnya tentang apa yang sebenarnya ditampilkan dalam respons.

Ringkasan sintaksis parameter kolom

Format nilai parameter permintaan fields hanya didasarkan pada sintaksis XPath. Sintaksis yang didukung dirangkum di bawah ini, dan contoh tambahan diberikan di bagian berikut.

  • Gunakan daftar yang dipisahkan koma untuk memilih beberapa kolom.
  • Gunakan a/b untuk memilih kolom b yang bertingkat dalam kolom a; gunakan a/b/c untuk memilih kolom c yang disusun bertingkat di dalam b.

    Pengecualian: Untuk respons API yang menggunakan wrapper "data", tempat respons disusun bertingkat dalam objek data yang terlihat seperti data: { ... }, jangan sertakan "data" di Spesifikasi fields. Menyertakan objek data dengan spesifikasi kolom seperti data/a/b akan menyebabkan error. Sebagai gantinya, cukup gunakan spesifikasi fields seperti a/b.

  • Gunakan sub-selektor untuk meminta kumpulan sub-kolom spesifik dari array atau objek dengan menempatkan ekspresi dalam tanda kurung "( )".

    Misalnya: fields=items(id,author/email) hanya menampilkan ID item dan email penulis untuk setiap elemen dalam array item. Anda juga dapat menentukan satu sub-kolom, dengan fields=items(id) setara dengan fields=items/id.

  • Gunakan karakter pengganti dalam pemilihan kolom, jika diperlukan.

    Misalnya: fields=items/pagemap/* memilih semua objek di peta halaman.

Contoh penggunaan parameter kolom lainnya

Contoh di bawah menyertakan deskripsi tentang pengaruh nilai parameter fields terhadap respons.

Catatan: Seperti semua nilai parameter kueri, nilai parameter fields harus dienkode ke URL. Agar lebih mudah dibaca, contoh dalam dokumen ini menghilangkan encoding.

Identifikasi kolom yang ingin Anda tampilkan, atau buat pilihan kolom.
Nilai parameter permintaan fields adalah daftar kolom yang dipisahkan koma, dan setiap kolom ditentukan secara relatif terhadap root respons. Jadi, jika Anda menjalankan operasi list, responsnya adalah kumpulan, dan biasanya mencakup array resource. Jika Anda melakukan operasi yang menampilkan satu resource, kolom akan ditetapkan relatif terhadap resource tersebut. Jika kolom yang Anda pilih adalah (atau merupakan bagian dari) array, server akan menampilkan bagian yang dipilih dari semua elemen dalam array.

Berikut beberapa contoh tingkat koleksi:
Contoh Efek
items Menampilkan semua elemen dalam array item, termasuk semua kolom di setiap elemen, tetapi tidak ada kolom lainnya.
etag,items Menampilkan kolom etag dan semua elemen dalam array item.
items/title Hanya menampilkan kolom title untuk semua elemen dalam array item.

Setiap kali kolom bertingkat ditampilkan, respons akan menyertakan objek induk yang mencakupnya. Kolom induk tidak menyertakan kolom turunan lainnya, kecuali jika kolom tersebut juga dipilih secara eksplisit.
context/facets/label Hanya menampilkan kolom label untuk semua anggota array facets, yang bertingkat dalam objek context.
items/pagemap/*/title Untuk setiap elemen dalam array item, hanya menampilkan kolom title (jika ada) dari semua objek yang merupakan turunan dari pagemap.

Berikut beberapa contoh tingkat resource:
Contoh Efek
title Menampilkan kolom title untuk resource yang diminta.
author/uri Menampilkan sub-kolom uri dari objek author dalam resource yang diminta.
links/*/href
Menampilkan kolom href dari semua objek yang merupakan turunan dari links.
Hanya minta bagian kolom tertentu menggunakan sub-pilihan.
Secara default, jika permintaan Anda menentukan kolom tertentu, server akan menampilkan objek atau elemen array secara keseluruhan. Anda dapat menentukan respons yang hanya menyertakan sub-kolom tertentu. Anda melakukannya menggunakan sintaksis sub-pilihan "( )", seperti dalam contoh di bawah.
Contoh Efek
items(title,author/uri) Hanya menampilkan nilai title dan uri penulis untuk setiap elemen dalam array item.

Menangani respons sebagian

Setelah server memproses permintaan valid yang menyertakan parameter kueri fields, server akan mengirimkan kembali kode status HTTP 200 OK, bersama dengan data yang diminta. Jikafields parameter kueri mengalami error atau tidak valid, server akan menampilkan400 Bad Request bersama dengan pesan error yang memberi tahu pengguna apa yang salah dengan pemilihan kolom (misalnya,"Invalid field selection a/b").

Berikut adalah contoh respons sebagian yang ditampilkan di bagian pendahuluan di atas. Permintaan menggunakan parameter fields untuk menentukan kolom yang akan ditampilkan.

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

Respons sebagian akan terlihat seperti ini:

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

Catatan: Untuk API yang mendukung parameter kueri untuk penomoran halaman data (misalnya, maxResults dan nextPageToken), gunakan parameter tersebut untuk mengurangi hasil setiap kueri ke ukuran yang dapat dikelola. Jika tidak, peningkatan kinerja yang mungkin terjadi dengan respons sebagian mungkin tidak akan terlihat.

Patch (update sebagian)

Anda juga dapat menghindari pengiriman data yang tidak perlu saat memodifikasi resource. Untuk mengirim data yang diperbarui hanya untuk kolom tertentu yang Anda ubah, gunakan kata kerja HTTP PATCH. Semantik patch yang dijelaskan dalam dokumen ini berbeda (dan lebih sederhana) dibandingkan dengan implementasi GData lama untuk update parsial.

Contoh singkat di bawah ini menunjukkan cara penggunaan patch akan meminimalkan data yang perlu Anda kirim untuk melakukan update kecil.

Contoh

Contoh ini menampilkan permintaan patch sederhana untuk memperbarui hanya judul resource API "Demo" umum (fiksi). Resource tersebut juga memiliki komentar, kumpulan karakteristik, status, dan banyak kolom lainnya, tetapi permintaan ini hanya mengirimkan kolom title karena satu-satunya kolom yang diubah:

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

{
  "title": "New title"
}

Respons:

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

Server menampilkan kode status 200 OK, beserta representasi lengkap resource yang diupdate. Karena hanya kolom title yang disertakan dalam permintaan patch, itu adalah satu-satunya nilai yang berbeda dari sebelumnya.

Catatan: Jika Anda menggunakan parameter fields respons sebagian bersama dengan patch, Anda dapat lebih meningkatkan efisiensi permintaan update. Permintaan patch hanya mengurangi ukuran permintaan. Respons sebagian akan mengurangi ukuran respons. Jadi, untuk mengurangi jumlah data yang dikirim secara dua arah, gunakan permintaan patch dengan parameter fields.

Semantik permintaan patch

Isi permintaan patch hanya menyertakan kolom resource yang ingin diubah. Saat menentukan kolom, Anda harus menyertakan objek induk yang mengapitnya, sama seperti induk yang mengapit ditampilkan dengan respons sebagian. Data yang dimodifikasi yang Anda kirim akan digabungkan ke dalam data untuk objek induk, jika ada.

  • Tambahkan: Untuk menambahkan kolom yang belum ada, tentukan kolom baru dan nilainya.
  • Ubah: Untuk mengubah nilai kolom yang ada, tentukan kolom dan tetapkan ke nilai baru.
  • Hapus: Untuk menghapus kolom, tentukan kolom dan tetapkan ke null. Misalnya, "comment": null Anda juga dapat menghapus seluruh objek (jika dapat diubah) dengan menyetelnya ke null. Jika Anda menggunakan Library Klien Java API, gunakan Data.NULL_STRING; untuk mengetahui detailnya, lihat JSON null.

Catatan tentang array: Permintaan patch yang berisi array akan menggantikan array yang ada dengan yang Anda berikan. Anda tidak dapat memodifikasi, menambahkan, atau menghapus item dalam array dengan tidak konsisten.

Menggunakan patch dalam siklus baca-ubah-tulis

Memulai dengan mengambil respons parsial dengan data yang ingin Anda ubah bisa menjadi praktik yang berguna. Hal ini sangat penting untuk resource yang menggunakan ETag karena Anda harus memberikan nilai ETag saat ini dalam header HTTP If-Match agar berhasil memperbarui resource. Setelah mendapatkan data, Anda dapat mengubah nilai yang ingin diubah dan mengirim kembali representasi parsial yang dimodifikasi dengan permintaan patch. Berikut ini contoh yang mengasumsikan bahwa resource Demo menggunakan ETag:

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

Ini adalah respons sebagian:

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

Permintaan patch berikut didasarkan pada respons tersebut. Seperti yang ditunjukkan di bawah, parameter ini juga menggunakan parameter fields untuk membatasi data yang ditampilkan dalam respons patch:

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. */
  },
}

Server merespons dengan kode status HTTP 200 OK, dan representasi sebagian dari resource yang diupdate:

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. */
  }
}

Membuat permintaan patch secara langsung

Untuk beberapa permintaan patch, Anda harus mendasarkannya pada data yang telah diambil sebelumnya. Misalnya, jika Anda ingin menambahkan item ke array dan tidak ingin kehilangan elemen array yang ada, Anda harus mendapatkan data yang ada terlebih dahulu. Demikian pula, jika API menggunakan ETag, Anda harus mengirimkan nilai ETag sebelumnya bersama permintaan agar sumber daya dapat diperbarui.

Catatan: Anda dapat menggunakan header HTTP "If-Match: *" untuk memaksa patch melewati ETag saat digunakan.  Jika Anda melakukan ini, Anda tidak perlu melakukan pembacaan sebelum menulis.

Namun, dalam situasi lain, Anda dapat membuat permintaan patch secara langsung, tanpa terlebih dahulu mengambil data yang ada. Misalnya, Anda dapat dengan mudah menyiapkan permintaan patch yang memperbarui kolom ke nilai baru atau menambahkan kolom baru. Berikut ini contohnya:

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

Dengan permintaan ini, jika kolom komentar memiliki nilai yang sudah ada, nilai baru akan menimpanya; jika tidak, nilai baru akan ditetapkan ke nilai baru. Demikian pula, jika ada karakteristik volume, nilainya akan ditimpa; jika tidak, model akan dibuat. Kolom akurasi, jika disetel, akan dihapus.

Menangani respons terhadap patch

Setelah memproses permintaan patch yang valid, API akan menampilkan kode respons HTTP 200 OK beserta representasi lengkap resource yang dimodifikasi. Jika ETag digunakan oleh API, server akan memperbarui nilai ETag jika berhasil memproses permintaan patch, seperti yang dilakukan pada PUT.

Permintaan patch menampilkan seluruh representasi resource, kecuali jika Anda menggunakan parameter fields untuk mengurangi jumlah data yang ditampilkan.

Jika permintaan patch menghasilkan status resource baru yang secara sintaksis atau semantik tidak valid, server akan menampilkan kode status HTTP 400 Bad Request atau 422 Unprocessable Entity, dan status resource tetap tidak berubah. Misalnya, jika Anda mencoba menghapus nilai untuk kolom yang wajib diisi, server akan menampilkan error.

Notasi alternatif saat kata kerja HTTP PATCH tidak didukung

Jika firewall Anda tidak mengizinkan permintaan PATCH HTTP, lakukan permintaan POST HTTP dan setel header penggantian ke PATCH, seperti yang ditunjukkan di bawah:

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

Perbedaan antara patch dan update

Dalam praktiknya, saat mengirim data untuk permintaan update yang menggunakan kata kerja PUT HTTP, Anda hanya perlu mengirim kolom yang wajib diisi atau opsional; jika Anda mengirim nilai untuk kolom yang ditetapkan oleh server, nilai tersebut akan diabaikan. Meskipun ini mungkin tampak seperti cara lain untuk melakukan pembaruan sebagian, pendekatan ini memiliki beberapa batasan. Dengan update yang menggunakan kata kerja PUT HTTP, permintaan akan gagal jika Anda tidak memberikan parameter yang diperlukan, dan permintaan ini akan menghapus data yang ditetapkan sebelumnya jika Anda tidak memberikan parameter opsional.

Jauh lebih aman untuk menggunakan patch karena alasan ini. Anda hanya menyediakan data untuk {i>field<i} yang ingin diubah; kolom yang Anda abaikan tidak dihapus. Satu-satunya pengecualian untuk aturan ini terjadi dengan elemen atau array berulang: Jika Anda menghilangkan semuanya, elemen atau array tersebut tetap seperti adanya; jika Anda menyediakannya, seluruh set data itu akan diganti dengan set data yang Anda berikan.

Mengajukan banyak permintaan ke Google Wallet

Google Wallet API mendukung batching API untuk mengurangi jumlah panggilan koneksi yang harus dibuat klien. Untuk informasi lebih lanjut tentang permintaan batch dan struktur respons, lihat Detail batch.

Kode contoh berikut menunjukkan permintaan batch. Java dan PHP contoh menggunakan paket Google Wallet library untuk menyederhanakan pembuatan class dan objek.

Java

Untuk memulai integrasi di Java, lihat contoh kode di 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<EventTicketObject> callback =
      new JsonBatchCallback<EventTicketObject>() {
        // Invoked if the request was successful
        public void onSuccess(EventTicketObject 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/tickets/events/rest/v1/eventticketobject
    EventTicketObject batchObject =
        new EventTicketObject()
            .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)))
            .setSeatInfo(
                new EventSeat()
                    .setSeat(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString().setLanguage("en-US").setValue("42")))
                    .setRow(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString().setLanguage("en-US").setValue("G3")))
                    .setSection(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString().setLanguage("en-US").setValue("5")))
                    .setGate(
                        new LocalizedString()
                            .setDefaultValue(
                                new TranslatedString().setLanguage("en-US").setValue("A"))))
            .setTicketHolderName("Ticket holder name")
            .setTicketNumber("Ticket number");

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

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

PHP

Untuk memulai integrasi di PHP, lihat contoh kode di 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/tickets/events/rest/v1/eventticketobject
    $batchObject = new EventTicketObject([
      '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
        ])
      ],
      'seatInfo' => new EventSeat([
        'seat' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => '42'
          ])
        ]),
        'row' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => 'G3'
          ])
        ]),
        'section' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => '5'
          ])
        ]),
        'gate' => new LocalizedString([
          'defaultValue' => new TranslatedString([
            'language' => 'en-US',
            'value' => 'A'
          ])
        ])
      ]),
      'ticketHolderName' => 'Ticket holder name',
      'ticketNumber' => 'Ticket number'
    ]);

    $batch->add($this->service->eventticketobject->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

Untuk memulai integrasi Anda di Python, lihat referensi contoh kode di 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/tickets/events/rest/v1/eventticketobject
        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
            }],
            'seatInfo': {
                'seat': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': '42'
                    }
                },
                'row': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'G3'
                    }
                },
                'section': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': '5'
                    }
                },
                'gate': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'A'
                    }
                }
            },
            'ticketHolderName': 'Ticket holder name',
            'ticketNumber': 'Ticket number'
        }

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

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

    print('Batch complete')

C#

Untuk memulai integrasi Anda di C#, lihat referensi contoh kode di 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/tickets/events/rest/v1/eventticketobject
    EventTicketObject batchObject = new EventTicketObject
    {
      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
        }
      },
      SeatInfo = new EventSeat
      {
        Seat = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "42"
          }
        },
        Row = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "G3"
          }
        },
        Section = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "5"
          }
        },
        Gate = new LocalizedString
        {
          DefaultValue = new TranslatedString
          {
            Language = "en-US",
            Value = "A"
          }
        }
      },
      TicketHolderName = "Ticket holder name",
      TicketNumber = "Ticket number"
    };

    data += "--batch_createobjectbatch\n";
    data += "Content-Type: application/json\n\n";
    data += "POST /walletobjects/v1/eventTicketObject/\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

Untuk memulai integrasi Anda di Node, lihat paket lengkap contoh kode di 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/tickets/events/rest/v1/eventticketobject
    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
        }
      ],
      'seatInfo': {
        'seat': {
          'defaultValue': {
            'language': 'en-US',
            'value': '42'
          }
        },
        'row': {
          'defaultValue': {
            'language': 'en-US',
            'value': 'G3'
          }
        },
        'section': {
          'defaultValue': {
            'language': 'en-US',
            'value': '5'
          }
        },
        'gate': {
          'defaultValue': {
            'language': 'en-US',
            'value': 'A'
          }
        },
      },
      'ticketHolderName': 'Ticket holder name',
      'ticketNumber': 'Ticket number'
    };

    data += '--batch_createobjectbatch\n';
    data += 'Content-Type: application/json\n\n';
    data += 'POST /walletobjects/v1/eventTicketObject\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

Untuk memulai integrasi Anda di Go, lihat contoh kode lengkap kami di GitHub contoh kode di GitHub.

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

		eventticketObject := new(walletobjects.EventTicketObject)
		eventticketObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
		eventticketObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
		eventticketObject.TicketHolderName = "Ticket holder name"
		eventticketObject.TicketNumber = "Ticket number"
		eventticketObject.State = "ACTIVE"

		eventticketJson, _ := json.Marshal(eventticketObject)
		batchObject := fmt.Sprintf("%s", eventticketJson)

		data += "--batch_createobjectbatch\n"
		data += "Content-Type: application/json\n\n"
		data += "POST /walletobjects/v1/eventTicketObject\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)
	}
}