35 个版本
0.0.14-beta.1 | 2024 年 5 月 6 日 |
---|---|
0.0.13 | 2024 年 2 月 23 日 |
0.0.10 | 2024 年 1 月 25 日 |
0.0.7 | 2023 年 12 月 29 日 |
#866 in 网络编程
145KB
3.5K SLoC
API SDK
为 Rust 编写 HTTP API 客户端提供的一个易于使用的 API 工具包。
- 基于 reqwest 来处理 HTTP 请求
- 宏定义 API 和发送请求
- 以 JSON / XML / 表单 / 多部分的形式发送请求
- 通过 serde 解析响应
- 使用 serde_json 处理 JSON 响应
- 使用 quick-xml 处理 XML 响应
- 支持
X-Request-ID
和X-Trace-ID
/X-Span-ID
- 更多定制能力
- 提供
UrlRewriter
和DnsResolver
来自定义 URL 和 API 端点 - 通过使用
ApiAuthenticator
设置Authorization
头 - 通过集成 reqwest-middleware 提供中间件
- 使用
MockServer
模拟服务器响应
- 提供
- 变更日志
动机
当使用 reqwest 向服务器端发送 API 请求时,我们需要做一些常见的工作。包括设置认证信息、解析请求响应、处理异常、添加日志和跟踪信息等。
因此,我们通常开发一些辅助函数来实现上述功能。该 crate 的设计目的是简化这部分开发工作并提供一个通用的设计实现。
入门
安装
更新 Cargo.toml
以将此 crate 添加为依赖项。
[dependencies]
apisdk = { version = "0" }
此 crate 有几个功能
- uuid
- dns
- 安装
hickory-resolver
(也称为trust-dns-resolver
),并能够用它来进行 DNS 查询
- 安装
定义 API 结构体
要定义一个非常简单的 API,我们只需要几行代码。
use apisdk::{http_api, send, ApiResult};
// Define an API struct
#[http_api("https://www.example.com/api")]
#[derive(Debug, Clone)] // optional
pub struct MyApi;
// Response DTO
#[derive(serde::Deserialize)]
pub struct User {}
impl MyApi {
// Define a function for public use.
// It should return ApiResult<T>, which is an alias for Result<T, ApiError>.
pub async fn get_user(&self, user_id: u64) -> ApiResult<User> {
// Initiate a GET request with the URL path, and wait for the endpoint to be resolved.
let req = self.get(format!("/user/{}", user_id)).await?;
// Send the request to server, and parse it to result.
send!(req).await
}
}
调用 API
要使用 API,请按照以下步骤操作。
use apisdk::ApiResult;
async fn foo() -> ApiResult<()> {
// Initiate an API instance with default settings.
// Or use MyApi::builder().build() to generate a customized instance.
let api = MyApi::default();
// Invoke the function to execute HTTP request.
let user = api.get_user(1).await?;
Ok(())
}
关键点
http_api
和 api_method
宏
http_api
- 声明一个结构体作为 API
#[http_api("https://api.site/base")]
api_method
- (可选) 精炼 API 方法
创建 API 实例
我们可以使用 XxxApi::builder()
获取 ApiBuilder
的实例,并调用以下函数来定制 API 实例。
with_client
- 设置
reqwest::ClientBuilder
以定制客户端
- 设置
with_rewriter
- 重写 HTTP URL
with_resolver
- 自定义 DNS 查询
with_authenticator
- 为每个请求设置凭证
with_initialiser
&with_middleware
- 支持所有
reqwest-middleware
组件
- 支持所有
with_log
- 在处理请求时启用/禁用日志
之后,我们应该调用 build()
来创建 API 实例。
对于非常简单的 API,我们可以使用 XxxApi::default()
来替换 XxxApi::builder().build()
。
创建 HTTP 请求
API 实例提供一系列函数来协助创建 HTTP 请求。
- 通过 HTTP 方法创建
asyncfn request(method:Method,path:implAsRef<str>) -> ApiResult<RequestBuilder>
- 便利函数
asyncfn head(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn get(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn post(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn put(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn patch(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn delete(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn options(path:implAsRef<str>) -> ApiResult<RequestBuilder>
asyncfn trace(path:implAsRef<str>) -> ApiResult<RequestBuilder>
我们还可以使用 API 实例的 core
字段来访问更多底层功能。
let api = XxxApi::default();
let req = api.core // an instance of apisdk::ApiCore
.rebase("http://different.host.com/api") // reset the BaseUrl
.build_request(Method::GET, "/path")?;
extends RequestBuilder
此包重新导出 RequestBuilder
从 reqwest-middleware
,并提供了一些有用的扩展。我们可以使用 req.with_extension()
来应用这些扩展。
RequestId
- 设置
X-Request-ID
的值
- 设置
TraceId
- 设置
X-Trace-ID
和/或X-Span-ID
的值
- 设置
MockServer
- 模拟服务器响应
send
宏
send
- 发送请求,不检测或处理有效载荷
send_json
- 发送带有 JSON 有效载荷的请求
send_xml
- 发送带有 XML 有效载荷的请求
send_form
- 发送带有 urlencoded 表单或 multipart 表单的请求
send_multipart
- 发送带有多部分表单的请求
这些宏支持以下表单。
// Form 1: send and parse response as JSON / XML
let _: Data = send!(req).await?;
// Form 2: send, drop response and return ApiResult<()>
send!(req, ()).await?;
// Form 3: send and return ResponseBody
let _ = send!(req, Body).await?;
// Form 4: send and parse JSON response to Data
let _: Data = send!(req, Json).await?;
// Form 5: send and parse XML response to Data
let _: Data = send!(req, Xml).await?;
// Form 6: send and parse Text response to Data by using FromStr trait
let _: Data = send!(req, Text).await?;
// Form 7: send and parse JSON response to Data
let _ = send!(req, Data).await?;
// Form 8: send and parse JSON response to Data
let _ = send!(req, Json<Data>).await?;
您可以检查 tests
获取更多示例。
依赖项
~11–24MB
~365K SLoC