openlark_platform/app_engine/apaas/v1/application/function/
invoke.rs1use 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#[derive(Debug, Clone)]
17pub struct FunctionInvokeRequestBuilder {
18 config: Config,
19 namespace: String,
21 function_api_name: String,
23 params: serde_json::Value,
25}
26
27impl FunctionInvokeRequestBuilder {
28 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 pub fn params(mut self, params: impl Into<serde_json::Value>) -> Self {
44 self.params = params.into();
45 self
46 }
47
48 pub async fn execute(self) -> SDKResult<FunctionInvokeResponse> {
50 self.execute_with_options(RequestOption::default()).await
51 }
52
53 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 let resp = Transport::request(req, &self.config, Some(option)).await?;
70 resp.data
71 .ok_or_else(|| openlark_core::error::validation_error("Operation", "响应数据为空"))
72 }
73}
74
75#[derive(Debug, Clone, Deserialize, Serialize)]
77struct FunctionInvokeRequest {
78 #[serde(rename = "params")]
80 params: serde_json::Value,
81}
82
83#[derive(Debug, Clone, Deserialize, Serialize)]
85pub struct FunctionInvokeResponse {
86 #[serde(rename = "result")]
88 pub result: serde_json::Value,
89 #[serde(rename = "status")]
91 pub status: String,
92 #[serde(rename = "message")]
94 pub message: String,
95}
96
97impl ApiResponseTrait for FunctionInvokeResponse {
98 fn data_format() -> ResponseFormat {
99 ResponseFormat::Data
100 }
101}
102
103#[deprecated(note = "renamed to FunctionInvokeRequestBuilder, will be removed in v1.0 (#271)")]
105pub type FunctionInvokeBuilder = FunctionInvokeRequestBuilder;
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[tokio::test]
113 async fn test_invoke_function_returns_data_on_success() {
114 use serde_json::json;
115 use wiremock::MockServer;
116 use wiremock::matchers::{method, path};
117 use wiremock::{Mock, ResponseTemplate};
118
119 let server = MockServer::start().await;
120 Mock::given(method("POST"))
121 .and(path(
122 "/open-apis/apaas/v1/applications/ns_test/functions/func_001/invoke",
123 ))
124 .respond_with(ResponseTemplate::new(200).set_body_json(json!({
125 "code": 0,
126 "msg": "success",
127 "data": {
128 "result": {"output": "ok"},
129 "status": "SUCCESS",
130 "message": "执行成功"
131 }
132 })))
133 .mount(&server)
134 .await;
135
136 let config = Config::builder()
137 .app_id("ci_app_id")
138 .app_secret("ci_app_secret")
139 .base_url(server.uri())
140 .enable_token_cache(false)
141 .build();
142
143 let resp = FunctionInvokeRequestBuilder::new(config, "ns_test", "func_001")
144 .params(json!({"arg": 1}))
145 .execute()
146 .await
147 .expect("执行函数应成功");
148 assert_eq!(resp.status, "SUCCESS");
149 assert_eq!(resp.message, "执行成功");
150 assert_eq!(resp.result["output"], "ok");
151
152 let received = server.received_requests().await.unwrap_or_default();
153 assert_eq!(received.len(), 1);
154 assert_eq!(
155 received[0].url.path(),
156 "/open-apis/apaas/v1/applications/ns_test/functions/func_001/invoke"
157 );
158 }
159}