gRPC Module
The mockforge_grpc crate provides dynamic gRPC service discovery and mocking with HTTP bridge capabilities.
Modules
Core Functions
start
#![allow(unused)] fn main() { pub async fn start(port: u16) -> Result<(), Box<dyn std::error::Error + Send + Sync>> }
Starts a gRPC server with default configuration on the specified port.
Parameters:
port: Port number to bind the gRPC server to
Returns: Result<(), Error> indicating server startup success
Example:
use mockforge_grpc::start; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { start(50051).await?; Ok(()) }
start_with_config
#![allow(unused)] fn main() { pub async fn start_with_config( port: u16, latency_profile: Option<LatencyProfile>, config: DynamicGrpcConfig, ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> }
Starts a gRPC server with custom configuration and optional latency simulation.
Parameters:
port: Port number to bind the gRPC server tolatency_profile: Optional latency injection profileconfig: Dynamic gRPC configuration
Returns: Result<(), Error> indicating server startup success
Example:
#![allow(unused)] fn main() { use mockforge_grpc::{start_with_config, DynamicGrpcConfig}; use mockforge_core::LatencyProfile; let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), enable_reflection: true, ..Default::default() }; start_with_config(50051, Some(LatencyProfile::normal()), config).await?; }
Configuration Types
DynamicGrpcConfig
#![allow(unused)] fn main() { pub struct DynamicGrpcConfig { pub proto_dir: String, pub enable_reflection: bool, pub excluded_services: Vec<String>, pub http_bridge: Option<HttpBridgeConfig>, } }
Configuration for dynamic gRPC service discovery.
Fields:
proto_dir: Directory containing.protofiles (default: “proto”)enable_reflection: Whether to enable gRPC reflection (default: false)excluded_services: List of services to exclude from discoveryhttp_bridge: Optional HTTP bridge configuration
Methods:
#![allow(unused)] fn main() { impl DynamicGrpcConfig { pub fn default() -> Self } }
Example:
#![allow(unused)] fn main() { let config = DynamicGrpcConfig { proto_dir: "./my-protos".to_string(), enable_reflection: true, excluded_services: vec!["HealthService".to_string()], http_bridge: Some(HttpBridgeConfig { enabled: true, port: 8080, generate_openapi: true, }), }; }
HttpBridgeConfig
#![allow(unused)] fn main() { pub struct HttpBridgeConfig { pub enabled: bool, pub port: u16, pub generate_openapi: bool, pub cors_enabled: bool, } }
Configuration for HTTP bridge functionality.
Fields:
enabled: Whether HTTP bridge is enabled (default: true)port: HTTP server port (default: 8080)generate_openapi: Whether to generate OpenAPI specs (default: true)cors_enabled: Whether CORS is enabled (default: false)
Methods:
#![allow(unused)] fn main() { impl HttpBridgeConfig { pub fn default() -> Self } }
Service Registry
ServiceRegistry
#![allow(unused)] fn main() { pub struct ServiceRegistry { /* fields omitted */ } }
Registry containing discovered gRPC services.
Methods:
#![allow(unused)] fn main() { impl ServiceRegistry { pub fn new() -> Self pub fn with_descriptor_pool(descriptor_pool: DescriptorPool) -> Self pub fn descriptor_pool(&self) -> &DescriptorPool pub fn register(&mut self, name: String, service: DynamicGrpcService) pub fn get(&self, name: &str) -> Option<&Arc<DynamicGrpcService>> pub fn service_names(&self) -> Vec<String> } }
Example:
#![allow(unused)] fn main() { use mockforge_grpc::ServiceRegistry; let mut registry = ServiceRegistry::new(); registry.register("MyService".to_string(), dynamic_service); println!("Registered services: {:?}", registry.service_names()); }
Dynamic Service Types
DynamicGrpcService
#![allow(unused)] fn main() { pub struct DynamicGrpcService { /* fields omitted */ } }
Dynamically generated gRPC service implementation.
Methods:
#![allow(unused)] fn main() { impl DynamicGrpcService { pub fn new( proto_service: ProtoService, config: Option<ServiceConfig>, ) -> Self } }
ProtoService
#![allow(unused)] fn main() { pub struct ProtoService { pub name: String, pub methods: HashMap<String, ProtoMethod>, pub package: String, } }
Parsed protobuf service definition.
Fields:
name: Service namemethods: Map of method names to method definitionspackage: Protobuf package name
ProtoMethod
#![allow(unused)] fn main() { pub struct ProtoMethod { pub name: String, pub input_type: String, pub output_type: String, pub is_client_streaming: bool, pub is_server_streaming: bool, } }
Parsed protobuf method definition.
Fields:
name: Method nameinput_type: Input message type nameoutput_type: Output message type nameis_client_streaming: Whether method accepts client streamingis_server_streaming: Whether method returns server streaming
Mock Response Types
MockResponse
#![allow(unused)] fn main() { pub enum MockResponse { Unary(Value), ServerStream(Vec<Value>), ClientStream(Value), BidiStream(Vec<Value>), } }
Mock response types for different gRPC method patterns.
Variants:
Unary(Value): Single request-responseServerStream(Vec<Value>): Server streaming responseClientStream(Value): Client streaming responseBidiStream(Vec<Value>): Bidirectional streaming
Reflection Types
MockReflectionProxy
#![allow(unused)] fn main() { pub struct MockReflectionProxy { /* fields omitted */ } }
Proxy for gRPC reflection protocol.
Methods:
#![allow(unused)] fn main() { impl MockReflectionProxy { pub async fn new( config: ProxyConfig, registry: Arc<ServiceRegistry>, ) -> Result<Self> } }
ReflectionProxy
#![allow(unused)] fn main() { pub trait ReflectionProxy { fn list_services(&self) -> Vec<String>; fn get_service_descriptor(&self, service_name: &str) -> Option<&prost_reflect::ServiceDescriptor>; fn get_method_descriptor(&self, service_name: &str, method_name: &str) -> Option<&prost_reflect::MethodDescriptor>; } }
Trait for gRPC reflection functionality.
ProxyConfig
#![allow(unused)] fn main() { pub struct ProxyConfig { pub max_message_size: usize, pub connection_timeout: Duration, pub request_timeout: Duration, } }
Configuration for reflection proxy.
Fields:
max_message_size: Maximum message size in bytes (default: 4MB)connection_timeout: Connection timeout durationrequest_timeout: Request timeout duration
Proto Parser
ProtoParser
#![allow(unused)] fn main() { pub struct ProtoParser { /* fields omitted */ } }
Parser for protobuf files.
Methods:
#![allow(unused)] fn main() { impl ProtoParser { pub fn new() -> Self pub async fn parse_directory(&mut self, dir: &str) -> Result<()> pub fn services(&self) -> &HashMap<String, ProtoService> pub fn into_pool(self) -> DescriptorPool } }
Example:
#![allow(unused)] fn main() { use mockforge_grpc::dynamic::proto_parser::ProtoParser; let mut parser = ProtoParser::new(); parser.parse_directory("./proto").await?; let services = parser.services(); println!("Found {} services", services.len()); }
Discovery Functions
discover_services
#![allow(unused)] fn main() { pub async fn discover_services( config: &DynamicGrpcConfig, ) -> Result<ServiceRegistry, Box<dyn std::error::Error + Send + Sync>> }
Discovers and registers gRPC services from proto files.
Parameters:
config: Discovery configuration
Returns: Result<ServiceRegistry, Error> with discovered services
Example:
#![allow(unused)] fn main() { use mockforge_grpc::{discover_services, DynamicGrpcConfig}; let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), ..Default::default() }; let registry = discover_services(&config).await?; println!("Discovered services: {:?}", registry.service_names()); }
Generated Types
Greeter Service
#![allow(unused)] fn main() { pub mod generated { pub mod greeter_server { pub trait Greeter: Send + Sync + 'static { type SayHelloStreamStream: Stream<Item = Result<HelloReply, Status>> + Send + 'static; async fn say_hello( &self, request: Request<HelloRequest>, ) -> Result<Response<HelloReply>, Status>; async fn say_hello_stream( &self, request: Request<HelloRequest>, ) -> Result<Response<Self::SayHelloStreamStream>, Status>; async fn say_hello_client_stream( &self, request: Request<Streaming<HelloRequest>>, ) -> Result<Response<HelloReply>, Status>; async fn chat( &self, request: Request<Streaming<HelloRequest>>, ) -> Result<Response<Self::ChatStream>, Status>; } } } }
Generated gRPC service trait with all streaming patterns.
Message Types
HelloRequest
#![allow(unused)] fn main() { pub struct HelloRequest { pub name: String, } }
Request message for greeting service.
Fields:
name: Name to greet
HelloReply
#![allow(unused)] fn main() { pub struct HelloReply { pub message: String, pub metadata: Option<HashMap<String, String>>, pub items: Vec<String>, } }
Response message for greeting service.
Fields:
message: Greeting messagemetadata: Optional metadata mapitems: Optional list of items
Error Handling
All functions return Result<T, Box<dyn std::error::Error + Send + Sync>>. Common errors include:
- File I/O errors (proto file reading)
- Protobuf parsing errors
- Server binding errors
- Reflection setup errors
- HTTP bridge configuration errors
Constants
DEFAULT_MAX_MESSAGE_SIZE: Default maximum message size (4MB)
Feature Flags
data-faker: Enables advanced data synthesis features
Examples
Basic gRPC Server
use mockforge_grpc::start; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { // Starts server on port 50051 with default config // Automatically discovers services from ./proto directory start(50051).await?; Ok(()) }
Server with Reflection
use mockforge_grpc::{start_with_config, DynamicGrpcConfig}; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), enable_reflection: true, // Enable gRPC reflection ..Default::default() }; start_with_config(50051, None, config).await?; // Now you can use grpcurl: // grpcurl -plaintext localhost:50051 list // grpcurl -plaintext localhost:50051 describe MyService Ok(()) }
Server with HTTP Bridge
use mockforge_grpc::{start_with_config, DynamicGrpcConfig}; use mockforge_grpc::dynamic::http_bridge::HttpBridgeConfig; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), http_bridge: Some(HttpBridgeConfig { enabled: true, port: 8080, generate_openapi: true, }), ..Default::default() }; start_with_config(50051, None, config).await?; // gRPC available on localhost:50051 // REST API available on localhost:8080 // OpenAPI docs at http://localhost:8080/api/docs Ok(()) }
Manual Service Discovery
use mockforge_grpc::{discover_services, DynamicGrpcConfig}; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), excluded_services: vec!["HealthService".to_string()], ..Default::default() }; let registry = discover_services(&config).await?; println!("Discovered services:"); for service_name in registry.service_names() { println!(" - {}", service_name); } // Access service descriptors if let Some(descriptor) = registry.descriptor_pool().get_service_by_name("MyService") { println!("Service methods:"); for method in descriptor.methods() { println!(" - {}", method.name()); } } Ok(()) }
Custom Service Implementation
use mockforge_grpc::dynamic::service_generator::DynamicGrpcService; use mockforge_grpc::dynamic::proto_parser::{ProtoParser, ProtoService}; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { // Parse proto files let mut parser = ProtoParser::new(); parser.parse_directory("./proto").await?; // Get a specific service if let Some(proto_service) = parser.services().get("MyService") { // Create dynamic service let dynamic_service = DynamicGrpcService::new(proto_service.clone(), None); // The service will automatically handle all RPC methods // with mock responses based on the protobuf definitions } Ok(()) }
Using gRPC Reflection
use mockforge_grpc::reflection::{MockReflectionProxy, ProxyConfig}; use std::sync::Arc; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let config = DynamicGrpcConfig { proto_dir: "./proto".to_string(), enable_reflection: true, ..Default::default() }; let registry = discover_services(&config).await?; let registry_arc = Arc::new(registry); let proxy_config = ProxyConfig::default(); let reflection_proxy = MockReflectionProxy::new(proxy_config, registry_arc).await?; // The reflection proxy enables: // - Service listing: reflection_proxy.list_services() // - Service descriptors: reflection_proxy.get_service_descriptor("MyService") // - Method descriptors: reflection_proxy.get_method_descriptor("MyService", "MyMethod") Ok(()) }