22个版本 (6个稳定版本)
1.5.0 | 2024年5月6日 |
---|---|
1.4.0 | 2023年5月12日 |
1.3.0 | 2022年8月27日 |
1.2.0 | 2022年1月10日 |
0.1.1 | 2017年12月10日 |
在 HTTP客户端 中排名53
每月下载量1,607
被 6 个 库使用
47KB
704 代码行
Restson Rust
为Rust编程语言提供的易于使用的REST客户端,可以自动将Rust结构体进行序列化和反序列化。提供异步接口和同步调用的简单包装器。该库使用Hyper和Serde JSON实现。
入门指南
将以下行添加到您的项目中 Cargo.toml
文件
[dependencies]
restson = "^1.5"
serde = "^1.0"
serde_derive = "^1.0"
这将为Restson库添加依赖项,同时也为Serde添加依赖项,后者需要用于从用户定义的数据结构中派生出Serialize
和Deserialize
。
特性
特性 | 描述 | 默认 |
---|---|---|
阻塞 | 此选项启用对同步、阻塞、客户端的支持。当仅使用异步时,可以禁用此选项以移除不必要的依赖项。 | 是 |
lib-serde-json | 此选项启用Serde JSON解析器以处理GET请求。lib-simd-json的替代方案。 | 是 |
lib-simd-json | 此选项启用使用simd-json进行JSON解析,以处理GET请求。如果目标硬件支持SIMD,则此选项可以提高解析性能。lib-serde-json的替代方案。 | 否 |
native-tls | 此选项选择native_tls 作为TLS提供者。rustls的替代方案。 |
是 |
rustls | 此选项选择rustls 作为TLS提供者。native-tls的替代方案。 |
否 |
数据结构
接下来,应该定义REST接口的数据结构。结构体字段需要与API JSON字段匹配。不需要定义整个JSON,结构体也可以只包含字段子集。使用GET
的结构体应该派生Deserialize
,而使用POST
的结构体应该派生Serialize
。
示例JSON(http://httpbin.org/anything响应的子集)
{
"method": "GET",
"origin": "1.2.3.4",
"url": "https://httpbin.org/anything"
}
对应的Rust结构体
#[macro_use]
extern crate serde_derive;
#[derive(Serialize,Deserialize)]
struct HttpBinAnything {
method: String,
url: String,
}
这些定义允许在处理请求时自动将数据结构序列化/反序列化为JSON。对于更复杂的场景,请参阅Serde 示例。
REST路径
在Restson库中,API资源路径与类型相关联。也就是说,URL将自动构建,而不是作为请求参数提供。这允许轻松参数化路径,而无需手动处理URL,并减少代码中的URL字面量。
使用REST请求的每个类型都需要实现RestPath
特质。该特质可以对同一类型进行多次实现,使用不同的泛型参数,如下所示。`get_path
`还可以返回错误,表示参数无效。这个错误将直接传递给客户端调用者。
// plain API call without parameters
impl RestPath<()> for HttpBinAnything {
fn get_path(_: ()) -> Result<String,Error> { Ok(String::from("anything")) }
}
// API call with one u32 parameter (e.g. "http://httpbin.org/anything/1234")
impl RestPath<u32> for HttpBinAnything {
fn get_path(param: u32) -> Result<String,Error> { Ok(format!("anything/{}", param)) }
}
请求
要运行请求,首先需要创建客户端实例。客户端可以是异步的,可以与Rust async/await系统一起使用,也可以是同步的,它将在HTTP请求完成并直接返回值之前阻塞。资源的基本URL作为参数提供。
// async client
let async_client = RestClient::new("http://httpbin.org").unwrap();
// sync client
let client = RestClient::new_blocking("http://httpbin.org").unwrap();
这创建了一个具有默认配置的客户端实例。要配置客户端,需要使用一个Builder
。
// async client
let async_client = RestClient::builder().dns_workers(1)
.build("http://httpbin.org").unwrap();
// sync client
let client = RestClient::builder().dns_workers(1)
.blocking("http://httpbin.org").unwrap();
GET
以下代码片段展示了示例GET
请求。
// Gets https://httpbin.org/anything/1234 and deserializes the JSON to data variable
// (data is struct HttpBinAnything)
let data = client.get::<_, HttpBinAnything>(1234).unwrap();
请求函数会自动从RestPath
调用`get_path
`,从给定的参数构建URL。URL参数的类型(如上所示,编译器推断正确的类型)和返回的数据(`HttpBinAnything
`)在请求中进行了注释。
Restson还提供了`get_with
`函数,它与基本的`get
`类似,但它还接受额外的查询参数,这些参数会被添加到请求URL中。
// Gets http://httpbin.org/anything/1234?a=2&b=abcd
let query = vec![("a","2"), ("b","abcd")];
let data = client.get_with::<_, HttpBinAnything>((), &query).unwrap();
这两个GET接口都返回`Result<Response<T>, Error>
`,其中T是目标类型,返回的JSON将被反序列化到该类型。
POST
以下代码片段展示了示例POST
请求。
#[derive(Serialize)]
struct HttpBinPost {
data: String,
}
impl RestPath<()> for HttpBinPost {
fn get_path(_: ()) -> Result<String,Error> { Ok(String::from("post")) }
}
let data = HttpBinPost { data: String::from("test data")};
// Posts data to http://httpbin.org/post
client.post((), &data).unwrap();
除了基本的`post
`接口外,还可以使用`post_with
`函数提供查询参数。此外,`post_capture
`和`post_capture_with
`接口允许捕获和反序列化服务器在POST请求中返回的消息体(捕获请求需要在调用中添加类型注释)。
PUT
HTTP PUT请求也受支持,并且接口与POST接口类似:`put
`、`put_with
`、`put_capture
和`put_capture_with
`函数可用(捕获请求需要在调用中添加类型注释)。
PATCH
HTTP PATCH请求也受支持,并且接口与POST和PUT接口类似:`patch
`和`patch_with
`函数可用。
DELETE
Restson支持将HTTP DELETE请求发送到API路径。通常,DELETE请求会发送到API URL,不包含消息体。但是,如果需要消息体或查询参数,可以使用`delete_with
`。此外,虽然服务器向DELETE请求发送响应体的情况并不常见,但仍然可以使用`delete_capture
`和`delete_capture_with
`函数来捕获它。
与其他请求类似,路径是从`RestPath
`特质中获取的。
struct HttpBinDelete {
}
impl RestPath<()> for HttpBinDelete {
fn get_path(_: ()) -> Result<String,Error> { Ok(String::from("delete")) }
}
`delete
`函数不返回任何数据(只有可能的错误),因此需要对该类型进行注释。
// DELETE request to http://httpbin.org/delete
let client = RestClient::new_blocking("http://httpbin.org").unwrap();
client.delete::<(), HttpBinDelete>(()).unwrap();
并发请求
当使用异步客户端时,可以像下面这样同时运行多个请求
let client = RestClient::new("https://httpbin.org").unwrap();
// all three GET requests are done concurrently, and then joined
let (data1, data2, data3) = tokio::try_join!(
client.get::<_, HttpBinAnything>(1),
client.get::<_, HttpBinAnything>(2),
client.get::<_, HttpBinAnything>(3)
).unwrap();
具有数组根元素的JSON
在上面的所有示例中,JSON结构由键值对组成,可以用Rust结构体表示。然而,有效的JSON也可能具有没有键的数组根元素。例如,以下JSON是有效的。
["a","b","c"]
在Restson中,可以处理返回数组的API。然而,用户类型需要是一个容器,而不是结构体。例如,在这种情况下,类型需要是Vec<String>。此外,该类型还需要实现前面解释过的
RestPath
特质,最简单的方法是将容器包装在一个struct
中。
#[derive(Serialize,Deserialize,Debug,Clone)]
struct Products ( pub Vec<Product> );
#[derive(Serialize,Deserialize,Debug,Clone)]
pub struct Product {
pub name: String,
//...
}
impl RestPath<()> for Products {
fn get_path(_: ()) -> Result<String,Error> { Ok(String::from("/api/objects/products"))}
}
pub fn products(&self) -> Vec<Product> {
let client = RestClient::new_blocking("https://127.0.0.1:8080").unwrap();
client.get::<_, Products>(()).unwrap().0
}
相对路径
可以在基本URL中使用相对路径,以避免在get_path
实现中返回版本或其他前缀。例如,端点https://127.0.0.1:8080/api/v1/ep
可以通过将https://127.0.0.1:8080/api/v1/
设置为基本URL并从get_path
返回ep
来处理。注意:基本URL中的尾部斜杠很重要!如果没有它,在连接元素时,最后一个元素会被替换而不是添加(有关更多信息,请参阅此处)。
体清洗
对于某些API,在反序列化之前必须删除魔法值或其他清洁/处理返回的响应。可以使用set_body_wash_fn
提供自定义处理函数,在将其传递给反序列化步骤之前,它会使用原始返回体调用。
请求头
可以使用set_headers
向请求添加自定义头。这些头添加到所有后续的GET和POST请求中,直到它们被clear_headers
调用清除。
日志记录
库使用log
crate提供调试和跟踪日志。这些日志允许轻松地看到来自服务器的出站请求以及入站响应。有关详细信息,请参阅log crate文档。
示例
有关更多示例,请参阅tests目录。
迁移
迁移到v1.0
版本1.0添加了改变客户端主要界面的新功能,最显著的是异步支持。要将现有代码从0.x版本迁移,需要更新RestClient
创建。应使用RestClient::new_blocking
或RestClient::builder
().blocking("http://httpbin.org")来创建同步客户端。
迁移到v1.2
版本1.2允许使用不可变客户端进行请求。这具有允许并发请求等好处。然而,这也改变了服务器响应的返回方式,现在所有get
请求(以及其他捕获数据的请求)都需要类型注解。例如,以前let data: HttpBinAnything = client.get(1234).unwrap();
是允许的,但现在必须写成let data = client.get::<_, HttpBinAnything>(1234).unwrap();
。
许可证
库是根据MIT许可证发布的。有关详细信息,请参阅许可证。
依赖项
~7–20MB
~316K SLoC