1个不稳定版本

0.5.3 2023年4月22日

#344 in HTTP客户端


bangumi中使用

MIT 许可证

40KB
573

rustified

由于维护不足,rustified是rustify的分支。

一个用于与HTTP API端点交互的Rust库

rustified是一个用Rust编写的库,简化了搭建HTTP API的负担。它提供了一个Endpoint trait以及一个宏助手,允许模板化各种远程端点。提供了异步和同步客户端来执行针对端点的请求,并可选择实现自定义客户端,使用Client trait。

rustified支持请求序列化和响应反序列化。还支持以字节形式表示的原始请求和响应。该库还包含许多处理请求的助手,如中间件支持和包装API响应。

安装

将rustified添加到您的cargo.toml作为依赖项

[dependencies]
rustified = "0.5.3"
rustified_derive = "0.5.3"

使用方法

基本使用

use rustified::{Client, Endpoint};
use rustified_derive::Endpoint;

// Defines an API endpoint at /test/path that takes no inputs and returns an
// empty response.
#[derive(Endpoint)]
#[endpoint(path = "test/path")]
struct Test {}

let endpoint = Test {};
let client = Client::default("http://api.com"); // Configures base address of http://api.com
let result = endpoint.exec(&client).await; // Sends GET request to http://api.com/test/path

assert!(result.is_ok());

请求体

use derive_builder::Builder;
use rustified::{Client, Endpoint};
use rustified_derive::Endpoint;

// Defines an API endpoint at /test/path/{name} that takes one input for
// creating the url and two inputs for building the request body. The content
// type of the request body defaults to JSON, however, it can be modified by
// passing the `request_type` parameter to the endpoint configuration.
//
// Note: The `#[endpoint(body)]` attribute tags are technically optional in the
// below example. If no `body` attribute is found anywhere then rustified defaults
// to serializing all "untagged" fields as part of the body. Fields can be opted
// out of this behavior by tagging them with #[endpoint(skip)].
#[derive(Builder, Endpoint)]
#[endpoint(path = "test/path/{self.name}", method = "POST", builder = "true")]
#[builder(setter(into))] // Improves the building process
struct Test {
    #[endpoint(skip)] // This field shouldn't be serialized anywhere
    pub name: String, // Used to create a dynamic URL
    #[endpoint(body)] // Instructs rustified to serialize this field as part of the body
    pub age: i32,
    #[endpoint(body)]
    pub role: String,
}

// Setting `builder` to true creates a `builder()` method on our struct that
// returns the TestBuilder type created by `derive_builder`.
let endpoint = Test::builder()
        .name("George-Miao")
        .age(42)
        .role("CEO")
        .build()
        .unwrap();
let client = Client::default("http://api.com");
let result = endpoint.exec(&client).await; // Sends POST request to http://api.com/test/path/George-Miao

assert!(result.is_ok());

查询参数

use derive_builder::Builder;
use rustified::{Client, Endpoint};
use rustified_derive::Endpoint;

// Defines a similar API endpoint as in the previous example but adds an
// optional query parameter to the request. Additionally, this example opts to
// not specify the `#[endpoint(body)]` attributes to make use of the default
// behavior covered in the previous example.
#[derive(Builder, Endpoint)]
#[endpoint(path = "test/path/{self.name}", method = "POST", builder = "true")]
#[builder(setter(into, strip_option), default)] // Improves building process
struct Test {
    #[endpoint(skip)]
    pub name: String,
    #[endpoint(query)]
    pub scope: Option<String>, // Note: serialization is skipped when this field is None
    pub age: i32, // Serialized into the request body
    pub role: String, // Serialized into the request body
}

let endpoint = Test::builder()
        .name("George-Miao")
        .scope("global")
        .age(42)
        .role("CEO")
        .build()
        .unwrap();
let client = Client::default("http://api.com");
let result = endpoint.exec(&client).await; // Sends POST request to http://api.com/test/path/George-Miao?scope=global

assert!(result.is_ok());

响应

use rustified::{Client, Endpoint};
use rustified_derive::Endpoint;

// Defines an API endpoint at /test/path that takes a single byte array which
// will be used as the request body (no serialization occurs). The endpoint
// returns a `TestResponse` which contains the result of the operation.
#[derive(Endpoint)]
#[endpoint(path = "test/path", response = "TestResponse")]
struct Test {
    #[endpoint(raw)] // Indicates this field contains the raw request body
    pub file: Vec<u8>
}

#[derive(Deserialize)]
struct TestResponse {
    pub success: bool,
}

let endpoint = Test {
    file: b"contents".to_vec(),
};
let client = Client::default("http://api.com");
let result = endpoint.exec(&client).await;

assert!(result.is_ok());

let response = result.unwrap().parse().unwrap(); // Returns the parsed `TestResponse`
dbg!(response.success);

示例

您可以在示例目录中找到示例用法。它们可以用cargo运行

cargo run --package rustified --example reqres1
cargo run --package rustified --example reqres2

基于rustify构建的vaultrs crate是一个很好的参考。

功能

此crate提供以下功能

  • blocking:启用Client的阻塞变体以及Endpoint中的阻塞exec函数。

错误处理

本crate产生的所有错误都封装在crate提供的ClientError枚举中。

测试

有关测试,请参阅测试目录。使用cargo test运行测试。

依赖项

~6–24MB
~351K SLoC