91. 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.
1// todo.proto
2syntax = "proto3";
3
4package todo;
5
6// Message Type
7message TodoItem {
8 int32 id = 1;
9 string task = 2;
10 bool completed = 3;
11}
12
13message AddTodoRequest {
14 string task = 1;
15}
16
17message AddTodoResponse {
18 TodoItem item = 1;
19}
20
21message GetTodosRequest {}
22
23message GetTodosResponse {
24 repeated TodoItem items = 1;
25}
26
27// Service
28service TodoService {
29 rpc AddTodo (AddTodoRequest) returns (AddTodoResponse);
30 rpc GetTodos (GetTodosRequest) returns (GetTodosResponse);
31}2. Generate Code dari Proto
Gunakan plugin Protobuf untuk Go:
1protoc --go_out=. --go-grpc_out=. todo.proto3. Implementasi Server gRPC dengan Golang
Buat file server.go:
1package main
2
3import (
4 "context"
5 "log"
6 "net"
7 "sync"
8
9 pb "path/to/generated/todo"
10 "google.golang.org/grpc"
11)
12
13type server struct {
14 pb.UnimplementedTodoServiceServer
15 todos []pb.TodoItem
16 mu sync.Mutex
17 nextID int32
18}
19
20func (s *server) AddTodo(ctx context.Context, req *pb.AddTodoRequest) (*pb.AddTodoResponse, error) {
21 s.mu.Lock()
22 defer s.mu.Unlock()
23 s.nextID++
24 item := pb.TodoItem{
25 Id: s.nextID,
26 Task: req.GetTask(),
27 Completed: false,
28 }
29 s.todos = append(s.todos, item)
30 return &pb.AddTodoResponse{Item: &item}, nil
31}
32
33func (s *server) GetTodos(ctx context.Context, req *pb.GetTodosRequest) (*pb.GetTodosResponse, error) {
34 s.mu.Lock()
35 defer s.mu.Unlock()
36 // Copy slice untuk keamanan concurrent
37 items := make([]*pb.TodoItem, len(s.todos))
38 for i, todo := range s.todos {
39 copied := todo
40 items[i] = &copied
41 }
42 return &pb.GetTodosResponse{Items: items}, nil
43}
44
45func main() {
46 lis, err := net.Listen("tcp", ":50051")
47 if err != nil {
48 log.Fatalf("failed to listen: %v", err)
49 }
50 s := grpc.NewServer()
51 pb.RegisterTodoServiceServer(s, &server{})
52 log.Println("gRPC server running at :50051")
53 if err := s.Serve(lis); err != nil {
54 log.Fatalf("failed to serve: %v", err)
55 }
56}4. Implementasi Client Sederhana
Buat file client.go:
1package main
2
3import (
4 "context"
5 "log"
6 "time"
7
8 pb "path/to/generated/todo"
9 "google.golang.org/grpc"
10)
11
12func main() {
13 conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
14 if err != nil {
15 log.Fatalf("did not connect: %v", err)
16 }
17 defer conn.Close()
18 c := pb.NewTodoServiceClient(conn)
19
20 // Simulasi AddTodo
21 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
22 defer cancel()
23 r, err := c.AddTodo(ctx, &pb.AddTodoRequest{Task: "Beli kopi"})
24 if err != nil {
25 log.Fatalf("could not add: %v", err)
26 }
27 log.Printf("Added Todo: %v", r.GetItem())
28
29 // Simulasi GetTodos
30 resp, err := c.GetTodos(ctx, &pb.GetTodosRequest{})
31 if err != nil {
32 log.Fatalf("could not get todos: %v", err)
33 }
34 for _, t := range resp.GetItems() {
35 log.Printf("%d: %s [completed: %v]", t.GetId(), t.GetTask(), t.GetCompleted())
36 }
37}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! 🚀