#rest-client #async-client #http-request #async-http #rest #client

restson

易于使用的REST客户端,具有自动序列化和反序列化功能

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

Download history 242/week @ 2024-05-01 140/week @ 2024-05-08 166/week @ 2024-05-15 244/week @ 2024-05-22 374/week @ 2024-05-29 356/week @ 2024-06-05 190/week @ 2024-06-12 266/week @ 2024-06-19 219/week @ 2024-06-26 267/week @ 2024-07-03 367/week @ 2024-07-10 412/week @ 2024-07-17 436/week @ 2024-07-24 561/week @ 2024-07-31 287/week @ 2024-08-07 260/week @ 2024-08-14

每月下载量1,607
6 个 库使用

MIT许可

47KB
704 代码行

crates.io License: MIT Docs: latest

Restson Rust

为Rust编程语言提供的易于使用的REST客户端,可以自动将Rust结构体进行序列化和反序列化。提供异步接口和同步调用的简单包装器。该库使用HyperSerde JSON实现。

入门指南

将以下行添加到您的项目中 Cargo.toml 文件

[dependencies]
restson = "^1.5"
serde = "^1.0"
serde_derive = "^1.0"

这将为Restson库添加依赖项,同时也为Serde添加依赖项,后者需要用于从用户定义的数据结构中派生出SerializeDeserialize

特性

特性 描述 默认
阻塞 此选项启用对同步、阻塞、客户端的支持。当仅使用异步时,可以禁用此选项以移除不必要的依赖项。
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_blockingRestClient::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