Kirim Permintaan Batch

Dokumen ini menunjukkan cara mengelompokkan panggilan API secara bersamaan untuk mengurangi jumlah koneksi yang harus dibuat klien Anda.

Dokumen ini secara khusus membahas cara membuat permintaan batch menggunakan library klien Java. Contoh dasar juga tersedia di Library Klien Google API untuk .NET. Sistem batch untuk Google Play EMM API menggunakan HTTP yang sama sintaksis sebagai sistem OData batch processing.

Ringkasan

Setiap permintaan yang dibuat klien melalui Google Play EMM API akan mengakibatkan jumlah overhead tertentu. Google Play EMM API mendukung batch, agar klien Anda dapat menempatkan beberapa panggilan API ke dalam satu permintaan.

Berikut adalah beberapa contoh situasi yang mungkin membuat Anda ingin menggunakan pengelompokan:

  • Domain baru saja didaftarkan dan sekarang memiliki banyak data yang harus diupload.
  • Seorang pengguna membuat perubahan pada data saat aplikasi Anda sedang offline, sehingga aplikasi Anda perlu menyinkronkan banyak data lokal dengan server.

Dalam kasus semacam ini, daripada mengirim setiap panggilan secara terpisah, Anda dapat mengelompokkannya menjadi satu permintaan. Anda bahkan dapat mengelompokkan permintaan untuk beberapa pengguna, atau untuk beberapa Google API.

Namun, Anda dibatasi hingga 1.000 panggilan dalam satu permintaan batch. Jika Anda perlu melakukan lebih banyak panggilan dari itu, gunakan beberapa permintaan batch.

Detail batch

Permintaan batch terdiri dari beberapa panggilan API yang digabungkan menjadi satu permintaan JSON-RPC. Bagian ini menjelaskan sintaksis permintaan batch secara mendetail, dengan contoh di bagian berikut.

Catatan: Kumpulan permintaan n yang dikelompokkan bersama-sama dihitung dalam batas penggunaan Anda sebagai permintaan n, bukan sebagai satu permintaan. Permintaan batch dibagi menjadi serangkaian permintaan sebelum diproses.

Format permintaan batch

Library klien Java berisi panggilan untuk membuat permintaan bagi setiap panggilan API EMM Google Play. Misalnya, untuk mencantumkan semua aplikasi yang diinstal di perangkat, Anda harus menggunakan hal berikut:

AndroidEnterprise enterprise = ...;
InstallsListResponse response = enterprise.installs().list(enterpriseId, userId, deviceId)
  .execute();

Ada panggilan batch() tambahan yang dapat mengantrekan beberapa permintaan, seperti yang terlihat di sini:

AndroidEnterprise enterprise = ...;
BatchRequest batchRequest = enterprise.batch();
enterprise.installs().list(enterpriseId, userId, deviceId1).queue(batchRequest, callback1);
enterprise.installs().list(enterpriseId, userId, deviceId2).queue(batchRequest, callback2);
enterprise.installs().list(enterpriseId, userId, deviceId3).queue(batchRequest, callback3);
batchRequest.execute();
Saat batchRequest.execute() dipanggil, semua permintaan dalam antrean akan dikirim sekaligus ke server sebagai array JSON. Server menerapkan parameter kueri dan header permintaan luar (sebagaimana diperlukan) ke setiap bagian, lalu memperlakukan setiap bagian seolah-olah permintaan tersebut adalah permintaan JSON terpisah.

Respons terhadap permintaan batch

Server mengeksekusi setiap permintaan terpisah, dan mengelompokkan hasilnya menjadi respons tunggal yang dibuat dari satu array. Library klien membagi respons ini menjadi respons individual, dan masing-masing dikirim ke fungsi callback yang diteruskan ke queue(). Callback adalah antarmuka yang menetapkan metode untuk kegagalan dan metode untuk berhasil. Misalnya, callback1 akan diterapkan sebagai instance berikut:

private class InstallsCallback implements JsonBatchCallback<InstallsListResponse> {

  @Override
  public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
    ...
  }

  @Override
  public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
    ...
  }
}

Catatan: Server dapat melakukan panggilan Anda dalam urutan apa pun, jadi jangan mengandalkan penerimaan hasil dalam urutan yang ditentukan dalam permintaan Anda. Jika Anda ingin memastikan bahwa dua panggilan terjadi dalam urutan tertentu, Anda tidak dapat mengirimnya dalam satu permintaan; sebagai gantinya, mengirim permintaan pertama sendiri, dan menunggu respons sebelum mengirimkan yang kedua.

Contoh permintaan batch

Contoh berikut menunjukkan cara menampilkan daftar semua aplikasi yang diinstal di semua perangkat pengguna tertentu. Panggilan pertama digunakan untuk mendapatkan ID perusahaan dan pengguna, dan karenanya harus dijalankan secara berurutan. Setelah semua ID perangkat diperoleh dengan enterprise.devices().list(), kita dapat melakukan permintaan batch untuk mengambil semua aplikasi di semua perangkat pengguna sekaligus.

package com.google.playenterprise.example;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.androidenterprise.AndroidEnterprise;
import com.google.api.services.androidenterprise.AndroidEnterprise.Installs;
import com.google.api.services.androidenterprise.AndroidEnterpriseScopes;
import com.google.api.services.androidenterprise.model.Device;
import com.google.api.services.androidenterprise.model.DevicesListResponse;
import com.google.api.services.androidenterprise.model.Enterprise;
import com.google.api.services.androidenterprise.model.Install;
import com.google.api.services.androidenterprise.model.InstallsListResponse;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Lists all the apps installed on all devices of a given user.
 */
public class ListAllInstalls {
  private AndroidEnterprise enterprise;
  private final List<String> installList = new ArrayList<>();

  public static void main(String[] argv) throws Exception {
    if (argv.length != 2) {
      throw new IllegalArgumentException("Usage: ListAllInstalls email jsonFilename");
    } else if (!argv[0].contains("@")) {
      throw new IllegalArgumentException("First parameter should be a valid email.");
    }
    new ListAllInstalls().run(argv[0], argv[1]);
  }

  private void run(String userEmail, String jsonKeyPath) throws IOException {
    enterprise = createAndroidEnterprise(jsonKeyPath);

    // Get the enterprise id, user id, and user devices.
    String domain = userEmail.split("@")[1];
    List<Enterprise> results = enterprise.enterprises().list(domain).execute().getEnterprise();
    if (results.isEmpty()) {
      throw new RuntimeException("No enterprise found.");
    }
    String enterpriseId = results.get(0).getId();
    String userId = enterprise
        .users()
        .list(enterpriseId, userEmail)
        .execute()
        .getUser()
        .get(0)
        .getId();
    List<Device> devices = getAllDevices(enterpriseId, userId);

    // Batch all calls to get installs on all user devices.
    gatherAllInstalls(enterpriseId, userId, devices);

    for (String entry : installList) {
      // Do something.
      System.out.println(entry);
    }
  }

  private List<Device> getAllDevices(String enterpriseId, String userId) throws IOException {
    DevicesListResponse devices = enterprise.devices().list(enterpriseId, userId).execute();
    return devices.getDevice();
  }

  private void gatherAllInstalls(String enterpriseId, String userId, List<Device> devices)
      throws IOException {
    BatchRequest batchRequest = enterprise.batch();
    for (Device device : devices) {
      Installs.List list = enterprise
          .installs().list(enterpriseId, userId, device.getAndroidId());
      // Each callback can take the specifics of the associated request in its constructor.
      list.queue(batchRequest, new InstallsCallback(device.getAndroidId()));
    }
    // Executes all the queued requests and their callbacks, single-threaded.
    batchRequest.execute();
  }

  private class InstallsCallback extends JsonBatchCallback<InstallsListResponse> {
    private final String androidId;

    InstallsCallback(String androidId) {
      this.androidId = androidId;
    }

    @Override
    public void onSuccess(InstallsListResponse response, HttpHeaders responseHeaders) {
      for (Install install : response.getInstall()) {
        installList.add(androidId + "," + install.getProductId());
      }
    }

    @Override
    public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
      throw new RuntimeException("Error fetching a device");
    }
  }

  private AndroidEnterprise createAndroidEnterprise(String jsonKeyPath) throws IOException {
    HttpTransport httpTransport = new NetHttpTransport();
    JsonFactory jsonFactory = new JacksonFactory();

    InputStream is = new BufferedInputStream(new FileInputStream(jsonKeyPath));
    final Credential credential = GoogleCredential.fromStream(is, httpTransport, jsonFactory)
        .createScoped(AndroidEnterpriseScopes.all());

    HttpRequestInitializer httpRequestInitializer = new HttpRequestInitializer() {
      @Override
      public void initialize(HttpRequest request) throws IOException {
        credential.initialize(request);
      }
    };
    return new AndroidEnterprise.Builder(httpTransport, jsonFactory, httpRequestInitializer)
        .build();
  }
}