> For the complete documentation index, see [llms.txt](https://bagus-cahyono.gitbook.io/programming-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bagus-cahyono.gitbook.io/programming-notes/programming/protobuf_grpc.md).

# Protobuf & gRPC

## Protobuf

Protobuf (Protocol Buffers) is a language-neutral, platform-neutral data serialization format developed by Google. It’s designed for efficient communication and storage, especially in distributed systems.

* **Compact and Efficient**: Protobuf uses binary serialization, which is smaller and faster than formats like JSON or XML.
* **Schema-based**: Data is defined in .proto files using a schema, which ensures strict typing and compatibility. Less ambiguous and easier to use programmatically.
* **Cross-language**: Supported in many languages like Go, Python, Java, etc.

## gRPC

**(Google Remote Procedure Calls)** is a high-performance RPC framework that uses Protobuf for data serialization. It enables seamless communication between services, regardless of the programming language.

* **Supports Multiple Communication Types**:
  * Unary (one request, one response)
  * Server-streaming (one request, multiple responses)
  * Client-streaming (multiple requests, one response)
  * Bi-directional streaming (multiple requests, multiple responses)
* **Built-in Code Generation**: gRPC generates client and server stubs automatically from the `.proto` file.
* **HTTP/2 Support**: Enables multiplexing, compression, and improved performance over HTTP/1.1.

## Example

### **Define the Protobuf File**

`user.proto`

```proto
syntax = "proto3";

package user;

service UserService {
  // Unary RPC: Request user details
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
}

message GetUserRequest {
  string id = 1; // User ID
}

message GetUserResponse {
  string id = 1;
  string name = 2;
  int32 age = 3;
}
```

### Generate Code

Run the following command to generate the code (example for Go):

```bash
protoc --go_out=. --go-grpc_out=. user.proto
```

This generates:

1. `user.pb.go`: Contains Protobuf message definitions.
2. `user_grpc.pb.go`: Contains gRPC service definitions (interfaces for server and client).

#### **Step 3: Implement the Server**

`server.go`

```go
package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "path/to/generated/user" // Update with actual path
)

// Server struct implements the generated UserServiceServer interface
type Server struct {
    pb.UnimplementedUserServiceServer
}

// Implement GetUser method
func (s *Server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    log.Printf("Received request for user ID: %s", req.Id)

    // Mock user data
    user := &pb.GetUserResponse{
        Id:   req.Id,
        Name: "John Doe",
        Age:  30,
    }
    return user, nil
}

func main() {
    listener, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    grpcServer := grpc.NewServer()
    pb.RegisterUserServiceServer(grpcServer, &Server{})

    log.Println("Server is running on port 50051")
    if err := grpcServer.Serve(listener); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}
```

### Implement the Client

`client.go`

```go
package main

import (
    "context"
    "log"
    "time"

    "google.golang.org/grpc"
    pb "path/to/generated/user" // Update with actual path
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("Failed to connect to server: %v", err)
    }
    defer conn.Close()

    client := pb.NewUserServiceClient(conn)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    // Call GetUser RPC
    req := &pb.GetUserRequest{Id: "123"}
    resp, err := client.GetUser(ctx, req)
    if err != nil {
        log.Fatalf("Error calling GetUser: %v", err)
    }

    log.Printf("User details: ID=%s, Name=%s, Age=%d", resp.Id, resp.Name, resp.Age)
}
```

### Run the System

Start the gRPC server:

```bash
go run server.go
```

Run the client:

```bash
go run client.go
```

### Output

On the server:

```
Received request for user ID: 123
```

On the client:

```
User details: ID=123, Name=John Doe, Age=30
```
