101. Studi Kasus: Mengkonsumsi gRPC Server Go dari Python Client
gRPC (Google Remote Procedure Call) adalah framework komunikasi open source yang telah menjadi fondasi berbagai sistem microservices modern. Arsitektur gRPC mempercepat pengembangan layanan lintas platform dengan performa tinggi, terutama ketika komunikasi antar bahasa diperlukan. Pada artikel kali ini, kita akan membahas tentang integrasi gRPC antara server Go dan client Python, lengkap dengan studi kasus, contoh kode, dan diagram alur.
Mengapa gRPC?
Beberapa alasan gRPC digemari:
- Performance: Berbasis HTTP/2 yang mendukung multiplexing dan kompresi header.
- IDL (Interface Definition Language): Protobuf memudahkan definisi kontrak layanan.
- Interoperabilitas: Mendukung berbagai bahasa populer seperti Go, Python, Java, C#, dan lain-lain.
- Streaming: Mendukung client, server, dan bidirectional streaming.
- Scalability: Cocok untuk arsitektur microservices di production.
Studi Kasus
Mari kita buat sebuah layanan sederhana UserService yang menyediakan dua operasi utama:
- GetUserByID(id) - Mendapatkan informasi user berdasarkan ID.
- ListUsers() - Mendapatkan list seluruh user yang tersedia.
Layanan ini akan dibangun dengan server Go dan dikonsumsi oleh client Python.
1. Mendesain Kontrak Layanan dengan Proto
Kita mulai dengan mendefinisikan API-nya menggunakan protobuf.
1// user.proto
2syntax = "proto3";
3
4package user;
5
6service UserService {
7 rpc GetUserByID(UserIDRequest) returns (UserResponse);
8 rpc ListUsers(Empty) returns (UserListResponse);
9}
10
11message Empty {}
12
13message UserIDRequest {
14 int32 id = 1;
15}
16
17message UserResponse {
18 int32 id = 1;
19 string name = 2;
20 string email = 3;
21}
22
23message UserListResponse {
24 repeated UserResponse users = 1;
25}2. Implementasi Server Go
Setup Project
Struktur folder:
1grpc-demo/
2 ├── proto/
3 │ └── user.proto
4 ├── server/
5 └── main.goGenerate Go Code dari Proto
Jalankan:
1protoc --go_out=. --go-grpc_out=. proto/user.protoSample Code Server
1package main
2
3import (
4 "context"
5 "log"
6 "net"
7
8 pb "grpc-demo/proto"
9 "google.golang.org/grpc"
10)
11
12type userServer struct {
13 pb.UnimplementedUserServiceServer
14 users map[int32]*pb.UserResponse
15}
16
17func (s *userServer) GetUserByID(ctx context.Context, req *pb.UserIDRequest) (*pb.UserResponse, error) {
18 user, ok := s.users[req.Id]
19 if !ok {
20 return nil, status.Errorf(codes.NotFound, "user not found")
21 }
22 return user, nil
23}
24
25func (s *userServer) ListUsers(_ context.Context, _ *pb.Empty) (*pb.UserListResponse, error) {
26 var userList []*pb.UserResponse
27 for _, user := range s.users {
28 userList = append(userList, user)
29 }
30 return &pb.UserListResponse{Users: userList}, nil
31}
32
33func main() {
34 lis, err := net.Listen("tcp", ":50051")
35 if err != nil {
36 log.Fatalf("failed to listen: %v", err)
37 }
38
39 server := grpc.NewServer()
40 pb.RegisterUserServiceServer(server, &userServer{
41 users: map[int32]*pb.UserResponse{
42 1: {Id: 1, Name: "Alice", Email: "alice@example.com"},
43 2: {Id: 2, Name: "Bob", Email: "bob@example.com"},
44 },
45 })
46
47 log.Println("gRPC server listening on :50051")
48 if err := server.Serve(lis); err != nil {
49 log.Fatalf("failed to serve: %v", err)
50 }
51}3. Generate Python Client Stub
Install dependency:
1pip install grpcio grpcio-toolsCompile proto untuk Python:
1python -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. proto/user.protoAkan menghasilkan user_pb2.py dan user_pb2_grpc.py.
4. Implementasi Python Client
Sample Code
1import grpc
2import user_pb2
3import user_pb2_grpc
4
5def get_user_by_id(stub, user_id):
6 req = user_pb2.UserIDRequest(id=user_id)
7 try:
8 res = stub.GetUserByID(req)
9 print(f"User {user_id}: {res.name} ({res.email})")
10 except grpc.RpcError as e:
11 print(f"Failed to get user {user_id}: {e.details()}")
12
13def list_users(stub):
14 res = stub.ListUsers(user_pb2.Empty())
15 for u in res.users:
16 print(f"- {u.id}: {u.name} ({u.email})")
17
18def main():
19 with grpc.insecure_channel('localhost:50051') as channel:
20 stub = user_pb2_grpc.UserServiceStub(channel)
21 print("== List Users ==")
22 list_users(stub)
23 print("\n== Get User By ID ==")
24 get_user_by_id(stub, 1)
25 get_user_by_id(stub, 99) # Example: user tidak ada
26
27if __name__ == '__main__':
28 main()5. Diagram Alur
Untuk memperjelas, berikut diagram alur interaksi antar komponen menggunakan mermaid:
sequenceDiagram
participant Client as Python Client
participant Server as Go gRPC Server
Client->>Server: Connect (TCP :50051)
Client->>Server: GetUserByID(1)
Server-->>Client: UserResponse (Alice)
Client->>Server: GetUserByID(99)
Server-->>Client: Error (not found)
Client->>Server: ListUsers()
Server-->>Client: UserListResponse ([Alice, Bob])
6. Simulasi Output
Mari lihat tabel data user di server dan kemungkinan output client:
| ID | Name | |
|---|---|---|
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
Output client saat dijalankan:
1== List Users ==
2- 1: Alice (alice@example.com)
3- 2: Bob (bob@example.com)
4
5== Get User By ID ==
6User 1: Alice (alice@example.com)
7Failed to get user 99: user not found7. Pembahasan dan Best Practice
- Error Handling: Client harus menangani error gRPC RpcError untuk kasus tidak ditemukan, timeout, dsb.
- Contract-First: Dengan menggunakan proto sebagai sumber kebenaran (source of truth), baik client maupun server bisa dikembangkan independen selama kontrak tidak berubah.
- Interop Testing: Selalu lakukan integrasi test lintas bahasa dengan protokol yang sama, pastikan serialization/deserialization berjalan benar.
- Secure Channel: Untuk production, gunakan TLS pada insecure_channel.
- Proto Versioning: Jika API bertambah/berubah, jaga backward compatibility (mis: gunakan field baru dengan tag unik).
8. Kesimpulan
Studi kasus ini menunjukkan bagaimana production-ready microservices dapat dikembangkan dengan stack lintas bahasa menggunakan gRPC. Dengan kontrak API terdefinisi di proto, kita bisa membangun server Go dan melayani request dari berbagai platform, seperti Python client. Pendekatan ini bukan hanya meningkatkan performa dan konsistensi data, namun juga mempercepat pengembangan lintas tim dan bahasa.
Adopsi gRPC membuka peluang mengembangkan polyglot systems tanpa kompromi pada maintainability dan scalability.
Referensi: