tutorial

13 Implementasi Unary RPC

Pada tahun-tahun belakangan ini, konsep Remote Procedure Call (RPC) kian populer dalam pengembangan backend services. Salah satu pattern yang paling sederhana tapi sering dipakai adalah Unary RPC, di mana klien mengirim satu permintaan dan server mengembalikan satu respons. Di artikel ini, saya akan membahas konsep Unary RPC dan bagaimana mengimplementasikannya menggunakan gRPC di lingkungan Go (Golang). Mari kita berangkat dari teori, praktik, dan best practice dunia nyata.


Apa itu Unary RPC?

Sebelum masuk ke kode, kita perlu memahami konsep dasarnya. Unary RPC adalah model komunikasi satu-ke-satu antara klien dan server:

  • Single request –> Single response

Ilustrasi komunikasinya sangat mirip seperti fungsi biasa di dalam bahasa pemrograman, namun fungsi tersebut berjalan di server lain.

Alur Komunikasi Unary RPC

sequenceDiagram
    participant Client
    participant Server
    Client->>Server: Request (Data)
    Server-->>Client: Response (Data)

Studi Kasus: Service Pengelolaan Buku

Agar lebih nyata, kita akan buat simulasi sistem pengelolaan buku yang sederhana. Klien akan mengirim permintaan untuk mendapatkan informasi buku berdasarkan IDnya, dan server merespons dengan detail buku tersebut.


Membuat Definisi Protobuf

Kunci utama RPC di gRPC adalah file .proto yang mendefinisikan kontrak antar service.

// book.proto
syntax = "proto3";

package bookservice;

// Request
message GetBookRequest {
  string id = 1;
}

// Response
message Book {
  string id = 1;
  string title = 2;
  string author = 3;
  int32  year = 4;
}

// Service
service BookService {
  rpc GetBook (GetBookRequest) returns (Book);
}

Setelah membuat file ini, generate kode stub dengan perintah berikut:

protoc --go_out=. --go-grpc_out=. book.proto

Implementasi Server Unary RPC

Mari kita implementasikan service handler di Golang.

Struktur Dummy Database

// book_server.go
var books = map[string]*bookservice.Book{
    "1": &bookservice.Book{Id: "1", Title: "Go Programming", Author: "John Doe", Year: 2021},
    "2": &bookservice.Book{Id: "2", Title: "Distributed Systems", Author: "Jane Roe", Year: 2020},
}

Handler RPC - GetBook

type server struct {
  bookservice.UnimplementedBookServiceServer
}

func (s *server) GetBook(
    ctx context.Context,
    req *bookservice.GetBookRequest,
) (*bookservice.Book, error) {
    book, ok := books[req.Id]
    if !ok {
        return nil, status.Error(codes.NotFound, "book not found")
    }
    return book, nil
}

Main server

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    grpcServer := grpc.NewServer()
    bookservice.RegisterBookServiceServer(grpcServer, &server{})

    log.Println("Server running on port :50051")
    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}

Implementasi Client Unary RPC

Mari simulasi klien yang melakukan request ke server menggunakan ID buku tertentu.

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    client := bookservice.NewBookServiceClient(conn)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
    defer cancel()

    bookID := "1"
    res, err := client.GetBook(ctx, &bookservice.GetBookRequest{Id: bookID})
    if err != nil {
        log.Fatalf("Error: %v", err)
    }

    fmt.Printf("Book: %+v\n", res)
}

Simulasi: Request & Response

Mari kita lihat bagaimana komunikasi terjadi.

LangkahDariKeData
Mengirim permintaan bukuClientServer{id: "1"}
Mencari bukuServer (db)InternalLookup berdasarkan ID
Mengirim responsServerClient{id: "1", title: "Go Programming", ...}


Alur Komunikasi Unggulan

Dengan unary RPC, alurnya simpel. Berikut diagram alur request-nya:

flowchart TD
    A[Client Kirim Request] --> B{Server Terima}
    B -- Buku Ada --> C[Server Kirim Data Buku]
    B -- Buku Tidak Ada --> D[Server Kirim Error]
    C & D --> E[Client Terima Respons]

Design ini sangat efisien untuk operasi yang memang hanya membutuhkan satu data dengan satu request.


Perbandingan dengan RPC Lain

Agar lebih jelas, berikut tabel perbandingan model komunikasi di gRPC:

Tipe RPCDariKeFlow
UnaryClientServerSatu request, satu response
Server StreamingClientServerSatu request, stream response
Client StreamingClientServerStream request, satu response
Bidirectional StreamingClientServerStream request, stream response


Manfaat dan Best Practice Unary RPC

Kelebihan

  • Sederhana – Mirip pemakaian fungsi biasa.
  • Cepat – Overhead sedikit, tidak ada stream.
  • Cocok untuk operasi CRUD simple, auth, lookup data, dsb.

Best Practice

  1. Validasi Data — Validasi permintaan di server sebelum proses data.
  2. Timeout — Gunakan context timeout di client untuk menghindari hang.
  3. Error Handling — Kirim error message yang jelas dari server ke client.
  4. Versioning — Pertimbangkan versioning API sejak awal.

Kesimpulan

Unary RPC adalah pattern yang sangat powerful sekaligus sederhana untuk microservices. Di Go, dengan gRPC kita bisa mengimplementasikannya dengan sangat efisien dan maintainable. Pattern ini cocok untuk berbagai use case, terutama operasi pemanggilan remote yang satu-permintaan-satu-jawaban.

Selamat bereksperimen dengan unary RPC di service kamu! Jika kamu punya pertanyaan atau ingin berdiskusi lebih dalam, jangan ragu tinggalkan komentar di bawah.

comments powered by Disqus

Topik Terhangat

programming
170
tips-and-trick
43
tutorial
36
jaringan
28
hardware
11
linux
4
kubernetes
1