Anotasi dan sintaksis Framework Cloud Endpoints

Anotasi Endpoints Frameworks menjelaskan konfigurasi, metode, parameter, dan detail penting lainnya yang menentukan properti dan perilaku endpoint API.

Lihat Menulis dan menganotasi kode untuk mengetahui informasi tentang cara menambahkan anotasi menggunakan project Maven. Artefak Maven App Engine Cloud Endpoints disediakan untuk membuat dan membangun API backend, serta membuat library klien dari API tersebut.

Anotasi yang menentukan konfigurasi dan perilaku di seluruh API (memengaruhi semua class yang diekspos di API dan semua metode yang diekspos) adalah @Api. Semua metode publik, non-statis, non-jembatan dari class yang dianotasi dengan @Api diekspos di API publik.

Jika memerlukan konfigurasi API khusus untuk metode tertentu, Anda dapat secara opsional menggunakan @ApiMethod untuk menetapkan konfigurasi berdasarkan per metode. Anda mengonfigurasi anotasi ini dengan menetapkan berbagai atribut, seperti yang ditunjukkan dalam tabel berikut.

@Api: Anotasi cakupan API

Anotasi @Api mengonfigurasi seluruh API, dan berlaku untuk semua metode publik suatu class kecuali jika diganti oleh @ApiMethod.

Untuk mengganti anotasi @Api tertentu untuk class tertentu dalam API, lihat @ApiClass dan @ApiReference.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import com.google.api.server.spi.config.Api;

Atribut

Atribut @Api Deskripsi Contoh
audiences Wajib diisi jika API Anda memerlukan autentikasi dan jika Anda mendukung klien Android. Untuk mengetahui informasi selengkapnya, lihat ID klien dan audiens. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
apiKeyRequired Opsional. Digunakan untuk membatasi akses ke permintaan yang menyediakan kunci API. apiKeyRequired = AnnotationBoolean.TRUE
authenticators Wajib diisi jika API Anda melakukan autentikasi menggunakan Firebase, Auth0, atau akun layanan. Atribut ini tidak diperlukan jika API Anda melakukan autentikasi menggunakan token ID Google. Anda dapat menyetel ini di tingkat API atau di tingkat masing-masing metode. Tetapkan ke {EspAuthenticator.class}, atau Anda dapat menulis autentikator kustom Anda sendiri, seperti yang dijelaskan dalam Autentikator Antarmuka. authenticators = {EspAuthenticator.class}
backendRoot Tidak digunakan lagi. Untuk menayangkan API dari jalur yang berbeda, di file web.xml, ubah url-pattern di bagian EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
canonicalName Digunakan untuk menentukan nama yang berbeda atau lebih mudah dibaca untuk API di library klien. Nama ini digunakan untuk membuat nama di library klien; backend API terus menggunakan nilai yang ditentukan dalam properti name.

Misalnya, jika API Anda memiliki name yang ditetapkan ke dfaanalytics, Anda dapat menggunakan properti ini untuk menentukan nama kanonis DFA Group Analytics; class klien yang dibuat kemudian akan berisi nama DfaGroupAnalytics.

Anda harus menyertakan spasi yang relevan di antara nama; spasi ini akan digantikan dengan huruf camel case atau garis bawah yang sesuai.
canonicalName = "DFA Analytics:"n
clientIds Wajib diisi jika API Anda menggunakan autentikasi. Daftar ID klien untuk klien yang diizinkan meminta token. Untuk mengetahui informasi selengkapnya, lihat ID klien dan audiens. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
defaultVersion Menentukan apakah versi default digunakan jika tidak ada yang diberikan dalam atribut version. defaultVersion = AnnotationBoolean.TRUE
description Deskripsi singkat API. Hal ini diekspos di layanan penemuan untuk mendeskripsikan API Anda, dan secara opsional juga dapat digunakan untuk membuat dokumentasi. description = "Sample API for a simple game"
documentationLink URL tempat pengguna dapat menemukan dokumentasi tentang versi API ini. Hal ini ditampilkan dalam sorotan "Pelajari Lebih Lanjut" API Explorer di bagian atas halaman API Explorer agar pengguna dapat mempelajari layanan Anda. documentationLink = "http://link_to/docs"
issuers Konfigurasi penerbit JWT kustom. issuers = { @ApiIssuer(name = "auth0", issuer = "https://test.auth0.com/authorize", jwksUri = "https://test.auth0.com/.well-known/jwks.json") }
issuerAudiences Audiens untuk masing-masing penerbit. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
limitDefinitions Opsional. Digunakan untuk menentukan kuota untuk API Anda. Lihat @ApiLimitMetric. limitDefinitions = { @ApiLimitMetric(name = "read-requests", displayName = "Read requests", limit = 1000)}
name Nama API, yang digunakan sebagai awalan untuk semua metode dan jalur API. Nilai name:
  • Harus dimulai dengan huruf kecil
  • Harus cocok dengan ekspresi reguler [a-z]+[A-Za-z0-9]*
Jika Anda tidak menentukan name, myapi default akan digunakan.
name = "foosBall"
namespace Mengonfigurasi namespace untuk klien yang dihasilkan. Lihat @ApiNamespace. namespace=@ApiNamespace(ownerDomain="your-company.com", ownerName="YourCo", packagePath="cloud/platform")
root Tidak digunakan lagi. Untuk menayangkan API dari jalur yang berbeda, di file web.xml, ubah url-pattern di bagian EndpointsServlet. <url-pattern>/example-api/*</url-pattern>
scopes Jika tidak diberikan, defaultnya adalah cakupan email (https://www.googleapis.com/auth/userinfo.email), yang diperlukan untuk OAuth. Anda dapat mengganti ini untuk menentukan cakupan OAuth 2.0 lainnya jika diinginkan. Namun, jika Anda menentukan lebih dari satu cakupan, perhatikan bahwa pemeriksaan cakupan akan berhasil jika token dibuat untuk cakupan mana pun yang ditentukan. Untuk mewajibkan beberapa cakupan, satu String harus ditentukan dengan spasi di antara setiap cakupan. Untuk mengganti cakupan yang ditentukan di sini untuk metode API tertentu, tentukan cakupan yang berbeda dalam anotasi @ApiMethod. scopes = {"ss0", "ss1 and_ss2"}
title Teks yang ditampilkan di API Explorer sebagai judul API Anda, dan diekspos di layanan penemuan dan direktori. title = "My Backend API"
transformers Menentukan daftar transformer kustom. Perhatikan bahwa ada anotasi alternatif (@ApiTransformer) yang lebih disukai. Atribut ini diganti oleh @ApiTransformer. transformers = {BazTransformer.class}
version Menentukan versi endpoint Anda. Jika Anda tidak menyediakannya, v1 default akan digunakan. version = "v2"

Anotasi Sample@Api

Anotasi ini ditempatkan sebelum definisi class:

/** An endpoint class we are exposing. */
@Api(name = "myApi",
    version = "v1",
    namespace = @ApiNamespace(ownerDomain = "helloworld.example.com",
        ownerName = "helloworld.example.com",
        packagePath = ""))

ID klien dan audiens

Untuk autentikasi OAuth2, token OAuth2 dikeluarkan untuk ID klien tertentu, yang berarti Anda dapat menggunakan ID klien untuk membatasi akses ke API Anda. Saat mendaftarkan aplikasi Android di konsol Google Cloud , Anda akan membuat client ID untuk aplikasi tersebut. ID klien ini adalah ID yang meminta token OAuth2 dari Google untuk tujuan autentikasi. Jika API backend dilindungi oleh autentikasi, token akses OAuth2 akan dikirim dan dibuka oleh Endpoints, ID klien akan diekstrak dari token, lalu ID tersebut akan dibandingkan dengan daftar ID klien yang dapat diterima yang dideklarasikan backend (daftar clientIds).

Jika ingin API Endpoints Anda mengautentikasi pemanggil, Anda harus memberikan daftar clientIds yang diizinkan untuk meminta token. Daftar ini harus terdiri dari semua ID klien yang telah Anda peroleh melalui Google Cloud console untuk klien web atau Android Anda. Artinya, klien harus diketahui pada waktu pembuatan API. Jika Anda menentukan daftar kosong, {}, maka tidak ada klien yang dapat mengakses metode yang dilindungi oleh Auth.

Jika Anda menggunakan atribut clientIds dan ingin menguji panggilan yang diautentikasi ke API menggunakan Google API Explorer, Anda harus memberikan client ID-nya dalam daftar clientIds: nilai yang akan digunakan adalah com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID.

Tentang audiens

Daftar clientIds melindungi API backend dari klien yang tidak sah. Namun, perlindungan lebih lanjut diperlukan untuk melindungi klien, sehingga token autentikasi mereka hanya berfungsi untuk API backend yang dimaksud. Untuk klien Android, mekanisme ini adalah atribut audiences, tempat Anda menentukan client ID backend API.

Perhatikan bahwa saat Anda membuat project konsol, ID klien default akan otomatis dibuat dan diberi nama untuk digunakan oleh project. Google Cloud Saat Anda mengupload backend API ke App Engine, API tersebut akan menggunakan client ID tersebut. Ini adalah client ID web yang disebutkan dalam autentikasi API.

@ApiMethod: Anotasi cakupan metode

Anotasi @ApiMethod digunakan untuk memberikan konfigurasi API yang berbeda dari default yang diberikan oleh anotasi @Api atau @ApiClass. Perhatikan bahwa hal ini bersifat opsional: semua metode publik, non-statis, dan non-jembatan dalam class dengan anotasi @Api diekspos di API, baik metode tersebut memiliki anotasi @ApiMethod atau tidak.

Atribut dalam anotasi ini memungkinkan Anda mengonfigurasi detail satu metode API. Jika atribut yang sama ditentukan dalam @Api dan @ApiMethod, @ApiMethod akan menggantikan.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import com.google.api.server.spi.config.AnnotationBoolean;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;

Atribut

Atribut @ApiMethod Deskripsi Contoh
apiKeyRequired Opsional. Digunakan untuk membatasi akses ke permintaan yang menyediakan Kunci API. apiKeyRequired = AnnotationBoolean.TRUE
audiences Berikan ini jika Anda ingin mengganti konfigurasi di @API. Untuk mengetahui informasi selengkapnya, lihat ID klien dan audiens. audiences = {"1-web-apps.apps.googleusercontent.com", "2-web-apps.apps.googleusercontent.com"}
authenticators Wajib diisi jika API Anda melakukan autentikasi menggunakan Firebase, Auth0, atau akun layanan, dan Anda belum menetapkan atribut ini di tingkat API. Atribut ini tidak diperlukan jika API Anda melakukan autentikasi menggunakan token ID Google. Tetapkan ke {EspAuthenticator.class}, atau Anda dapat menulis autentikator kustom Anda sendiri, seperti yang dijelaskan dalam Authenticator Antarmuka authenticators = {EspAuthenticator.class}
clientIds Daftar ID klien untuk klien yang diizinkan meminta token. Wajib diisi jika API Anda menggunakan autentikasi. clientIds = {"1-web-apps.apps.googleusercontent.com", "2-android-apps.apps.googleusercontent.com"}
httpMethod Metode HTTP yang akan digunakan. Jika Anda tidak menyetelnya, default akan dipilih berdasarkan nama metode. httpMethod = HttpMethod.GET
issuerAudiences Berikan ini jika Anda ingin mengganti konfigurasi di @Api. issuerAudiences = { @ApiIssuerAudience(name = "auth0", audiences = {"aud-1.auth0.com", "aud-2.auth0.com"}) }
metricCosts Opsional. Menunjukkan bahwa metode memiliki batas kuota. Anda menetapkan anotasi @ApiMetricCost ke metricCosts. Anda juga harus menentukan atribut limitDefinitions untuk menentukan kuota dalam anotasi @Api. Anotasi @ApiMetricCost menggunakan atribut berikut:
  • name: Nama yang Anda tentukan dalam anotasi ApiLimitMetric.
  • biaya: Integer yang menentukan biaya untuk setiap permintaan. Biaya memungkinkan metode untuk menggunakan kuota yang sama dengan tarif yang berbeda. Misalnya, jika kuota memiliki batas 1.000 dan biaya 1, aplikasi yang memanggil dapat membuat 1.000 permintaan per menit sebelum melampaui batas. Dengan biaya 2 untuk kuota yang sama, aplikasi yang memanggil hanya dapat membuat 500 permintaan per menit sebelum melampaui batas.
metricCosts = { @ApiMetricCost(name = read-requests", cost = 1) }
name Nama untuk metode ini di library klien yang dihasilkan. Ini otomatis diberi awalan dengan nama API Anda untuk membuat nama unik bagi metode tersebut. Nilai name:
  • Harus dimulai dengan huruf kecil
  • Harus cocok dengan ekspresi reguler [a-z]+[A-Za-z0-9]*
Jika Anda tidak menentukan name, myapi default akan digunakan.
name = "foosBall.list"
path Jalur URI yang akan digunakan untuk mengakses metode ini. Jika Anda tidak menyetelnya, jalur default akan digunakan berdasarkan nama metode Java. Jika Anda berencana untuk menambahkan pengelolaan API, jangan sertakan garis miring di akhir jalur. path = "foos"
scopes Tentukan satu atau beberapa cakupan OAuth 2.0, yang salah satunya diperlukan untuk memanggil metode ini. Jika Anda menetapkan scopes untuk suatu metode, setelan tersebut akan menggantikan setelan di anotasi @Api. Jika Anda menentukan lebih dari satu cakupan, perhatikan bahwa pemeriksaan cakupan akan berhasil jika token dibuat untuk cakupan mana pun yang ditentukan. Untuk mewajibkan beberapa cakupan, tentukan satu String dengan spasi di antara setiap cakupan. scopes = {"ss0", "ss1 and_ss2"}

Contoh anotasi @ApiMethod

Anotasi ini ditempatkan sebelum definisi metode di dalam class:

/** A simple endpoint method that takes a name and says Hi back. */
@ApiMethod(
    name = "sayHiUser",
    httpMethod = ApiMethod.HttpMethod.GET)
public MyBean sayHiUser(@Named("name") String name, User user)
    throws OAuthRequestException, IOException {
  MyBean response = new MyBean();
  response.setData("Hi, " + name + "(" + user.getEmail() + ")");

  return response;
}

Metode yang menggunakan entity sebagai parameter harus menggunakan HttpMethod.POST (untuk operasi penyisipan) atau HttpMethod.PUT (untuk operasi pembaruan):

@ApiMethod(
    name = "mybean.insert",
    path = "mybean",
    httpMethod = ApiMethod.HttpMethod.POST
)
public void insertFoo(MyBean foo) {
}

@Named

Anotasi @Named diperlukan untuk semua parameter jenis non-entitas yang diteruskan ke metode sisi server. Anotasi ini menunjukkan nama parameter dalam permintaan yang disisipkan di sini. Parameter yang tidak dianotasi dengan @Named disisipkan dengan seluruh objek permintaan.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import javax.inject.Named;

Contoh ini menunjukkan penggunaan @Named:

/** A simple endpoint method that takes a name and says Hi back. */
@ApiMethod(name = "sayHi")
public MyBean sayHi(@Named("name") String name) {
  MyBean response = new MyBean();
  response.setData("Hi, " + name);

  return response;
}

dengan @Named menentukan bahwa hanya parameter id yang disisipkan dalam permintaan.

@ApiLimitMetric

Bagian ini menjelaskan anotasi yang diperlukan untuk menentukan kuota untuk API Anda. Lihat Mengonfigurasi kuota untuk semua langkah yang diperlukan untuk menyiapkan kuota.

Anda menetapkan anotasi @ApiLimitMetric ke atribut limitDefinitions dari anotasi cakupan API. Anda juga harus menambahkan @ApiMetricCost ke anotasi @ApiMethod untuk setiap metode yang ingin Anda terapkan kuotanya.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import com.google.api.server.spi.config.ApiLimitMetric;

Atribut

Atribut @ApiLimitMetric

Deskripsi
nama Nama untuk kuota. Biasanya, ini adalah jenis permintaan (misalnya, "read-requests" atau "write-requests") yang secara unik mengidentifikasi kuota
displayName Teks yang ditampilkan untuk mengidentifikasi kuota di tab Quotas di halaman Endpoints > Services di konsol Google Cloud . Teks ini juga ditampilkan kepada konsumen API Anda di halaman Kuota IAM & admin dan API & layanan. Nama tampilan harus maksimal 40 karakter.
Untuk tujuan keterbacaan, teks "per menit per project" secara otomatis ditambahkan ke nama tampilan di halaman Kuota.
Untuk menjaga konsistensi dengan nama tampilan layanan Google yang tercantum di halaman Kouta yang dilihat konsumen API Anda, sebaiknya gunakan nama tampilan berikut:
  • Gunakan "Permintaan" jika Anda hanya memiliki satu metrik.
  • Jika Anda memiliki beberapa metrik, setiap metrik harus menjelaskan jenis permintaan dan berisi kata "permintaan" (misalnya, "Permintaan baca" atau "Permintaan tulis").
  • Gunakan "unit kuota" dan bukan "permintaan" jika biaya untuk kuota ini lebih besar dari 1.
batas Nilai bilangan bulat yang merupakan jumlah maksimum permintaan per menit per project konsumen untuk kuota.

Contoh

limitDefinitions = {
      @ApiLimitMetric(
        name = "read-requests",
        displayName = "Read requests",
        limit = 1000),
      @ApiLimitMetric(
        name = "write-requests",
        displayName = "Write requests",
        limit = 50),
    }

@ApiNamespace

Anotasi @ApiNamespace menyebabkan library klien yang dihasilkan memiliki namespace yang Anda tentukan, bukan namespace default yang dibuat selama pembuatan library klien.

Secara default, jika Anda tidak menggunakan anotasi ini, namespace yang digunakan adalah kebalikan dari your-project-id.appspot.com. Artinya, jalur paketnya adalah com.appspot.your-project-id.yourApi.

Anda dapat mengubah namespace default dengan memberikan anotasi @ApiNamespace dalam anotasi @Api:

/** An endpoint class we are exposing. */
@Api(name = "myApi",
    version = "v1",
    namespace = @ApiNamespace(ownerDomain = "helloworld.example.com",
        ownerName = "helloworld.example.com",
        packagePath = ""))

Tetapkan atribut ownerDomain ke domain perusahaan Anda sendiri dan ownerName ke nama perusahaan Anda, misalnya, your-company.com. Kebalikan dari ownerDomain digunakan untuk jalur paket: com.your-company.yourApi.

Anda dapat secara opsional menggunakan atribut packagePath untuk memberikan cakupan lebih lanjut. Misalnya, dengan menyetel packagePath ke cloud, jalur paket yang digunakan di library klien adalah com.your-company.cloud.yourApi. Anda dapat menambahkan lebih banyak nilai ke jalur paket dengan memberikan pembatas /: packagePath="cloud/platform".

@Nullable

Anotasi ini menunjukkan bahwa parameter metode bersifat opsional (dan oleh karena itu merupakan parameter kueri). @Nullable hanya dapat digunakan dengan parameter @Named.

@ApiClass

Di API multikelas, Anda dapat menggunakan @ApiClass untuk menentukan properti yang berbeda untuk class tertentu, dengan mengganti properti yang setara dalam konfigurasi @Api. Lihat Menggunakan @ApiClass untuk properti yang dapat berbeda antar-class untuk deskripsi lengkap anotasi ini.

@ApiReference

Dalam API multikelas, Anda dapat menggunakan @ApiReference untuk menyediakan metode alternatif pewarisan anotasi. Lihat Menggunakan pewarisan @ApiReference untuk mengetahui deskripsi lengkap tentang anotasi ini.

@ApiResourceProperty

@ApiResourceProperty memberikan kontrol atas cara properti resource diekspos di API. Anda dapat menggunakannya pada getter atau setter properti untuk menghapus properti dari resource API. Anda juga dapat menggunakannya di kolom itu sendiri, jika kolom bersifat pribadi, untuk mengeksposnya di API. Anda juga dapat menggunakan anotasi ini untuk mengubah nama properti dalam resource API.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import com.google.api.server.spi.config.ApiResourceProperty;
import com.google.api.server.spi.config.AnnotationBoolean;

Atribut

Atribut @ApiResourceProperty Deskripsi Contoh
ignored Jika disetel ke AnnotationBoolean.TRUE, properti akan dihilangkan. Jika tidak ditentukan atau disetel ke AnnotationBoolean.FALSE, properti tidak akan dihapus. @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
name Jika diberikan, properti ini menentukan nama properti yang akan diekspos di API. @ApiResourceProperty(name = "baz")

Contoh class dengan @ApiResourceProperty

Cuplikan berikut menunjukkan class dengan pengambil properti yang dianotasikan dengan @ApiResourceProperty:


class Resp {
  private String foobar = "foobar";
  private String bin = "bin";

  @ApiResourceProperty
  private String visible = "nothidden";

  @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
  public String getBin() {
    return bin;
  }

  public void setBin(String bin) {
    this.bin = bin;
  }

  @ApiResourceProperty(name = "baz")
  public String getFoobar() {
    return foobar;
  }

  public void setFoobar(String foobar) {
    this.foobar = foobar;
  }
}

public Resp getResp() {
  return new Resp();
}

Pada cuplikan kode sebelumnya, @ApiResourceProperty diterapkan ke pengambil getBin untuk properti bin, dengan setelan atribut ignored memberi tahu Endpoints Frameworks untuk menghapus properti ini di resource API.

@ApiResourceProperty juga diterapkan ke kolom pribadi visible, yang tidak memiliki getter atau setter. Menggunakan anotasi ini akan mengekspos kolom ini sebagai properti di resource API.

Dalam cuplikan yang sama, @ApiResourceProperty juga diterapkan ke getter yang berbeda, getFoobar, yang menampilkan nilai properti untuk properti foobar. Atribut name dalam anotasi ini memberi tahu Endpoints Frameworks untuk mengubah nama properti di resource API. Nilai properti itu sendiri tidak berubah.

Dalam cuplikan contoh sebelumnya, representasi JSON objek Resp terlihat seperti ini:

{"baz": "foobar", "visible": "nothidden"}

@ApiTransformer

Anotasi @ApiTransformer menyesuaikan cara jenis diekspos di Endpoints melalui transformasi ke dan dari jenis lain. (Transformer yang ditentukan harus berupa implementasi com.google.api.server.spi.config.Transformer.)

Menggunakan anotasi @ApiTransformer pada class adalah cara yang lebih disukai untuk menentukan transformer. Namun, Anda dapat menentukan transformer kustom di atribut transformer dari anotasi @Api.

Impor yang diperlukan

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

import com.google.api.server.spi.config.ApiTransformer;

Contoh class dengan @ApiTransformer

Cuplikan berikut menunjukkan class yang dianotasikan dengan @ApiTransformer:


@ApiTransformer(BarTransformer.class)
public class Bar {
  private final int x;
  private final int y;

  public Bar(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public int getX() {
    return x;
  }

  public int getY() {
    return y;
  }
}

Class ini diubah oleh class BarTransformer.

Contoh class transformer Endpoints

Cuplikan berikut menunjukkan contoh class transformer bernama BarTransformer. Ini adalah transformer yang direferensikan oleh @ApiTransformer dalam cuplikan sebelumnya:

public class BarTransformer implements Transformer<Bar, String> {
  public String transformTo(Bar in) {
    return in.getX() + "," + in.getY();
  }

  public Bar transformFrom(String in) {
    String[] xy = in.split(",");
    return new Bar(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]));
  }
}

Dengan asumsi ada objek dengan properti bar berjenis Bar, tanpa transformer sebelumnya, objek tersebut ditampilkan sebagai:

{"bar": {"x": 1, "y": 2}}

Dengan transformer, objek direpresentasikan sebagai:

{"bar": "1,2"}