7个不稳定版本
0.4.0 | 2023年2月22日 |
---|---|
0.3.0 | 2021年8月14日 |
0.2.2 | 2021年8月11日 |
0.2.1 | 2021年6月27日 |
0.1.1 | 2021年5月12日 |
#178 in HTTP客户端
每月372次下载
用于 8 个 crate(5 个直接使用)
47KB
637 行
pretend
pretend
是一个模块化、受 Feign 启发的基于宏的 HTTP 客户端。其目标是解耦 REST API 的定义与实现。
一些功能
- 声明式
- 以异步为首要实现
- 与HTTP客户端无关
- 由于 serde 支持JSON
入门
通过注释一个 trait 来描述 REST API
use pretend::{pretend, request, Result};
#[pretend]
trait HttpBin {
#[request(method = "POST", path = "/anything")]
async fn post_anything(&self, body: &'static str) -> Result<String>;
}
在内部,pretend
会为 Pretend
实现这个 trait。可以通过传递客户端实现和 REST API 的基础 URL 来构建这个 struct 的实例。在下面的示例中,我们使用基于 reqwest
的客户端。
use pretend::{Pretend, Url};
use pretend_reqwest::Client;
#[tokio::main]
async fn main() {
let client = Client::default();
let url = Url::parse("https://httpbin.org").unwrap();
let pretend = Pretend::for_client(client).with_url(url);
let response = pretend.post_anything("hello").await.unwrap();
assert!(response.contains("hello"));
}
发送头信息、查询参数和正文
使用 header
作为属性提供头信息。
use pretend::{header, pretend, request, Result};
#[pretend]
trait HttpBin {
#[request(method = "GET", path = "/get")]
#[header(name = "X-Test-Header-1", value = "abc")]
#[header(name = "X-Test-Header-2", value = "other")]
async fn get_with_headers(&self, value: i32, custom: &str) -> Result<()>;
}
查询参数和正文作为方法参数提供。正文类型根据参数名称猜测
- 参数
body
将作为原始字节数据发送。这要求正文具有 'static 生命周期。 - 参数
form
将使用serde
序列为表单编码。 - 参数
json
将使用serde
序列为 JSON。
查询参数通过 query
参数传递。它也使用 serde
序列化。
use pretend::{pretend, request, Json, Result, Serialize};
#[derive(Serialize)]
struct Data {
value: i32,
}
#[pretend]
trait HttpBin {
#[request(method = "POST", path = "/anything")]
async fn post_bytes(&self, body: &'static [u8]) -> Result<()>;
#[request(method = "POST", path = "/anything")]
async fn post_string(&self, body: &'static str) -> Result<()>;
#[request(method = "POST", path = "/anything")]
async fn post_with_query_params(&self, query: &Data) -> Result<()>;
#[request(method = "POST", path = "/anything")]
async fn post_json(&self, json: &Data) -> Result<()>;
}
处理响应
pretend
支持广泛的各种响应类型,基于方法的返回类型。正文可以作为一个 Vec<u8>
、一个字符串或者通过使用 Json
包装器类型作为 JSON 返回。如果应该丢弃正文,也可以使用单元类型 ()
。
还提供了 JsonResult
作为便利类型。它将根据 HTTP 状态码反序列化为值类型或错误类型。
当仅检索主体时,HTTP错误会导致方法返回错误。可以通过将这些类型包装在Response
中,防止方法失败并访问HTTP状态码。这还允许访问响应头。
use pretend::{pretend, request, Deserialize, Json, JsonResult, Response, Result};
#[derive(Deserialize)]
struct Data {
value: i32,
}
#[derive(Deserialize)]
struct Error {
error: String,
}
#[pretend]
trait HttpBin {
#[request(method = "POST", path = "/anything")]
async fn read_bytes(&self) -> Result<Vec<u8>>;
#[request(method = "POST", path = "/anything")]
async fn read_string(&self) -> Result<String>;
#[request(method = "POST", path = "/anything")]
async fn read_json(&self) -> Result<Json<Data>>;
#[request(method = "POST", path = "/anything")]
async fn read_json_result(&self) -> Result<JsonResult<Data, Error>>;
#[request(method = "POST", path = "/anything")]
async fn read_status(&self) -> Result<Response<()>>;
}
模板化
请求路径和头支持模板化。花括号之间的值将被具有相同名称的参数替换。替换使用format!
进行,这意味着支持实现Display
的任何类型。
use pretend::{header, pretend, request, Deserialize, Json, Pretend, Result};
use pretend_reqwest::Client;
use std::collections::HashMap;
#[derive(Deserialize)]
struct Data {
url: String,
headers: HashMap<String, String>,
}
#[pretend]
trait HttpBin {
#[request(method = "POST", path = "/{path}")]
#[header(name = "X-{header}", value = "{value}$")]
async fn read(&self, path: &str, header: &str, value: i32) -> Result<Json<Data>>;
}
#[tokio::main]
async fn main() {
let client = Client::default();
let url = Url::parse("https://httpbin.org").unwrap();
let pretend = Pretend::for_client(client).with_url(url);
let response = pretend.read("anything", "My-Header", 123).await.unwrap();
let data = response.value();
assert_eq!(data.url, "https://httpbin.org/anything");
assert_eq!(*data.headers.get("X-My-Header").unwrap(), "123$".to_string());
}
文档
更多信息,请参阅API参考。
依赖项
~7–9.5MB
~262K SLoC