Skip to main content

openlark_docs/common/api_endpoints/
bitable.rs

1//! Bitable API V1 端点枚举
2//!
3//! 提供 Bitable v1 的端点定义,支持 method、path 和认证要求的统一管理(#439 迁移)。
4//! 从 api_endpoints.rs 提取为独立子模块,避免主文件持续膨胀。
5
6use super::CatalogEndpoint;
7use openlark_core::api::{ApiRequest, HttpMethod};
8
9/// Bitable API V1 端点枚举(#424 深化了请求语义:method + path + auth 在此集中)。
10#[derive(Debug, Clone, PartialEq)]
11#[cfg_attr(test, derive(strum_macros::EnumIter))]
12pub enum BitableApiV1 {
13    /// App管理相关
14    AppCreate,
15    /// 复制多维表格应用(参数:app_token)
16    AppCopy(String),
17    /// 获取多维表格应用信息(参数:app_token)
18    AppGet(String),
19    /// 更新多维表格应用信息(参数:app_token)
20    AppUpdate(String),
21    /// 列出多维表格仪表盘(参数:app_token)
22    DashboardList(String),
23    /// 复制仪表盘(参数:app_token, block_id)
24    DashboardCopy(String, String),
25    /// 自动化流程
26    BlockWorkflowList(String),
27    /// 列出自动化工作流(参数:app_token)
28    WorkflowList(String),
29    /// 更新自动化工作流(参数:app_token, workflow_id)
30    WorkflowUpdate(String, String),
31
32    /// 表格管理相关
33    TableCreate(String),
34    /// 批量创建数据表(参数:app_token)
35    TableBatchCreate(String),
36    /// 更新数据表(参数:app_token, table_id)
37    TableUpdate(String, String),
38    /// 删除数据表(参数:app_token, table_id)
39    TableDelete(String, String),
40    /// 批量删除数据表(参数:app_token)
41    TableBatchDelete(String),
42    /// 获取数据表信息(参数:app_token, table_id)
43    TableGet(String, String),
44    /// 列出数据表(参数:app_token)
45    TableList(String),
46    /// 增量更新数据表(参数:app_token, table_id)
47    TablePatch(String, String),
48
49    /// 字段管理相关
50    FieldCreate(String, String),
51    /// 创建字段分组(参数:app_token, table_id)
52    FieldGroupCreate(String, String),
53    /// 更新字段(参数:app_token, table_id, field_id)
54    FieldUpdate(String, String, String),
55    /// 删除字段(参数:app_token, table_id, field_id)
56    FieldDelete(String, String, String),
57    /// 列出字段(参数:app_token, table_id)
58    FieldList(String, String),
59
60    /// 视图管理相关
61    ViewCreate(String, String),
62    /// 更新视图(参数:app_token, table_id, view_id)
63    ViewUpdate(String, String, String),
64    /// 删除视图(参数:app_token, table_id, view_id)
65    ViewDelete(String, String, String),
66    /// 获取视图(参数:app_token, table_id, view_id)
67    ViewGet(String, String, String),
68    /// 列出视图(参数:app_token, table_id)
69    ViewList(String, String),
70    /// 增量更新视图(参数:app_token, table_id, view_id)
71    ViewPatch(String, String, String),
72
73    /// 记录管理相关
74    RecordCreate(String, String),
75    /// 批量创建记录(参数:app_token, table_id)
76    RecordBatchCreate(String, String),
77    /// 获取记录(参数:app_token, table_id, record_id)
78    RecordGet(String, String, String),
79    /// 批量获取记录(参数:app_token, table_id)
80    RecordBatchGet(String, String),
81    /// 更新记录(参数:app_token, table_id, record_id)
82    RecordUpdate(String, String, String),
83    /// 批量更新记录(参数:app_token, table_id)
84    RecordBatchUpdate(String, String),
85    /// 删除记录(参数:app_token, table_id, record_id)
86    RecordDelete(String, String, String),
87    /// 批量删除记录(参数:app_token, table_id)
88    RecordBatchDelete(String, String),
89    /// 列出记录(参数:app_token, table_id)
90    RecordList(String, String),
91    /// 查询记录(参数:app_token, table_id)
92    RecordSearch(String, String),
93
94    /// 表单管理相关
95    FormGet(String, String, String),
96    /// 更新表单(参数:app_token, table_id, form_id)
97    FormPatch(String, String, String),
98    /// 升级表单(参数:app_token, table_id, form_id)
99    FormUpgrade(String, String, String),
100    /// 列出表单字段(参数:app_token, table_id, form_id)
101    FormFieldList(String, String, String),
102    /// 更新表单字段(参数:app_token, table_id, form_id, field_id)
103    FormFieldPatch(String, String, String, String),
104
105    /// 权限管理相关
106    RoleCreate(String),
107    /// 更新自定义角色(参数:app_token, role_id)
108    RoleUpdate(String, String),
109    /// 删除自定义角色(参数:app_token, role_id)
110    RoleDelete(String, String),
111    /// 列出自定义角色(参数:app_token)
112    RoleList(String),
113    /// 新增角色成员(参数:app_token, role_id)
114    RoleMemberCreate(String, String),
115    /// 批量新增角色成员(参数:app_token, role_id)
116    RoleMemberBatchCreate(String, String),
117    /// 删除角色成员(参数:app_token, role_id, member_id)
118    RoleMemberDelete(String, String, String),
119    /// 批量删除角色成员(参数:app_token, role_id)
120    RoleMemberBatchDelete(String, String),
121    /// 列出角色成员(参数:app_token, role_id)
122    RoleMemberList(String, String),
123}
124
125impl BitableApiV1 {
126    /// 生成对应的 URL
127    pub fn to_url(&self) -> String {
128        match self {
129            // App管理
130            BitableApiV1::AppCreate => "/open-apis/bitable/v1/apps".to_string(),
131            BitableApiV1::AppCopy(app_token) => {
132                format!("/open-apis/bitable/v1/apps/{app_token}/copy")
133            }
134            BitableApiV1::AppGet(app_token) => {
135                format!("/open-apis/bitable/v1/apps/{app_token}")
136            }
137            BitableApiV1::AppUpdate(app_token) => {
138                format!("/open-apis/bitable/v1/apps/{app_token}")
139            }
140            BitableApiV1::DashboardList(app_token) => {
141                format!("/open-apis/bitable/v1/apps/{app_token}/dashboards")
142            }
143            BitableApiV1::DashboardCopy(app_token, block_id) => {
144                format!("/open-apis/bitable/v1/apps/{app_token}/dashboards/{block_id}/copy")
145            }
146            BitableApiV1::BlockWorkflowList(app_token) => {
147                format!("/open-apis/bitable/v1/apps/{app_token}/block_workflows")
148            }
149            BitableApiV1::WorkflowList(app_token) => {
150                format!("/open-apis/bitable/v1/apps/{app_token}/workflows")
151            }
152            BitableApiV1::WorkflowUpdate(app_token, workflow_id) => {
153                format!("/open-apis/bitable/v1/apps/{app_token}/workflows/{workflow_id}")
154            }
155
156            // 表格管理
157            BitableApiV1::TableCreate(app_token) => {
158                format!("/open-apis/bitable/v1/apps/{app_token}/tables")
159            }
160            BitableApiV1::TableBatchCreate(app_token) => {
161                format!("/open-apis/bitable/v1/apps/{app_token}/tables/batch_create")
162            }
163            BitableApiV1::TableUpdate(app_token, table_id) => {
164                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}")
165            }
166            BitableApiV1::TableDelete(app_token, table_id) => {
167                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}")
168            }
169            BitableApiV1::TableBatchDelete(app_token) => {
170                format!("/open-apis/bitable/v1/apps/{app_token}/tables/batch_delete")
171            }
172            BitableApiV1::TableGet(app_token, table_id) => {
173                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}")
174            }
175            BitableApiV1::TableList(app_token) => {
176                format!("/open-apis/bitable/v1/apps/{app_token}/tables")
177            }
178            BitableApiV1::TablePatch(app_token, table_id) => {
179                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}")
180            }
181
182            // 字段管理
183            BitableApiV1::FieldCreate(app_token, table_id) => {
184                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/fields")
185            }
186            BitableApiV1::FieldGroupCreate(app_token, table_id) => {
187                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/field_groups")
188            }
189            BitableApiV1::FieldUpdate(app_token, table_id, field_id) => {
190                format!(
191                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/fields/{field_id}"
192                )
193            }
194            BitableApiV1::FieldDelete(app_token, table_id, field_id) => {
195                format!(
196                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/fields/{field_id}"
197                )
198            }
199            BitableApiV1::FieldList(app_token, table_id) => {
200                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/fields")
201            }
202
203            // 视图管理
204            BitableApiV1::ViewCreate(app_token, table_id) => {
205                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views")
206            }
207            BitableApiV1::ViewUpdate(app_token, table_id, view_id) => {
208                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views/{view_id}")
209            }
210            BitableApiV1::ViewDelete(app_token, table_id, view_id) => {
211                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views/{view_id}")
212            }
213            BitableApiV1::ViewGet(app_token, table_id, view_id) => {
214                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views/{view_id}")
215            }
216            BitableApiV1::ViewList(app_token, table_id) => {
217                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views")
218            }
219            BitableApiV1::ViewPatch(app_token, table_id, view_id) => {
220                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/views/{view_id}")
221            }
222
223            // 记录管理
224            BitableApiV1::RecordCreate(app_token, table_id) => {
225                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records")
226            }
227            BitableApiV1::RecordBatchCreate(app_token, table_id) => {
228                format!(
229                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_create"
230                )
231            }
232            BitableApiV1::RecordGet(app_token, table_id, record_id) => {
233                format!(
234                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
235                )
236            }
237            BitableApiV1::RecordBatchGet(app_token, table_id) => {
238                format!(
239                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_get"
240                )
241            }
242            BitableApiV1::RecordUpdate(app_token, table_id, record_id) => {
243                format!(
244                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
245                )
246            }
247            BitableApiV1::RecordBatchUpdate(app_token, table_id) => {
248                format!(
249                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_update"
250                )
251            }
252            BitableApiV1::RecordDelete(app_token, table_id, record_id) => {
253                format!(
254                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
255                )
256            }
257            BitableApiV1::RecordBatchDelete(app_token, table_id) => {
258                format!(
259                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_delete"
260                )
261            }
262            BitableApiV1::RecordList(app_token, table_id) => {
263                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records")
264            }
265            BitableApiV1::RecordSearch(app_token, table_id) => {
266                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search")
267            }
268
269            // 表单管理
270            BitableApiV1::FormGet(app_token, table_id, form_id) => {
271                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/forms/{form_id}")
272            }
273            BitableApiV1::FormPatch(app_token, table_id, form_id) => {
274                format!("/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/forms/{form_id}")
275            }
276            BitableApiV1::FormUpgrade(app_token, table_id, form_id) => {
277                format!(
278                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/forms/{form_id}/upgrade"
279                )
280            }
281            BitableApiV1::FormFieldList(app_token, table_id, form_id) => {
282                format!(
283                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/forms/{form_id}/fields"
284                )
285            }
286            BitableApiV1::FormFieldPatch(app_token, table_id, form_id, field_id) => {
287                format!(
288                    "/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/forms/{form_id}/fields/{field_id}"
289                )
290            }
291
292            // 权限管理
293            BitableApiV1::RoleCreate(app_token) => {
294                format!("/open-apis/bitable/v1/apps/{app_token}/roles")
295            }
296            BitableApiV1::RoleUpdate(app_token, role_id) => {
297                format!("/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}")
298            }
299            BitableApiV1::RoleDelete(app_token, role_id) => {
300                format!("/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}")
301            }
302            BitableApiV1::RoleList(app_token) => {
303                format!("/open-apis/bitable/v1/apps/{app_token}/roles")
304            }
305            BitableApiV1::RoleMemberCreate(app_token, role_id) => {
306                format!("/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}/members")
307            }
308            BitableApiV1::RoleMemberBatchCreate(app_token, role_id) => {
309                format!(
310                    "/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}/members/batch_create"
311                )
312            }
313            BitableApiV1::RoleMemberDelete(app_token, role_id, member_id) => {
314                format!(
315                    "/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}/members/{member_id}"
316                )
317            }
318            BitableApiV1::RoleMemberBatchDelete(app_token, role_id) => {
319                format!(
320                    "/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}/members/batch_delete"
321                )
322            }
323            BitableApiV1::RoleMemberList(app_token, role_id) => {
324                format!("/open-apis/bitable/v1/apps/{app_token}/roles/{role_id}/members")
325            }
326        }
327    }
328
329    /// 返回配置了正确 HTTP 方法的 ApiRequest(委托到 CatalogEndpoint trait)。
330    pub fn to_request<R>(&self) -> ApiRequest<R> {
331        <Self as CatalogEndpoint>::to_request(self)
332    }
333}
334
335impl CatalogEndpoint for BitableApiV1 {
336    fn to_url(&self) -> String {
337        // delegate to inherent for backward compat
338        BitableApiV1::to_url(self)
339    }
340
341    fn method(&self) -> HttpMethod {
342        match self {
343            // App 管理
344            BitableApiV1::AppCreate => HttpMethod::Post,
345            BitableApiV1::AppCopy(_) => HttpMethod::Post,
346            BitableApiV1::AppGet(_) => HttpMethod::Get,
347            BitableApiV1::AppUpdate(_) => HttpMethod::Put,
348            BitableApiV1::DashboardList(_) => HttpMethod::Get,
349            BitableApiV1::DashboardCopy(_, _) => HttpMethod::Post,
350            BitableApiV1::BlockWorkflowList(_) => HttpMethod::Get,
351            BitableApiV1::WorkflowList(_) => HttpMethod::Get,
352            BitableApiV1::WorkflowUpdate(_, _) => HttpMethod::Put,
353
354            // 表格管理
355            BitableApiV1::TableCreate(_) => HttpMethod::Post,
356            BitableApiV1::TableBatchCreate(_) => HttpMethod::Post,
357            BitableApiV1::TableUpdate(_, _) => HttpMethod::Put,
358            BitableApiV1::TableDelete(_, _) => HttpMethod::Delete,
359            BitableApiV1::TableBatchDelete(_) => HttpMethod::Post,
360            BitableApiV1::TableGet(_, _) => HttpMethod::Get,
361            BitableApiV1::TableList(_) => HttpMethod::Get,
362            BitableApiV1::TablePatch(_, _) => HttpMethod::Patch,
363
364            // 字段管理
365            BitableApiV1::FieldCreate(_, _) => HttpMethod::Post,
366            BitableApiV1::FieldGroupCreate(_, _) => HttpMethod::Post,
367            BitableApiV1::FieldUpdate(_, _, _) => HttpMethod::Put,
368            BitableApiV1::FieldDelete(_, _, _) => HttpMethod::Delete,
369            BitableApiV1::FieldList(_, _) => HttpMethod::Get,
370
371            // 视图管理
372            BitableApiV1::ViewCreate(_, _) => HttpMethod::Post,
373            BitableApiV1::ViewUpdate(_, _, _) => HttpMethod::Put,
374            BitableApiV1::ViewDelete(_, _, _) => HttpMethod::Delete,
375            BitableApiV1::ViewGet(_, _, _) => HttpMethod::Get,
376            BitableApiV1::ViewList(_, _) => HttpMethod::Get,
377            BitableApiV1::ViewPatch(_, _, _) => HttpMethod::Patch,
378
379            // 记录管理
380            BitableApiV1::RecordCreate(_, _) => HttpMethod::Post,
381            BitableApiV1::RecordBatchCreate(_, _) => HttpMethod::Post,
382            BitableApiV1::RecordGet(_, _, _) => HttpMethod::Get,
383            BitableApiV1::RecordBatchGet(_, _) => HttpMethod::Post,
384            BitableApiV1::RecordUpdate(_, _, _) => HttpMethod::Put,
385            BitableApiV1::RecordBatchUpdate(_, _) => HttpMethod::Post,
386            BitableApiV1::RecordDelete(_, _, _) => HttpMethod::Delete,
387            BitableApiV1::RecordBatchDelete(_, _) => HttpMethod::Post,
388            BitableApiV1::RecordList(_, _) => HttpMethod::Get,
389            BitableApiV1::RecordSearch(_, _) => HttpMethod::Post,
390
391            // 表单管理
392            BitableApiV1::FormGet(_, _, _) => HttpMethod::Get,
393            BitableApiV1::FormPatch(_, _, _) => HttpMethod::Patch,
394            BitableApiV1::FormUpgrade(_, _, _) => HttpMethod::Post,
395            BitableApiV1::FormFieldList(_, _, _) => HttpMethod::Get,
396            BitableApiV1::FormFieldPatch(_, _, _, _) => HttpMethod::Patch,
397
398            // 权限/角色管理
399            BitableApiV1::RoleCreate(_) => HttpMethod::Post,
400            BitableApiV1::RoleUpdate(_, _) => HttpMethod::Put,
401            BitableApiV1::RoleDelete(_, _) => HttpMethod::Delete,
402            BitableApiV1::RoleList(_) => HttpMethod::Get,
403            BitableApiV1::RoleMemberCreate(_, _) => HttpMethod::Post,
404            BitableApiV1::RoleMemberBatchCreate(_, _) => HttpMethod::Post,
405            BitableApiV1::RoleMemberDelete(_, _, _) => HttpMethod::Delete,
406            BitableApiV1::RoleMemberBatchDelete(_, _) => HttpMethod::Post,
407            BitableApiV1::RoleMemberList(_, _) => HttpMethod::Get,
408        }
409    }
410
411    // to_request 和 supported_access_token_types 使用 trait 默认实现
412}
413
414#[cfg(test)]
415mod tests {
416    use super::*;
417    use crate::common::api_endpoints::test_support::{
418        assert_endpoint_semantics, catalog_semantics_snapshot,
419    };
420
421    #[test]
422    fn bitable_catalog_semantics_snapshot() {
423        insta::assert_snapshot!(catalog_semantics_snapshot::<BitableApiV1>());
424    }
425
426    #[test]
427    fn test_bitable_api_v1_app_create() {
428        let endpoint = BitableApiV1::AppCreate;
429        assert_eq!(endpoint.to_url(), "/open-apis/bitable/v1/apps");
430    }
431
432    #[test]
433    fn test_bitable_api_v1_app_copy() {
434        let endpoint = BitableApiV1::AppCopy("app_token_123".to_string());
435        assert_eq!(
436            endpoint.to_url(),
437            "/open-apis/bitable/v1/apps/app_token_123/copy"
438        );
439    }
440
441    #[test]
442    fn test_bitable_api_v1_table_create() {
443        let endpoint = BitableApiV1::TableCreate("app_token_123".to_string());
444        assert_eq!(
445            endpoint.to_url(),
446            "/open-apis/bitable/v1/apps/app_token_123/tables"
447        );
448    }
449
450    #[test]
451    fn test_bitable_api_v1_record_create() {
452        let endpoint =
453            BitableApiV1::RecordCreate("app_token_123".to_string(), "table_id_456".to_string());
454        assert_eq!(
455            endpoint.to_url(),
456            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/records"
457        );
458    }
459
460    #[test]
461    fn test_bitable_api_v1_field_create() {
462        let endpoint =
463            BitableApiV1::FieldCreate("app_token_123".to_string(), "table_id_456".to_string());
464        assert_eq!(
465            endpoint.to_url(),
466            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/fields"
467        );
468    }
469
470    #[test]
471    fn test_bitable_api_v1_block_workflow_list() {
472        let endpoint = BitableApiV1::BlockWorkflowList("app_token_123".to_string());
473        assert_eq!(
474            endpoint.to_url(),
475            "/open-apis/bitable/v1/apps/app_token_123/block_workflows"
476        );
477    }
478
479    #[test]
480    fn test_bitable_api_v1_field_group_create() {
481        let endpoint =
482            BitableApiV1::FieldGroupCreate("app_token_123".to_string(), "table_id_456".to_string());
483        assert_eq!(
484            endpoint.to_url(),
485            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/field_groups"
486        );
487    }
488
489    #[test]
490    fn test_bitable_api_v1_form_upgrade() {
491        let endpoint = BitableApiV1::FormUpgrade(
492            "app_token_123".to_string(),
493            "table_id_456".to_string(),
494            "form_id_789".to_string(),
495        );
496        assert_eq!(
497            endpoint.to_url(),
498            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/forms/form_id_789/upgrade"
499        );
500    }
501
502    #[test]
503    fn test_bitable_api_v1_view_create() {
504        let endpoint =
505            BitableApiV1::ViewCreate("app_token_123".to_string(), "table_id_456".to_string());
506        assert_eq!(
507            endpoint.to_url(),
508            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/views"
509        );
510    }
511
512    #[test]
513    fn test_bitable_api_v1_form_get() {
514        let endpoint = BitableApiV1::FormGet(
515            "app_token_123".to_string(),
516            "table_id_456".to_string(),
517            "form_id_789".to_string(),
518        );
519        assert_eq!(
520            endpoint.to_url(),
521            "/open-apis/bitable/v1/apps/app_token_123/tables/table_id_456/forms/form_id_789"
522        );
523    }
524
525    #[test]
526    fn test_bitable_api_v1_role_member_create() {
527        let endpoint =
528            BitableApiV1::RoleMemberCreate("app_token_123".to_string(), "role_id_456".to_string());
529        assert_eq!(
530            endpoint.to_url(),
531            "/open-apis/bitable/v1/apps/app_token_123/roles/role_id_456/members"
532        );
533    }
534
535    #[test]
536    fn test_bitable_api_v1_batch_operations() {
537        let endpoint = BitableApiV1::TableBatchCreate("app_token_123".to_string());
538        assert!(endpoint.to_url().contains("batch_create"));
539
540        let endpoint = BitableApiV1::RecordBatchDelete(
541            "app_token_123".to_string(),
542            "table_id_456".to_string(),
543        );
544        assert!(endpoint.to_url().contains("batch_delete"));
545    }
546
547    // ========== #424 / #439: 端点目录语义测试(method + path + auth) ==========
548    #[test]
549    fn test_bitable_record_endpoints_semantics_424() {
550        assert_endpoint_semantics(
551            BitableApiV1::RecordCreate("app".into(), "tbl".into()),
552            HttpMethod::Post,
553            "/open-apis/bitable/v1/apps/app/tables/tbl/records",
554        );
555        assert_endpoint_semantics(
556            BitableApiV1::RecordGet("app".into(), "tbl".into(), "rec".into()),
557            HttpMethod::Get,
558            "/open-apis/bitable/v1/apps/app/tables/tbl/records/rec",
559        );
560        assert_endpoint_semantics(
561            BitableApiV1::RecordUpdate("app".into(), "tbl".into(), "rec".into()),
562            HttpMethod::Put,
563            "/open-apis/bitable/v1/apps/app/tables/tbl/records/rec",
564        );
565        assert_endpoint_semantics(
566            BitableApiV1::RecordDelete("app".into(), "tbl".into(), "rec".into()),
567            HttpMethod::Delete,
568            "/open-apis/bitable/v1/apps/app/tables/tbl/records/rec",
569        );
570        assert_endpoint_semantics(
571            BitableApiV1::RecordSearch("app".into(), "tbl".into()),
572            HttpMethod::Post,
573            "/open-apis/bitable/v1/apps/app/tables/tbl/records/search",
574        );
575    }
576}