ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深入解析 Metabase Embedding SDK 的 ActionExecuteError:useAction 错误处理的规范化类型与实战

深入解析 Metabase Embedding SDK 的 ActionExecuteError:useAction 错误处理的规范化类型与实战 深入解析 Metabase Embedding SDK 的 ActionExecuteErroruseAction 错误处理的规范化类型与实战【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabaseMetabase Embedding SDK 通过useAction钩子触发预置 Action 时任何非 2xx 响应都会被规范化为统一的ActionExecuteError类型写入钩子的error状态。本文以 ActionExecuteError.md 文档为主体结合仓库中的类型定义、错误适配器实现与单元测试完整讲解该类型的字段语义、底层构造链路以及在实际嵌入应用中如何正确读取与渲染错误信息帮助你在嵌入式数据应用中构建可靠、可诊断的 Action 错误处理。一、ActionExecuteError一次调用失败统一一种形状ActionExecuteError是useAction钩子暴露给调用方的公共错误类型。无论底层网络客户端抛出的是 HTTP 响应包装体、原生Error还是传输层异常SDK 都会把它们收敛为同一种可预测的结构让消费方无需任何类型断言即可直接读取字段。其类型定义如下来源types.tstype ActionExecuteError { data: { errors?: Recordstring, string; message?: string; }; isCancelled: boolean; status?: number; };钩子将error状态类型声明为ActionExecuteError | null见 use-action.ts 与 UseActionResult.md因此消费方可以零转换地直接读取字段const message error?.data?.message;这一设计有两个关键收益类型即契约调用方无需自行判断错误对象长什么样TS 会在编译期约束住所有可读字段不泄漏内部结构注释与实现均明确指出公共类型不得泄漏内部形状如via、cause、trace等诊断字段适配器会主动丢弃这些内部信息。二、属性详解PropertyType语义data{ errors?: Recordstring, string; message?: string; }错误负载主体包含面向用户的可读信息data.errors?Recordstring, string后端报告参数级校验失败时返回以参数 slug 为键、错误消息为值的字段级映射data.message?string对终端用户可操作的诊断信息是错误处理的核心字段isCancelledboolean是否为用户主动取消AbortError / DOMException abort消费方可据此忽略被取消的操作status?numberHTTP 状态码传输层失败离线、中止未收到 HTTP 响应时该字段缺失2.1 data.message面向用户的可操作诊断error.data.message是给终端用户看的核心信息。它会原样保留来自后端或数据库驱动器的原始文本包括校验错误、权限错误乃至 SQL 报错语句。官方指南在 actions.md 中特别强调不要用笼统的 Something went wrong 替换原始消息——原始 SQL / 校验 / 权限错误才是告诉用户如何修正输入的关键信息。由于 SQL 或驱动器错误的消息往往包含换行符与紧随其后的失败 SQL 语句渲染时必须使用white-space: pre-wrap样式pre元素即可否则span会把换行折叠成一整段难以阅读的文字。2.2 data.errors参数级校验失败与整体请求失败的分野error.data.errors是区分两类失败的关键参数级校验失败后端报告参数级校验失败时返回{ slug: message }形式的映射键与传给execute的参数 slug 一一对应slug 即 Action 编辑器中显示的参数名而非内部 UUID整体请求失败例如外键约束导致整条请求无法执行时errors为空的{}诊断信息全部集中在data.message例如{ message: Other rows refer to this row so it cannot be deleted., errors: {} }需要注意当后端完全没有返回errors时该字段会被省略而非置为{}——适配器只有在字段存在且形状合法对象且非数组时才透传因此用errors in error.data判断比依赖默认值更稳妥。2.3 statusHTTP 错误与传输层错误的分水岭status是可选字段4xx / 5xx 等 HTTP 层失败时存在可直接用于区分客户端错误与服务端错误离线、请求被中止等传输层失败时缺失因为根本没有收到 HTTP 响应。这一语义让调用方无需依赖消息文本即可判断错误的性质例如根据status是否为 5xx 决定是否重试。2.4 isCancelled把用户取消和真错误分开isCancelled为true表示该错误源于用户主动取消如AbortError或DOMException的 abort而不是请求真的失败。SDK 通过识别错误对象的名字name: AbortError或 DOM 异常类型来判断消费方可以据此静默忽略被取消的操作不向用户展示错误提示。三、错误从何而来useAction 的错误捕获链路理解ActionExecuteError的形状只是第一步更重要的是弄清它如何在运行时被构造出来。整条链路在 use-action.ts 中清晰可见const execute useCallback( async (parameters: TParameters): PromiseActionResultForKindTKind | null { if (actionId null || !reduxStore || !executeAction) { return null; } setIsExecuting(true); setError(null); try { const raw: ExecuteActionResult await executeAction(reduxStore)({ actionId, parameters, }); const next raw as ActionResultForKindTKind; setResult(next); return next; } catch (err) { const adapted toActionExecuteError(err); setError(adapted); setResult(null); throw adapted; } finally { setIsExecuting(false); } }, [actionId, executeAction, reduxStore], );要点有三双通道错误传播失败时适配后的错误对象既被写入error状态供渲染期消费又被重新throw供try/catch或await消费。所以即使不写try/catch渲染层也能通过error状态展示错误成功与失败互斥失败时setResult(null)成功时error已在请求前被清空避免状态残留不自动触发与查询类钩子不同useAction不会在挂载时自动执行必须由事件处理器显式调用executeactionId为null或 SDK 未初始化时直接解析为null不发请求。3.1 适配器 toActionExecuteError内部形状如何被清洗所有错误都先经过 to-action-execute-error.ts 这个公共 API 边界适配器。它的核心逻辑分两条路径路径一携带 HTTPstatus的响应api.request 抛出的包装体const message typeof data string ? data : typeof (data as { message?: unknown })?.message string ? (data as { message: string }).message : undefined;兼容两种响应体标准 JSON 错误体{ message: ... }以及 Metabase 部分端点如 Not found.直接返回的纯字符串体——字符串会被直接当作消息errors仅在存在且为合法对象非数组时透传内部诊断字段via、cause、trace等被全部丢弃绝不泄漏到公共 API。路径二无 status 的传输层 / 未知错误return { data: { message: error instanceof Error ? error.message : String(error) }, isCancelled: isAbort, };原生Error取其message字符串直接作为消息null/undefined则序列化为null/undefined且不输出status字段。此外无论哪条路径返回的永远是一个全新对象不保留原始引用避免调用方意外修改内部错误对象。isCancelled的判定复用metabase/api/client/errors的isAbortError/getErrorStatus工具见 to-action-execute-error.ts。四、实战在嵌入应用中渲染 Action 错误官方在 actions.md 的完整示例中给出了标准的错误渲染模式见 basic.tsx{/* [snippet error-render] */} {error ? ( pre style{{ whiteSpace: pre-wrap }} {error.data.message ?? Action failed.} /pre ) : null} {/* [endsnippet error-render] */}结合前文可以提炼出三条实战准则用error.data.message ?? 兜底文案展示message是可选字段必须提供兜底示例用Action failed.用white-space: pre-wrap保留换行SQL / 驱动器错误消息会包含换行与 SQL 语句普通span会将其折叠原样展示、不做美化替换原始错误消息才是用户修正输入的线索。如果需要更强的交互可以按status分派如 5xx 显示服务暂时不可用4xx 显示字段级errors映射并回填到表单对应字段并按isCancelled决定是否静默忽略。完整的useAction返回值execute、isExecuting、result、reset语义可参考 UseActionResult.md更多触发、参数与刷新数据的细节见 actions.md。五、行为验证单元测试锚定的契约ActionExecuteError的每种形状在仓库中都有对应的单元测试覆盖见 to-action-execute-error.unit.spec.ts这些用例就是该类型最精确的行为契约4xx / 5xx 归一化{ status: 403, data: { message: denied } }原样映射为{ status: 403, data: { message: denied }, isCancelled: false }500 状态被保留丢弃内部字段输入携带via/cause/trace/ 嵌套data时输出中这些字段全部不存在data中也不会泄漏status-code等内部键字段级 errors 透传errors: { discount: must be positive }被原样保留且与message共存即使没有messageerrors也会保留如{ message: undefined, errors: { id: required } }errors 省略规则响应体没有errors时输出不含该键errors为非对象如字符串时被忽略整体请求失败外键约束场景{ message: Other rows refer to this row so it cannot be deleted., errors: {} }原样透传传输层失败原生Error取其message且无status字符串、null、undefined分别序列化为对应文本无status字段的输入也被当作未知形状处理不输出status取消语义AbortError与DOMException(Aborted, AbortError)均被标记为isCancelled: true真值isCancelled会被强制转为布尔true缺失时默认false纯字符串响应体如 404 返回Not found.字符串直接作为data.message全新对象输出与输入不共享引用data子对象亦然。这些测试同时印证了公共类型不泄漏内部形状的工程决策——通过精确的字段白名单SDK 在保持调试信息完整的同时把错误面的复杂度完全封装在了适配器内部。六、与其他 API 的关系在 SDK 的类型体系中ActionExecuteError是useAction错误面的唯一公共类型与成功面形成完整闭环error状态类型为ActionExecuteError | null由 UseActionResult.md 定义成功面的result则由ActionResultForKindTKind按 Action 类型create/update/delete/bulk/sql判别缺省为AnyActionResult联合类型可通过key in result收窄——错误与成功两条路径在类型层面互不混淆该类型在 index.md 的 API 索引中与useAction、ActionKind、AnyActionResult等一并列出属于useAction类别下的公共 API 面。结语ActionExecuteError虽是一个不足 10 行的类型却承载了 SDK 错误处理的核心设计一条失败归一形状。掌握其message/errors/status/isCancelled的语义分野理解适配器对内部字段的清洗逻辑再配合white-space: pre-wrap的渲染规范即可在你的嵌入式应用中构建出既对用户友好、又对开发者可诊断的完整错误处理方案。【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进