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:
| id | task | completed |
|---|---|---|
| 1 | Beli kopi | false |
| 2 | Berjalan pagi | false |
6. Keunggulan dan Keterbatasan
Mari bandingkan aplikasi Todo berbasis gRPC vs REST sederhana dalam bentuk tabel:
| Fitur | REST API | gRPC |
|---|---|---|
| Serialisasi | JSON | Protobuf (binary) |
| Kecepatan | Medium | Sangat Cepat |
| Tipe Data | Weakly-typed (runtime) | Strongly-typed (compile) |
| Streaming | Kurang cocok | Native bidi support |
| Dokumentasi Kontrak | Swagger/OpenAPI | .proto (lebih konsisten) |
| Interoperabilitas | Tinggi | Tinggi |
| Support Browsers | Native (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! 🚀