#api-request #send-request #http-api #http-request #api-client #http

apisdk

为 Rust 编写 HTTP API 客户端提供的一个易于使用的 API 工具包

35 个版本

0.0.14-beta.12024 年 5 月 6 日
0.0.13 2024 年 2 月 23 日
0.0.10 2024 年 1 月 25 日
0.0.7 2023 年 12 月 29 日

#866 in 网络编程

MIT/Apache

145KB
3.5K SLoC

API SDK

英文简体中文

为 Rust 编写 HTTP API 客户端提供的一个易于使用的 API 工具包。

  • 基于 reqwest 来处理 HTTP 请求
  • 宏定义 API 和发送请求
  • 以 JSON / XML / 表单 / 多部分的形式发送请求
  • 通过 serde 解析响应
  • 支持 X-Request-IDX-Trace-ID/X-Span-ID
  • 更多定制能力
    • 提供 UrlRewriterDnsResolver 来自定义 URL 和 API 端点
    • 通过使用 ApiAuthenticator 设置 Authorization
    • 通过集成 reqwest-middleware 提供中间件
    • 使用 MockServer 模拟服务器响应
  • 变更日志

动机

当使用 reqwest 向服务器端发送 API 请求时,我们需要做一些常见的工作。包括设置认证信息、解析请求响应、处理异常、添加日志和跟踪信息等。

因此,我们通常开发一些辅助函数来实现上述功能。该 crate 的设计目的是简化这部分开发工作并提供一个通用的设计实现。

入门

安装

更新 Cargo.toml 以将此 crate 添加为依赖项。

[dependencies]
apisdk = { version = "0" }

此 crate 有几个功能

定义 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_apiapi_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

此包重新导出 RequestBuilderreqwest-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