12个版本
0.3.2 | 2024年1月11日 |
---|---|
0.3.1 | 2024年1月8日 |
0.3.0 | 2023年12月28日 |
0.2.0 | 2023年10月4日 |
0.1.1 | 2023年3月3日 |
#305 在 HTTP服务器
每月101 次下载
50KB
823 行
Axum Connect-Web
通过Rust的Axum将基于protobuf的Connect-Web RPC框架引入。
Axum版本
axum-connect:0.3
与axum:0.7
兼容axum-connect:0.2
与axum:0.6
兼容
功能 🔍
- 无缝集成到现有的Axum HTTP应用程序中
- 与Axum的API紧密相似
- 提取状态和其他实现
RpcFromRequestParts
的parts
,就像在Axum中一样。 - 返回任何实现
RpcIntoResponse
的类型,就像Axum一样。
- 提取状态和其他实现
- 生成的类型和服务处理程序是强类型的,...
- 处理程序强制执行语义上正确的HTTP 'parts'访问。
- 允许用户像Axum一样推导
RpcIntoResponse
和RpcFromRequestParts
。- 注意:这些必须是Axum类型的派生,因为它们更具有限制性;您不再处理任意的HTTP,而是在HTTP上说话
connect-web
RPC over HTTP。
- 注意:这些必须是Axum类型的派生,因为它们更具有限制性;您不再处理任意的HTTP,而是在HTTP上说话
- 使用惯用的Axum/Rust封装
connect-web
错误处理。 - 从单独的crate中的
*.proto
文件进行代码生成。 - 所有其他Axum带来的惊人好处,如社区、文档和性能!
注意 ⚠️
我们在生产中使用 axum-connect
,但不知道是否有更有头脑的人使用。它是用Rust编写的,这显然提供了一些编译器的保证,但尚未经过良好的测试或实战证明。请自行决定如何使用这些信息。
如果您使用 axum-connect
,请让我知道!如果您发现错误,请提出问题。
入门 🤓
假定您具备使用Protobuf(包括IDL及其在RPC框架中的应用)和Axum的相关知识。
依赖项 👀
您需要2个axum-connect
包,一个用于代码生成,另一个用于运行时使用。由于prost的工作方式,您还需要将其添加到自己的项目中。显然,您还需要axum
和tokio
。
# Note: axum-connect-build will fetch `protoc` for you.
cargo add --build axum-connect-build
cargo add axum-connect prost axum
cargo add tokio --features full
Protobuf文件 🥱
首先,创建必要的“hello world”proto服务定义。
proto/hello.proto
syntax = "proto3";
package hello;
message HelloRequest { string name = 1; }
message HelloResponse { string message = 1; }
service HelloWorldService {
rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
代码生成 🤔
使用axum_connect_codegen
包将proto IDL生成Rust代码。
目前,所有代码生成都是在本地磁盘上的proto文件中完成的,并使用一个
build.rs
文件。将来我希望支持更多Buf的语法,例如远程代码生成。
build.rs
use axum_connect_build::{axum_connect_codegen, AxumConnectGenSettings};
fn main() {
// This helper will use `proto` as the import path, and globs all .proto
// files in the `proto` directory.
//
// Note that you might need to re-save the `build.rs` file after updating
// a proto file to get rust-analyzer to pickup the change. I haven't put
// time into looking for a fix to that yet.
let settings = AxumConnectGenSettings::from_directory_recursive("proto")
.expect("failed to glob proto files");
axum_connect_codegen(settings).unwrap();
}
有趣的部分 😁
无聊的部分都处理完毕后,让我们使用Axum实现我们的服务!
use async_stream::stream;
use axum::{extract::Host, Router};
use axum_connect::{futures::Stream, prelude::*};
use proto::hello::*;
mod proto {
pub mod hello {
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
}
}
#[tokio::main]
async fn main() {
// Build our application with a route. Note the `rpc` method which was added by `axum-connect`.
// It expect a service method handler, wrapped in it's respective type. The handler (below) is
// just a normal Rust function. Just like Axum, it also supports extractors!
let app = Router::new()
.rpc(HelloWorldService::say_hello(say_hello_success))
.rpc(HelloWorldService::say_hello_stream(say_hello_stream));
let listener = tokio::net::TcpListener::bind("127.0.0.1:3030")
.await
.unwrap();
println!("listening on http://{:?}", listener.local_addr());
axum::serve(listener, app).await.unwrap();
}
async fn say_hello_success(
Host(host): Host,
request: HelloRequest
) -> HelloResponse {
HelloResponse {
message: format!(
"Hello {}! You're addressing the hostname: {}.",
request.name, host
),
}
}
发送它 🚀
为了测试它,手动尝试访问端点。
curl --location 'https://127.0.0.1:3030/hello.HelloWorldService/SayHello' \
--header 'Content-Type: application/json' \
--data '{ "name": "Alec" }'
从这里,您可以启动一个connect-web
TypeScript/Go项目,以端到端强类型RPC调用您的API。
请求/响应部分 🙍♂️
请求和响应类型都是通过axum-connect
派生的。一开始这可能会显得有些多余。
我们先从简单的开始,RpcIntoResponse
。连接RPC不是任意的HTML请求,它们不能返回任意的HTML响应。例如,流式响应必须返回HTTP 200状态码,不管错误状态如何。按照Axum(非常棒)的范式,这是通过类型系统强制执行的。RPC处理器不能返回任意的HTML,而必须返回axum-connect
知道如何转换为有效Connect响应的内容。
不那么直观的是,axum-connect
派生了RpcFromRequestParts
,这与Axum的FromRequestParts
几乎相同。重要的是,FromRequestParts
可以返回任意的HTML响应错误,这同样是一个问题。
Axum还允许FromRequest
在处理程序中占用最后一个参数,该处理程序消耗了整个HTTP请求(包括主体)。由于axum-connect
需要自己处理请求输入,所以没有与RPC处理器相对应的等效部分。
路线图 / 非目标 🛣️
- 探索比
RpcFromRequestParts
更好的类型- 理想情况下,客户端只需要提供一个
RpcIntoError
,但我还没有完全思考这个问题。我知道在自定义类型上有PITA。
- 理想情况下,客户端只需要提供一个
- 重新设计错误响应以允许多个错误
- 在生成的代码和运行时代码之间进行版本检查
- 为向前兼容性制定计划
- 使所有内容与
connect-web
对齐... - 全面集成测试
更多遥远的目标 🌜
- 我很乐意也支持一个WASM准备好的客户端库
- 使用
buf.build
支持远程代码生成和简化的proto处理 - 支持gRPC调用
- 我认为这很难做,我没有个人用例
- 可能有一天会支持通过WebRTC进行BiDi流式传输
- 这需要
connect-web
支持相同的协议 - WebRTC流因为它们是DTLS/SRTP和弹性的
- 这需要
- 用自定义的简单东西替换Prost
非目标 🙅
- 支持 gRPC 所有的功能
- 您已经可以通过 Axum 得到很多这样的功能,但 gRPC 是一个怪物,我不想复制它。这种复杂性对 Google 来说很有用,但对其他人来说却是个障碍。
- 做一切并与其他所有东西集成
- 我计划保持
axum-connect
高度专注于其核心功能。擅长它所做的事情,其他的事情则留给其他 crate。 - 这是 Rust 的典型用法。做好一件事,然后把其他的事情留给其他 crate。
- 我计划保持
Prost 和 Protobuf 📖
Protoc 版本
如果需要或希望这样做,可以在 AxumConnectGenSettings
中配置已安装的 protoc
版本。将值设置为 None
将完全禁用下载。
理由
由于 Prost 停止提供 protoc
二进制文件(这是一个我不同意的决定),因此 axum-connect-build
内部使用 protoc-fetcher 来下载并解决一份 protoc
的副本。这比强迫每个构建环境(通常是 Heroku 和/或 Docker)预安装最新的 protoc
二进制文件要简单得多。如果不同意,或者需要遵守公司政策,或者构建环境离线,可以禁用此行为。
我希望有一天能用一个新的“精简”的 protoc 库来替换所有的东西,为 Rust 社区提供支持。这个库内置了解析器,只支持最新的 proto3 语法以及标准的 JSON 序列化格式,并且明确不支持许多很少使用的功能。但那一天还不是今天。
许可证 🧾
Axum-Connect 采用双重许可(任选其一)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
- Apache 许可证,版本 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
依赖项
~10–15MB
~309K SLoC