Belajar gRPC - Menulis API gRPC Pertama dengan Protocol Buffers
Episode 3 of 19

Belajar gRPC - Menulis API gRPC Pertama dengan Protocol Buffers

Episode ini mengajarkan menulis kontrak gRPC: struktur lengkap file .proto, tipe data protobuf v3 modern seperti enum, oneof, map, dan repeated, hingga cara mendeklarasikan empat pola RPC — unary, server streaming, client streaming, dan bidirectional.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Semua kehebatan gRPC bermuara pada satu file: .proto. File ini adalah kontrak yang dibaca manusia, compiler, client, dan server sekaligus. Di episode 3 kalian akan belajar menulis kontrak tersebut dengan benar — bukan sekadar contoh sederhana, tapi struktur yang siap untuk service nyata.

Kita akan membahas tiga lapisan kontrak: struktur file (package, imports, options), tipe data protobuf v3 (scalar, enum, oneof, map, repeated), dan definisi service dengan keempat pola RPC. Di akhir episode, kalian punya satu file .proto lengkap yang siap di-generate di episode 4.

Struktur File .proto

Package, Imports, dan Options

Bagian paling atas file .proto berisi tiga deklarasi penting:

  • syntax = "proto3": memilih bahasa skema protobuf versi 3.
  • package: namespace yang menentukan nama jenis di kode hasil generate, contohnya catalog.v1.
  • import: menyertakan file lain, misalnya google/protobuf/timestamp.proto untuk tipe waktu.
Kerangka file product.proto
syntax = "proto3";
 
package catalog.v1;
 
import "google/protobuf/timestamp.proto";
 
option go_package = "learn-grpc/gen/catalog/v1;catalogv1";
 
message Product {
  string id = 1;
  string name = 2;
  double price = 3;
}

Option go_package menentukan lokasi output di Go; untuk bahasa lain, konvensinya berbeda-beda mengikuti plugin. Penulisan option go_package ini wajib untuk plugin Go.

Aturan Penomoran Field

Setiap field memakai nomor unik dalam satu message: string id = 1 berarti field bernomor 1. Nomor ini adalah bagian dari wire format, jadi jangan pernah mengubah makna nomor yang sudah dipakai. Nomor 1 sampai 15 memakai satu byte saja — berikan nomor kecil untuk field yang paling sering diakses.

Tipe Data Protobuf v3

Scalar Types

Protobuf v3 menyediakan tipe scalar yang dipetakan ke tipe native bahasa: int32, int64, uint32, float, double, bool, string, dan bytes. Perhatikan bahwa semua field v3 bersifat optional: nilai default seperti 0 dan string kosong otomatis digunakan bila field tidak diisi.

Enum, oneof, dan map

Tiga konstruksi ini menyelesaikan sebagian besar masalah pemodelan data:

enum, oneof, dan map
message Product {
  enum Status {
    STATUS_UNSPECIFIED = 0;
    STATUS_ACTIVE = 1;
    STATUS_ARCHIVED = 2;
  }
  Status status = 4;
 
  oneof dimension {
    int32 weight_grams = 5;
    int32 volume_ml = 6;
  }
 
  map<string, string> attributes = 7;
}
  • enum membatasi nilai yang valid; nilai pertama wajib bernilai 0.
  • oneof memastikan hanya satu field yang terisi; Product punya weight_grams atau volume_ml.
  • map menyimpan pasangan key-value, contohnya atribut bebas seperti color dan material.

repeated untuk List

Untuk daftar nilai, gunakan repeated — setara list atau array di bahasa pemrograman:

Field repeated
message Order {
  repeated string product_ids = 1;
  int32 total = 2;
}

repeated string product_ids = 1 bisa menyimpan nol atau banyak ID. Untuk tipe scalar, protobuf mengaktifkan packed encoding secara otomatis sehingga elemen list dikirim sangat ringkas.

Mendefinisikan Service

Empat Pola RPC

Inti kontrak adalah blok service. Empat pola komunikasi didukung penuh oleh protobuf:

  • Unary: satu request, satu response — seperti function call biasa.
  • Server streaming: client kirim satu request, server kirim banyak response.
  • Client streaming: client kirim banyak request, server kirim satu response.
  • Bidirectional streaming: kedua sisi mengirim banyak pesan secara bersamaan.
Keempat pola RPC
service ProductService {
  rpc GetProduct(ProductId) returns (Product);
  rpc ListProducts(ProductQuery) returns (stream Product);
  rpc AddBulk(stream Product) returns (BulkResult);
  rpc Search(stream SearchTerm) returns (stream Product);
}

Baca deklarasi di atas: rpc GetProduct(ProductId) returns (Product) adalah unary, ListProducts memakai kata kunci stream di response, AddBulk memakai stream di request, dan Search memakai stream di keduanya.

Message untuk Request dan Response

Setiap method perlu tipe request dan response sendiri. Jangan memakai ulang message untuk tujuan berbeda — pasangan request-response yang terpisah memudahkan evoluasi skema tanpa saling merusak:

Request dan response khusus
message ProductId {
  string id = 1;
}
 
message ProductQuery {
  string keyword = 1;
  int32 limit = 2;
}
 
message BulkResult {
  int32 added_count = 1;
}

Konvensi Penulisan yang Baik

Beberapa praktik yang membuat kontrak kalian sehat dalam jangka panjang:

  • Camel case untuk field (product_id) dan Pascal case untuk message (ProductQuery).
  • Awalan status enum dengan nama enum (STATUS_ACTIVE) agar kode hasil generate tidak ambigu.
  • Komentar // di atas setiap field dan method sebagai dokumentasi otomatis.
  • Satu service per file bila domainnya besar, dan hindari satu file raksasa.

Kontrak yang rapi akan membuat kode hasil generate mudah dibaca oleh seluruh tim lintas bahasa.

Penutup

Inti yang harus dibawa pulang:

  • .proto adalah kontrak tunggal yang dibaca manusia, compiler, client, dan server.
  • package, import, dan option go_package membentuk kerangka file yang valid.
  • Gunakan enum, oneof, map, dan repeated untuk memodelkan domain dengan tepat.
  • Keempat pola RPC dideklarasikan dengan kata kunci stream pada posisi yang sesuai.
  • Nomor field tidak boleh berubah setelah dipakai, karena bagian dari wire format.
  • Setiap method punya message request dan response khusus.

Di episode 4 selanjutnya kalian akan membangkitkan kode dan menjalankan server-client pertama: instalasi plugin, perintah protoc untuk Go, implementasi server sederhana, implementasi client sederhana, dan testing lokal dengan request-response nyata. File .proto yang barusan kalian tulis akan hidup sebagai kode yang bisa dijalankan.