Struct ApiRequest

Source
pub struct ApiRequest {
    pub api_path: String,
    pub body: Vec<u8>,
    pub query_params: HashMap<String, String>,
    pub path_params: HashMap<String, Vec<String>>,
    pub file: Vec<u8>,
    /* private fields */
}
Expand description

API请求的核心数据结构 - 命令模式的体现

ApiRequest 是整个SDK架构的核心,采用命令模式(Command Pattern)设计。 它封装了发起一次飞书API调用所需的所有信息,充当服务层(Service)与传输层(Transport)之间的桥梁。

§设计理念

  • 解耦性:服务层只负责构建请求,不关心HTTP细节
  • 统一性:所有API调用都通过这个统一的结构体表示
  • 灵活性:支持普通请求和multipart/form-data请求

§使用流程

  1. 服务层方法创建并配置 ApiRequest 实例
  2. 设置HTTP方法、路径、认证需求等基本信息
  3. 根据请求类型填充 body 和/或 file 字段
  4. 将配置好的请求传递给 Transport::request 进行处理

§示例

// 普通JSON请求
let mut api_req = ApiRequest {
    http_method: Method::POST,
    api_path: "/open-apis/drive/v1/files".to_string(),
    body: serde_json::to_vec(&request_data).unwrap(),
    ..Default::default()
};

// 文件上传请求(multipart)
let mut api_req = ApiRequest {
    http_method: Method::POST,
    api_path: "/open-apis/drive/v1/files/upload".to_string(),
    body: serde_json::to_vec(&metadata).unwrap(),  // JSON元数据
    file: file_bytes,  // 文件内容
    ..Default::default()
};

Fields§

§api_path: String

API的相对路径

例如:/open-apis/drive/v1/files/{file_id}

路径中的动态参数(如 {file_id})通常通过 format! 宏直接嵌入, 而不是使用 path_params 字段。

§body: Vec<u8>

请求体数据(序列化后的字节数组)

§在不同请求类型中的用途:

  • 普通请求:包含完整的请求体,通常是JSON序列化后的数据
  • 文件上传(multipart):仅包含JSON元数据部分,文件内容存储在 file 字段
  • 无请求体的请求:保持为空 Vec

§注意事项

服务层通常使用 serde_json::to_vec() 将请求结构体序列化到这个字段。

§query_params: HashMap<String, String>

URL查询参数

存储将被附加到URL末尾的查询参数。 例如:?page_size=10&page_token=xxx

§示例

api_req.query_params.insert("page_size".to_string(), "10".to_string());
api_req.query_params.insert("page_token".to_string(), token);
§path_params: HashMap<String, Vec<String>>

URL路径参数(当前未使用)

原设计意图可能是用于路径模板替换,如将 /files/{id} 中的 {id} 替换。 但当前实现中,路径参数都是通过 format! 宏直接嵌入到 api_path 中。

§TODO

考虑移除此字段或实现路径模板功能以保持设计一致性。

§file: Vec<u8>

文件内容(用于multipart/form-data请求)

§在不同请求类型中的用途:

  • 普通请求:保持为空 Vec
  • 文件上传(multipart):包含要上传的文件的二进制内容

§工作原理

file 字段非空时,Transport层会自动识别这是一个multipart请求:

  1. body 字段的内容作为multipart的JSON元数据部分
  2. file 字段的内容作为文件部分
  3. Content-Type自动设置为 multipart/form-data

§示例

// 文件上传请求
api_req.body = serde_json::to_vec(&FileMetadata {
    name: "document.pdf",
    parent_id: "folder123",
}).unwrap();
api_req.file = std::fs::read("path/to/document.pdf").unwrap();

Trait Implementations§

Source§

impl Clone for ApiRequest

Source§

fn clone(&self) -> ApiRequest

Returns a duplicate of the value. Read more
1.0.0 · Source§

const fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ApiRequest

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ApiRequest

Source§

fn default() -> ApiRequest

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,