tutorial

  1. Studi Kasus: Aplikasi Todo List berbasis gRPC

91. Studi Kasus: Aplikasi Todo List berbasis gRPC

gRPC telah menjadi salah satu teknologi populer untuk membangun layanan microservices berperforma tinggi dan efisien. Di artikel ini, saya akan membahas studi kasus sederhana: membangun aplikasi Todo List menggunakan gRPC dari nol. Kita akan mengeksplorasi arsitektur, struktur protokol, serta cuplikan kode Go yang dapat langsung diadaptasi untuk kasus nyata.


Mengapa gRPC?

Sebelum masuk ke studi kasus, mari kita sejenak membahas kenapa memilih gRPC:

  • Efisiensi: gRPC menggunakan Protobuf yang lebih ringan dan cepat dibanding JSON/HTTP tradisional.
  • Interoperabilitas: Mendukung banyak bahasa: Go, Java, C#, Python, dsb.
  • Contract-first API: Dengan file .proto, kontrak antara client dan server eksplisit dan strongly-typed.
  • Streaming: Mendukung streaming data dua arah, cocok untuk realtime.

Arsitektur Aplikasi Todo List

Kita akan membuat aplikasi Todo List dengan arsitektur berikut:

  • Client: CLI atau frontend yang mengirim request ke server gRPC.
  • Server: Menangani request, menyimpan tasks dalam in-memory storage sederhana.

Diagram Alur

Mari gambarkan proses menambah dan mendapatkan todo dengan mermaid flowchart:

flowchart TD
    Client-->|AddTodo|gRPC_Server
    gRPC_Server-->|Save data|Storage[In-memory]
    Client-->|GetTodos|gRPC_Server
    gRPC_Server-->|Fetch todos|Storage
    Storage-->|Todos list|gRPC_Server
    gRPC_Server-->|Todos response|Client

1. Mendefinisikan Protobuf

File .proto mendeskripsikan struktur data dan service.

// todo.proto
syntax = "proto3";

package todo;

// Message Type
message TodoItem {
  int32 id = 1;
  string task = 2;
  bool completed = 3;
}

message AddTodoRequest {
  string task = 1;
}

message AddTodoResponse {
  TodoItem item = 1;
}

message GetTodosRequest {}

message GetTodosResponse {
  repeated TodoItem items = 1;
}

// Service
service TodoService {
  rpc AddTodo (AddTodoRequest) returns (AddTodoResponse);
  rpc GetTodos (GetTodosRequest) returns (GetTodosResponse);
}

2. Generate Code dari Proto

Gunakan plugin Protobuf untuk Go:

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

3. Implementasi Server gRPC dengan Golang

Buat file server.go:

package main

import (
    "context"
    "log"
    "net"
    "sync"

    pb "path/to/generated/todo"
    "google.golang.org/grpc"
)

type server struct {
    pb.UnimplementedTodoServiceServer
    todos []pb.TodoItem
    mu    sync.Mutex
    nextID int32
}

func (s *server) AddTodo(ctx context.Context, req *pb.AddTodoRequest) (*pb.AddTodoResponse, error) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.nextID++
    item := pb.TodoItem{
        Id:        s.nextID,
        Task:      req.GetTask(),
        Completed: false,
    }
    s.todos = append(s.todos, item)
    return &pb.AddTodoResponse{Item: &item}, nil
}

func (s *server) GetTodos(ctx context.Context, req *pb.GetTodosRequest) (*pb.GetTodosResponse, error) {
    s.mu.Lock()
    defer s.mu.Unlock()
    // Copy slice untuk keamanan concurrent
    items := make([]*pb.TodoItem, len(s.todos))
    for i, todo := range s.todos {
        copied := todo
        items[i] = &copied
    }
    return &pb.GetTodosResponse{Items: items}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterTodoServiceServer(s, &server{})
    log.Println("gRPC server running at :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

4. Implementasi Client Sederhana

Buat file client.go:

package main

import (
    "context"
    "log"
    "time"

    pb "path/to/generated/todo"
    "google.golang.org/grpc"
)

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

    // Simulasi AddTodo
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.AddTodo(ctx, &pb.AddTodoRequest{Task: "Beli kopi"})
    if err != nil {
        log.Fatalf("could not add: %v", err)
    }
    log.Printf("Added Todo: %v", r.GetItem())

    // Simulasi GetTodos
    resp, err := c.GetTodos(ctx, &pb.GetTodosRequest{})
    if err != nil {
        log.Fatalf("could not get todos: %v", err)
    }
    for _, t := range resp.GetItems() {
        log.Printf("%d: %s [completed: %v]", t.GetId(), t.GetTask(), t.GetCompleted())
    }
}

5. Simulasi Interaksi Client-Server

Mari bayangkan simulasi menambah dua todo lalu mengambil todo list:

1. Add “Beli kopi”
Client → Server: AddTodo("Beli kopi")
Server adds: {id: 1, task: 'Beli kopi', completed: false}

2. Add “Berjalan pagi”
Client → Server: AddTodo("Berjalan pagi")
Server adds: {id: 2, task: 'Berjalan pagi', completed: false}

3. GetTodos
Client → Server: GetTodos()
Server response:

idtaskcompleted
1Beli kopifalse
2Berjalan pagifalse

6. Keunggulan dan Keterbatasan

Mari bandingkan aplikasi Todo berbasis gRPC vs REST sederhana dalam bentuk tabel:

FiturREST APIgRPC
SerialisasiJSONProtobuf (binary)
KecepatanMediumSangat Cepat
Tipe DataWeakly-typed (runtime)Strongly-typed (compile)
StreamingKurang cocokNative bidi support
Dokumentasi KontrakSwagger/OpenAPI.proto (lebih konsisten)
InteroperabilitasTinggiTinggi
Support BrowsersNative (bisa fetch)Tidak, mesti ada gateway

Kelemahan gRPC

  • Client di browser harus lewat proxy/gateway.
  • Kompleksitas setup komunikasi awal sedikit lebih tinggi.
  • Untuk aplikasi kecil/monolitik, REST mungkin “cukup”.

7. Penutup

gRPC adalah pilihan tepat untuk sistem yang butuh performance, tipe data yang kuat, atau komunikasi antar service dengan beban besar. Studi kasus Todo List kali ini membuktikan betapa hemat, ekspresif, dan scalable cara kerja gRPC.

Jika ingin eksplorasi lebih lanjut, coba tambahkan streaming pada fitur update status (CompleteTodo lewat stream), atau integrasikan database sebenarnya seperti PostgreSQL.


Sumber Belajar Lanjutan


Yuk, mulai refactor REST API kamu ke gRPC untuk pengalaman yang lebih optimal dan scalable! 🚀

comments powered by Disqus