Skip to main content

wechat_mp_sdk/api/
trait.rs

1//! WeChat API trait and context
2//!
3//! Provides the base trait and context for all WeChat API implementations.
4
5use std::sync::Arc;
6
7use serde::de::DeserializeOwned;
8use serde::Serialize;
9
10use crate::client::WechatClient;
11use crate::error::WechatError;
12use crate::token::TokenManager;
13
14/// Context holding shared resources for WeChat API implementations.
15///
16/// Contains references to the HTTP client and token manager that
17/// API implementations need to make requests.
18#[derive(Clone)]
19pub struct WechatContext {
20    /// The WeChat HTTP client for making API requests
21    pub(crate) client: Arc<WechatClient>,
22    /// The token manager for access token lifecycle
23    pub(crate) token_manager: Arc<TokenManager>,
24}
25
26impl std::fmt::Debug for WechatContext {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        f.debug_struct("WechatContext")
29            .field("client", &"WechatClient { .. }")
30            .field("token_manager", &"TokenManager { .. }")
31            .finish()
32    }
33}
34
35impl WechatContext {
36    /// Create a new WechatContext
37    pub fn new(client: Arc<WechatClient>, token_manager: Arc<TokenManager>) -> Self {
38        Self {
39            client,
40            token_manager,
41        }
42    }
43
44    /// Get a reference to the WeChat HTTP client.
45    pub fn client(&self) -> &WechatClient {
46        &self.client
47    }
48
49    /// Get a reference to the token manager.
50    pub fn token_manager(&self) -> &TokenManager {
51        &self.token_manager
52    }
53
54    pub(crate) async fn authed_get<T: DeserializeOwned>(
55        &self,
56        path: &str,
57        extra_query: &[(&str, &str)],
58    ) -> Result<T, WechatError> {
59        let token = self.token_manager.get_token().await?;
60        let authed_path = WechatClient::append_access_token(path, &token);
61        self.client.get(&authed_path, extra_query).await
62    }
63
64    pub(crate) async fn authed_post<T: DeserializeOwned, B: Serialize>(
65        &self,
66        path: &str,
67        body: &B,
68    ) -> Result<T, WechatError> {
69        let token = self.token_manager.get_token().await?;
70        let authed_path = WechatClient::append_access_token(path, &token);
71        self.client.post(&authed_path, body).await
72    }
73
74    pub(crate) async fn authed_post_raw<B: Serialize>(
75        &self,
76        path: &str,
77        body: &B,
78    ) -> Result<reqwest::Response, WechatError> {
79        let token = self.token_manager.get_token().await?;
80        let authed_path = WechatClient::append_access_token(path, &token);
81        let url = format!("{}{}", self.client.base_url(), &authed_path);
82        let request = self.client.http().post(&url).json(body).build()?;
83        Ok(self.client.send_request(request).await?)
84    }
85}
86
87/// Trait for WeChat API implementations.
88///
89/// All API modules should implement this trait to provide
90/// access to the shared context.
91pub trait WechatApi: Send + Sync {
92    /// Get a reference to the WeChat context
93    fn context(&self) -> &WechatContext;
94
95    /// Get the name of this API for logging and error context.
96    ///
97    /// Implementors should override this to return a descriptive name
98    /// (e.g., "auth", "user", "customer_service").
99    fn api_name(&self) -> &'static str {
100        "unknown"
101    }
102}