tutorial

48 Custom Options di Protobuf

Jika kamu sudah pernah berurusan dengan Protobuf (Protocol Buffers) dari Google, pasti tahu betapa powerful-nya tools serialization satu ini untuk aplikasi lintas platform dan lintas bahasa. Tapi tahukah kamu, Protobuf tidak hanya tentang mendefinisikan struktur data sederhana? Ada fitur yang sering terlupakan, namun sangat powerful—yakni Custom Options. Kali ini saya akan membedah fitur ini secara mendalam, termasuk contoh kode, simulasi skenario, dan sedikit diagram untuk memperjelas alurnya.


Pengantar Singkat Tentang Protobuf dan Options

Secara default, Protobuf sudah menyediakan banyak sekali options bawaan, misalnya deprecated, packed, dll. Ini digunakan buat menambah metadata tambahan pada field, message, enum, dan sebagainya.

Contoh:

message Person {
  optional string name = 1 [deprecated=true];
}

Kamu bisa set [deprecated=true] untuk menandai field yang sudah tidak sebaiknya digunakan lagi.

Tapi kadang, developer butuh lebih dari sekadar metadata standar. Bagaimana kalau kita ingin simpan informasi khusus, misalnya: “field tertentu ini harus di enkripsi di level aplikasi”, atau menandai “field ini harus muncul di dokumentasi Rest API”, dsb. Nah, Custom Options hadir sebagai solusi.


Apa itu Custom Options?

Custom Options memberi kita jalur untuk mendefinisikan metadata baru (custom) pada hampir semua elemen pada .proto: fields, message, enum, service, method—tergantung kebutuhan. Custom options dibuat dengan mendeklarasikan sebuah extension terhadap satu dari beberapa reserved option holder, seperti google.protobuf.FieldOptions.

Mengapa Perlu Custom Options?

  • Tambahan metadata yang bisa diproses di build time maupun runtime.
  • Integrasi dengan tools internal (misal: code generator custom, tools dokumentasi internal, validator, dsb).
  • Otomatisasi proses, misal testing, logging, bahkan control access.

Cara Kerja Custom Options

Untuk memanfaatkan custom options, ada 3 langkah utama:

  1. Buat Definition Custom Option.
  2. Gunakan Custom Option dalam .proto lain.
  3. Akses Custom Option pada build atau runtime.

Mari kita breakdown setiap langkah dengan kode nyata.

1. Buat Definition Custom Option

Custom option didefinisikan dengan menggunakan fitur extension pada .proto, pada pesan khusus dari Google google.protobuf.*Options.

Misal kita mau kasih informasi “field ini harus diekspor ke API” via option api_exported di field level:

// custom_options.proto
import "google/protobuf/descriptor.proto";

extend google.protobuf.FieldOptions {
  optional bool api_exported = 50001;
}

Note: Nomor field placehold “50001” diambil dari range yang direkomendasikan Google ([50000, 536870911]).

2. Gunakan Custom Option di .proto Lain

Setelah extension di-declare, selanjutnya kita import extension tersebut di file .proto yang relevan.

// person.proto
import "custom_options.proto";

message Person {
  string name = 1 [(api_exported) = true];
  int32 age = 2; // tanpa opsi
}

Field name sekarang punya metadata baru: (api_exported) = true.

3. Membaca Custom Options

Untuk membaca custom option, kamu butuh dukungan dari tools/bahasa yang kamu pakai. Library Protobuf Java, Go, C++, Python rata-rata sudah mendukung akses options ini lewat refleksi/protobuf API.

Contoh: Membaca Custom Options di Python

# install protobuf: pip install protobuf
from person_pb2 import Person, DESCRIPTOR
from custom_options_pb2 import api_exported

field = DESCRIPTOR.fields_by_name['name']
if field.GetOptions().Extensions[api_exported]:
    print("Field 'name' is exported to API")

Use Case & Studi Kasus

Use Case 1: Field-level Data Masking

Misal requirement security: “Semua field dengan tag custom mask = true harus otomatis di-masking saat serialization!”

Definisi extension:

// masking.proto
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
  optional bool mask = 50011;
}

Penggunaan:

// customer.proto
import "masking.proto";

message Customer {
  string name = 1;
  string phone = 2 [(mask) = true];
}

Runtime logic (Go-like pseudocode):

for _, field := range proto.MessageFields(customer) {
  if field.Options().GetExtension(mask) == true {
    MaskField(&customer, field)
  }
}

Use Case 2: Dokumentasi Otomatis Endpoints

Dengan custom option, keterangan “Endpoint ini versi beta” bisa langsung dimasukkan ke dalam .proto dan dipakai generator documentation internal.

Definisi extension:

// doc_tag.proto
import "google/protobuf/descriptor.proto";
extend google.protobuf.MethodOptions {
  optional string doc_tag = 50021;
}

Penggunaan:

service UserService {
  rpc GetUser(UserRequest) returns (User) {
    option (doc_tag) = "beta";
  }
}

Nanti tools dokumentasi bisa membedakan mana API yang sudah stabil dan mana yang masih beta.


Visualisasi Proses Kompilasi Protobuf Dengan Custom Options

Mari kita lihat bagaimana custom options flow dari .proto ke hasil akhir lewat diagram mermaid.

graph LR
    A[.proto dengan Custom Option] --> B[protoc compiler]
    B --> C["File hasil compile: *_pb2(.py|.go|.java)"]
    C --> D[Code Generation / Reflection API]
    D --> E[Read/Process Custom Metadata]
  • Node A: Developer menulis .proto dengan custom options.
  • Node B: protoc meng-compile .proto (dengan meng-embed custom extension di descriptor file).
  • Node C: Output adalah kode/descriptor file yang menyimpan info custom options.
  • Node D: Tools atau library membaca descriptor untuk mendeteksi custom options.
  • Node E: Custom tools/proses bisa mengakses, memproses, atau bereaksi berdasarkan value custom options.

Tabel: Jenis-Jenis Tempat Custom Options Diterapkan

Extension TargetContoh OptionUse Case
FieldOptionsmask, api_exportedData masking, API tag
MessageOptionsentity_typeORM, entity registry
ServiceOptionsservice_groupGrouping API
MethodOptionsdoc_tag, deprecatedDoc generator, warning
EnumOptions, EnumValueOptionsdescriptionEnum documentation

Simulasi Build: Step-by-step

Misal kamu punya tiga file: custom_options.proto, person.proto, dan kemudian meng-compile:

protoc --python_out=. custom_options.proto person.proto

Jika ada tool custom (misal validator), pipeline-nya kira-kira:

flowchart LR
    subgraph Developer
    F1[Edit .proto]
    end
    subgraph Build
    F2[protoc compile]
    F3[Custom tool analyze pb2]
    end
    F1 --> F2 --> F3

Limitasi & Catatan Penting

  1. Custom options hanya metadata, tidak mengubah serialization format/binarynya.
  2. Tidak semua code generator/language binding auto expose custom options.
  3. Opsi hanya dibaca via reflection/descriptors.

Kesimpulan

Custom options di Protobuf adalah fitur ajaib namun underrated yang bisa menghemat banyak waktu, menjaga konsistensi, dan memperkaya metadata proses developer. Dengan sedikit setup, kamu bisa membuat ekosistem lebih maintainable dan powerful, khususnya untuk organisasi dengan workflow yang banyak mengandalkan Protobuf.

Jika kamu sedang membangun tooling sendiri, atau ingin meng-enrich data model dan API-mu, jangan lupa review dan explore fitur satu ini.


Punya pengalaman unik pakai custom options? Share di kolom komentar!

comments powered by Disqus