openlark_workflow/common/
api_utils.rs1use openlark_core::{SDKResult, error};
5
6const ERROR_COMPONENT: &str = "openlark-workflow";
7
8fn attach_standard_error_context(
9 err: openlark_core::error::CoreError,
10 operation: &str,
11 resource: &str,
12 request_id: Option<String>,
13) -> openlark_core::error::CoreError {
14 err.with_operation(operation, ERROR_COMPONENT)
15 .map_context(|ctx| {
16 ctx.add_context("resource", resource);
17 if let Some(request_id) = request_id.filter(|value| !value.trim().is_empty()) {
18 ctx.set_request_id(request_id);
19 }
20 })
21}
22
23pub fn missing_response_data_error(
25 resource: &str,
26 request_id: Option<String>,
27) -> openlark_core::error::CoreError {
28 attach_standard_error_context(
29 error::validation_error("response.data", "服务器没有返回有效的数据"),
30 "extract_response_data",
31 resource,
32 request_id,
33 )
34}
35
36pub fn request_serialization_error(
38 resource: &str,
39 source: impl std::fmt::Display,
40) -> openlark_core::error::CoreError {
41 attach_standard_error_context(
42 error::validation_error("request.params", format!("无法序列化请求参数: {source}")),
43 "serialize_params",
44 resource,
45 None,
46 )
47}
48
49pub fn extract_response_data<T>(
59 response: openlark_core::api::Response<T>,
60 context: &str,
61) -> SDKResult<T> {
62 response.data.ok_or_else(|| {
63 missing_response_data_error(context, response.raw_response.request_id.clone())
64 })
65}
66
67pub fn serialize_params<T: serde::Serialize>(
77 params: &T,
78 context: &str,
79) -> SDKResult<serde_json::Value> {
80 serde_json::to_value(params).map_err(|e| request_serialization_error(context, e))
81}
82
83#[macro_export]
97macro_rules! api_url {
98 ($base_url:expr) => {
99 $base_url.to_string()
100 };
101 ($base_url:expr, $($arg:expr),+) => {
102 format!($base_url, $($arg),+)
103 };
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use openlark_core::error::ErrorTrait;
110 use serde::Serialize;
111
112 #[derive(Serialize)]
113 struct TestParams {
114 name: String,
115 value: i32,
116 }
117
118 struct FailingParams;
119
120 impl Serialize for FailingParams {
121 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
122 where
123 S: serde::Serializer,
124 {
125 Err(serde::ser::Error::custom("boom"))
126 }
127 }
128
129 #[test]
130 fn test_serialize_params_success() {
131 let params = TestParams {
132 name: "test".to_string(),
133 value: 42,
134 };
135 let result = serialize_params(¶ms, "查询任务");
136 assert!(result.is_ok());
137 let json = result.expect("序列化参数应成功");
138 assert_eq!(json["name"], "test");
139 assert_eq!(json["value"], 42);
140 }
141
142 #[test]
143 fn test_serialize_params_adds_standard_error_context() {
144 let err = serialize_params(&FailingParams, "查询任务").unwrap_err();
145 assert_eq!(err.context().operation(), Some("serialize_params"));
146 assert_eq!(err.context().component(), Some(ERROR_COMPONENT));
147 assert_eq!(err.context().get_context("resource"), Some("查询任务"));
148 }
149
150 #[test]
151 fn test_extract_response_data_adds_request_id_and_resource_context() {
152 let response = openlark_core::api::Response::new(
153 None::<serde_json::Value>,
154 openlark_core::api::RawResponse {
155 request_id: Some("req-wf-123".to_string()),
156 ..Default::default()
157 },
158 );
159
160 let err = extract_response_data(response, "查询任务").unwrap_err();
161 assert_eq!(err.context().operation(), Some("extract_response_data"));
162 assert_eq!(err.context().component(), Some(ERROR_COMPONENT));
163 assert_eq!(err.context().get_context("resource"), Some("查询任务"));
164 assert_eq!(err.context().request_id(), Some("req-wf-123"));
165 }
166
167 #[test]
168 fn test_missing_response_data_error_reuses_standard_shape() {
169 let err = missing_response_data_error("审批任务查询", Some("req-wf-456".to_string()));
170 assert_eq!(err.context().operation(), Some("extract_response_data"));
171 assert_eq!(err.context().component(), Some(ERROR_COMPONENT));
172 assert_eq!(err.context().get_context("resource"), Some("审批任务查询"));
173 assert_eq!(err.context().request_id(), Some("req-wf-456"));
174 }
175}