ConnectRPC is a Rust implementation of the Connect protocol, a modern and efficient RPC framework designed for building scalable and high-performance applications. It supports multiple transport protocols, including HTTP/1.1, HTTP/2, and gRPC, making it versatile for various use cases.
The library offers multiple components and features to facilitate the development of RPC clients and servers:
- Reqwest Client: Built on top of the popular Reqwest HTTP client for ease of use and reliability
- Axum Server: Implementation used for axum servers.
- Code Generation: Tools to generate client and server code from protobuf definitions.
- Unary Calls: Support for unary RPC calls.
- Unary Get Calls: Support for unary GET RPC calls.
- Streaming Calls: (Planned) Support for server-side, client-side, and bidirectional streaming RPC calls.
- Middleware Support: (Planned) Ability to add middleware for logging, authentication, etc. MTLs is supported since reqwest supports it.
Define services and messages in a proto file:
syntax = "proto3";
package hello;
message HelloRequest { optional string name = 1; }
message GoodbyeRequest { optional string name = 1; }
message HelloResponse { string message = 1; }
message GoodbyeResponse { string message = 1; }
service HelloWorldService {
rpc SayHello(HelloRequest) returns (HelloResponse) {}
rpc SayGoodbye(GoodbyeRequest) returns (GoodbyeResponse) {}
}You need to add connectrpc-build to your build-dependencies in Cargo.toml:
[build-dependencies]
connectrpc-build = "0.1"
protoc-fetcher = "0.1.2"Then, create a build.rs file to generate the necessary code. More complex examples will be included in the examples directory, but here is a simple snippet:
use std::{fs, path::PathBuf};
use connectrpc_build::Settings;
fn main() {
let settings = Settings::from_directory_recursive("./proto")
.expect("failed to create settings from directory");
let mut result = settings.generate().expect("failed to generate code");
// The difference between other generators is that **YOU** pick where the generated code goes, you can add more code to include potentially other things, such as `use your_module`;
let package = result.remove("hello").expect("no hello package found"); // package name
let out_file = PathBuf::from("src/lib.rs"); // where to put the generated code
fs::write(&out_file, package).expect("failed to write generated code");
}This will generate the necessary client and server code in src/lib.rs. If you are building a client only, you can specify the generation features in the Settings:
use std::{fs, path::PathBuf};
use connectrpc_build::{GeneratorFeatures, GeneratorReqwestFeatures, Settings};
fn main() {
let settings = Settings::from_directory_recursive("./proto")
.expect("failed to create settings from directory");
let features = GeneratorFeatures::new().reqwest(GeneratorReqwestFeatures {
proto: true, // Only generate the protobuf client
json: false, // Do not generate the JSON client
});
settings.features = features;
let mut result = settings.generate().expect("failed to generate code");
// The difference between other generators is that **YOU** pick where the generated code goes, you can add more code to include potentially other things, such as `use your_module`;
let package = result.remove("hello").expect("no hello package found"); // package name
let out_file = PathBuf::from("src/client.rs"); // where to put the generated code
fs::write(&out_file, package).expect("failed to write generated code");
// Generate server code to a separate file
let features = GeneratorFeatures::new().axum(); // Only generate the axum server
settings.features = features;
let mut result = settings.generate().expect("failed to generate code");
let package = result.remove("hello").expect("no hello package found"); // package name
let out_file = PathBuf::from("src/server.rs"); // where to put the generated code
fs::write(&out_file, package).expect("failed to write generated code");
}
Note: Depending on the features you enable, you might need to include additional dependencies in your `Cargo.toml`. For example, if you are using the Reqwest client, ensure that you have the `reqwest` crate included.
```toml
[package]
name = "your_crate_name"
version = "0.1.0"
edition = "2024"
[dependencies]
# Required dependencies for ConnectRPC
pbjson = "0.8.0"
pbjson-types = "0.8.0"
prost = "0.14"
serde = { version = "1", features = ["derive"] }
connectrpc = { version = "0.1", features = ["reqwest"] }
# Dependencies you need
reqwest = { version = "0.12", features = ["json", "gzip"] }
[build-dependencies]
# Required for code generation
connectrpc-build = "0.1"
protoc-fetcher = "0.1.2"This project is based on the works of:
I'm grateful for their contributions to the Rust ecosystem and their pioneering work in implementing the Connect protocol. Their efforts have laid the groundwork for this project, and I hope to build upon their successes to create a robust and efficient ConnectRPC implementation in Rust.
This project is licensed under the MIT License. See the LICENSE file for details.