Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
17 Sep 2025 · 5 mnt baca ·Artikel 101 / 110
Go

101. Studi Kasus: Mengkonsumsi gRPC Server Go dari Python Client

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

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:

  1. GetUserByID(id) - Mendapatkan informasi user berdasarkan ID.
  2. 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.

proto
 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:

text
1grpc-demo/
2 ├── proto/
3 │    └── user.proto
4 ├── server/
5      └── main.go

Generate Go Code dari Proto

Jalankan:

bash
1protoc --go_out=. --go-grpc_out=. proto/user.proto

Sample Code Server

go
 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:

bash
1pip install grpcio grpcio-tools

Compile proto untuk Python:

bash
1python -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. proto/user.proto

Akan menghasilkan user_pb2.py dan user_pb2_grpc.py.


4. Implementasi Python Client

Sample Code

python
 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:

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:

Output client saat dijalankan:

text
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 found

7. 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:

Artikel Terkait

💬 Komentar