g2h 0.1.1

A code generator that bridges gRPC services to HTTP/JSON endpoints using Axum
Documentation
# Example Project

This document walks through a complete example project using `g2h`.

## Project Structure

```
grpc-web-example/
├── build.rs
├── Cargo.toml
├── proto/
│   └── greeter.proto
└── src/
    └── main.rs
```

## Proto Definition

```protobuf
// proto/greeter.proto
syntax = "proto3";
package greeter.v1;

service GreeterService {
    rpc SayHello(HelloRequest) returns (HelloResponse);
    rpc SayGoodbye(GoodbyeRequest) returns (GoodbyeResponse);
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
    string timestamp = 2;
}

message GoodbyeRequest {
    string name = 1;
}

message GoodbyeResponse {
    string message = 1;
    string timestamp = 2;
}
```

## Cargo.toml

```toml
[package]
name = "grpc-web-example"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.0"
g2h = "0.1.0"
prost = "0.13.5"
tokio = { version = "1.35.0", features = ["full"] }
tonic = "0.13.0"
serde = { version = "1.0", features = ["derive"] }
chrono = "0.4.31"

[build-dependencies]
g2h = "0.1.0"
prost-build = "0.13.5"
tonic-build = "0.13.0"
```

## Build Script

```rust
// build.rs
use g2h::BridgeGenerator;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    BridgeGenerator::with_tonic_build()
        .build_prost_config()
        .compile_protos(&["proto/greeter.proto"], &["proto"])?;
    
    Ok(())
}
```

## Service Implementation & Server

```rust
// src/main.rs
use axum::{Router, Server};
use std::net::SocketAddr;
use tonic::{Request, Response, Status};
use chrono::Utc;

// Include the generated code
pub mod greeter {
    include!(concat!(env!("OUT_DIR"), "/greeter.v1.rs"));
}

use greeter::greeter_service_server::{GreeterService, GreeterServiceServer};
use greeter::{HelloRequest, HelloResponse, GoodbyeRequest, GoodbyeResponse};
use greeter::greeter_service_handler;

// Service implementation
#[derive(Default, Clone)]
struct MyGreeterService {}

#[tonic::async_trait]
impl GreeterService for MyGreeterService {
    async fn say_hello(
        &self,
        request: Request<HelloRequest>,
    ) -> Result<Response<HelloResponse>, Status> {
        let name = request.into_inner().name;
        let timestamp = Utc::now().to_rfc3339();
        
        let response = HelloResponse {
            message: format!("Hello, {}!", name),
            timestamp,
        };
        
        Ok(Response::new(response))
    }
    
    async fn say_goodbye(
        &self,
        request: Request<GoodbyeRequest>,
    ) -> Result<Response<GoodbyeResponse>, Status> {
        let name = request.into_inner().name;
        let timestamp = Utc::now().to_rfc3339();
        
        let response = GoodbyeResponse {
            message: format!("Goodbye, {}!", name),
            timestamp,
        };
        
        Ok(Response::new(response))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create the service implementation
    let greeter_service = MyGreeterService::default();
    
    // Set up the gRPC server (optional)
    let grpc_service = GreeterServiceServer::new(greeter_service.clone());
    
    // Create the HTTP router with our service
    let http_router = greeter_service_handler(greeter_service);
    
    // Configure our Axum application
    let app = Router::new()
        .nest("/api", http_router);
    
    // Start the HTTP server
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("HTTP server listening on {}", addr);
    
    Server::bind(&addr)
        .serve(app.into_make_service())
        .await?;
    
    Ok(())
}
```

## Test it with curl

Once your server is running, you can test it with curl:

```bash
curl -X POST http://localhost:3000/api/greeter.v1.GreeterService/SayHello \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'
```

Expected response:
```json
{
  "message": "Hello, World!",
  "timestamp": "2025-04-07T12:34:56.789Z"
}
```

## Test it with a gRPC client

For gRPC clients, the service is accessible at the same address using the standard gRPC protocol.