Skip to main content

openlark_platform/app_engine/apaas/v1/application/function/
invoke.rs

1//! 执行函数
2//!
3//! 文档: <https://open.feishu.cn/document/apaas-v1/application-function/invoke>
4//! docPath: <https://open.feishu.cn/document/apaas-v1/application-function/invoke>
5
6use openlark_core::{
7    SDKResult,
8    api::{ApiRequest, ApiResponseTrait, ResponseFormat},
9    config::Config,
10    http::Transport,
11    req_option::RequestOption,
12};
13use serde::{Deserialize, Serialize};
14
15/// 执行函数 Builder
16#[derive(Debug, Clone)]
17pub struct FunctionInvokeRequestBuilder {
18    config: Config,
19    /// 应用命名空间
20    namespace: String,
21    /// 函数 API 名称
22    function_api_name: String,
23    /// 函数参数
24    params: serde_json::Value,
25}
26
27impl FunctionInvokeRequestBuilder {
28    /// 创建新的 Builder
29    pub fn new(
30        config: Config,
31        namespace: impl Into<String>,
32        function_api_name: impl Into<String>,
33    ) -> Self {
34        Self {
35            config,
36            namespace: namespace.into(),
37            function_api_name: function_api_name.into(),
38            params: serde_json::json!({}),
39        }
40    }
41
42    /// 设置函数参数
43    pub fn params(mut self, params: impl Into<serde_json::Value>) -> Self {
44        self.params = params.into();
45        self
46    }
47
48    /// 执行请求
49    pub async fn execute(self) -> SDKResult<FunctionInvokeResponse> {
50        self.execute_with_options(RequestOption::default()).await
51    }
52
53    /// 使用选项执行请求
54    pub async fn execute_with_options(
55        self,
56        option: RequestOption,
57    ) -> SDKResult<FunctionInvokeResponse> {
58        let url = format!(
59            "/open-apis/apaas/v1/applications/{}/functions/{}/invoke",
60            self.namespace, self.function_api_name
61        );
62
63        let request = FunctionInvokeRequest {
64            params: self.params,
65        };
66
67        let req: ApiRequest<FunctionInvokeResponse> =
68            ApiRequest::post(&url).body(serde_json::to_value(&request)?);
69        Transport::request_typed(req, &self.config, Some(option), "Operation").await
70    }
71}
72
73/// 执行函数请求
74#[derive(Debug, Clone, Deserialize, Serialize)]
75struct FunctionInvokeRequest {
76    /// 函数参数
77    #[serde(rename = "params")]
78    params: serde_json::Value,
79}
80
81/// 执行函数响应
82#[derive(Debug, Clone, Deserialize, Serialize)]
83pub struct FunctionInvokeResponse {
84    /// 执行结果
85    #[serde(rename = "result")]
86    pub result: serde_json::Value,
87    /// 执行状态
88    #[serde(rename = "status")]
89    pub status: String,
90    /// 结果消息
91    #[serde(rename = "message")]
92    pub message: String,
93}
94
95impl ApiResponseTrait for FunctionInvokeResponse {
96    fn data_format() -> ResponseFormat {
97        ResponseFormat::Data
98    }
99}
100
101/// 旧名兼容别名(将在 v1.0 移除)
102#[deprecated(note = "renamed to FunctionInvokeRequestBuilder, will be removed in v1.0 (#271)")]
103pub type FunctionInvokeBuilder = FunctionInvokeRequestBuilder;
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    /// 端到端:POST .../functions/{api_name}/invoke → 强类型 FunctionInvokeResponse。
110    #[tokio::test]
111    async fn test_invoke_function_returns_data_on_success() {
112        use serde_json::json;
113        use wiremock::MockServer;
114        use wiremock::matchers::{method, path};
115        use wiremock::{Mock, ResponseTemplate};
116
117        let server = MockServer::start().await;
118        Mock::given(method("POST"))
119            .and(path(
120                "/open-apis/apaas/v1/applications/ns_test/functions/func_001/invoke",
121            ))
122            .respond_with(ResponseTemplate::new(200).set_body_json(json!({
123                "code": 0,
124                "msg": "success",
125                "data": {
126                    "result": {"output": "ok"},
127                    "status": "SUCCESS",
128                    "message": "执行成功"
129                }
130            })))
131            .mount(&server)
132            .await;
133
134        let config = Config::builder()
135            .app_id("ci_app_id")
136            .app_secret("ci_app_secret")
137            .base_url(server.uri())
138            .enable_token_cache(false)
139            .build();
140
141        let resp = FunctionInvokeRequestBuilder::new(config, "ns_test", "func_001")
142            .params(json!({"arg": 1}))
143            .execute()
144            .await
145            .expect("执行函数应成功");
146        assert_eq!(resp.status, "SUCCESS");
147        assert_eq!(resp.message, "执行成功");
148        assert_eq!(resp.result["output"], "ok");
149
150        let received = server.received_requests().await.unwrap_or_default();
151        assert_eq!(received.len(), 1);
152        assert_eq!(
153            received[0].url.path(),
154            "/open-apis/apaas/v1/applications/ns_test/functions/func_001/invoke"
155        );
156    }
157}