# 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
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/programming/protobuf_grpc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
