Dagger TypeScript SDK ErrorValue 类完全指南:结构化错误附加值的读取与类型体系
2026/9/14 17:55:19 网站建设 项目流程

Dagger TypeScript SDK ErrorValue 类完全指南:结构化错误附加值的读取与类型体系

【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger

导读

ErrorValue是 Dagger 核心 GraphQL API 中Error对象的一个组成单元,用于以“名称 + JSON 值”的形式为错误附加结构化上下文信息(如错误码、失败文件路径、重试信息等)。本文以@dagger.io/daggerTypeScript SDK 生成的客户端类 ErrorValue 为主线,完整讲解其构造方式、三个核心方法(idnamevalue)的语义与调用链,并结合仓库中 GraphQL Schema、Go 核心实现与测试用例,深入剖析ErrorValue的底层数据模型,帮助你准确掌握如何在 Dagger 管道中读取和使用结构化错误扩展信息。

一、ErrorValue 是什么:错误扩展的结构化载体

在 Dagger 中,错误并不只是“一条字符串”。当模块或引擎在执行过程中抛出错误时,可以携带一组结构化的扩展信息(extensions)。从仓库核心实现看,Error对象包含两个字段(core/error.go):

type Error struct { Message string `field:"true" doc:"A description of the error."` Values []*ErrorValue `field:"true" doc:"The extensions of the error."` }

其中Values[]*ErrorValue,即一组错误附加值;ErrorValue本身的结构同样定义在 core/error.go:

type ErrorValue struct { Name string `field:"true" doc:"The name of the value."` Value JSON `field:"true" doc:"The value."` }

也就是说,每个ErrorValue由两个字段构成:

  • name:值的名称,是扩展信息的键;
  • value:任意 JSON 编码的值,是扩展信息的载荷。

ErrorValueError一样实现了dagql.PersistedObjectdagql.PersistedObjectDecoder接口(core/error.go),因此它可以像 Dagger 中其他核心对象一样被持久化、编码与解码——这也解释了为什么 TypeScript 客户端中它会拥有id方法。

二、TypeScript 客户端中的类签名总览

ErrorValue类在生成的 TypeScript SDK 中位于 sdk/typescript/src/api/client.gen.ts,完整的声明结构如下:

成员签名说明
继承extends BaseClient所有 Dagger API 客户端对象的公共基类
构造器new ErrorValue(ctx?, _id?, _name?, _value?)仅供内部使用,不要直接new创建对象
id()Promise<ErrorValueID>返回该对象的唯一标识符
name()Promise<string>返回错误附加值的名称
value()Promise<JSON>返回错误附加值的 JSON 载荷

1. 类继承关系:BaseClient

ErrorValue直接继承自BaseClient。从生成的源码可见其私有字段与构造器(sdk/typescript/src/api/client.gen.ts):

export class ErrorValue extends BaseClient { private readonly _id?: ID = undefined private readonly _name?: string = undefined private readonly _value?: JSON = undefined /** * Constructor is used for internal usage only, do not create object from it. */ constructor(ctx?: Context, _id?: ID, _name?: string, _value?: JSON) { super(ctx) this._id = _id this._name = _name this._value = _value } ... }

三个私有字段(_id_name_value)分别对应底层 GraphQL 对象的idnamevalue字段,构造器接收这四个参数用于缓存已知值。这种“字段缓存 + 惰性查询”的模式是 Dagger 生成客户端的通用风格:如果客户端已经持有该字段的值,就直接返回,避免额外的 GraphQL 请求。

2. 构造器:仅供内部使用

官方文档明确指出:

Constructor is used for internal usage only, do not create object from it.

构造器参数ctxContext)、_idErrorValueID)、_namestring)、_valueJSON)均为可选。日常开发中你不需要也不应该直接实例化ErrorValue——它是通过查询Error.values字段(或加载其 ID)由 SDK 自动构造的。

三、三个核心方法详解

1.id():获取唯一标识符

id = async (): Promise<ID> => { if (this._id) { return this._id } const ctx = this._ctx.select("id") const response: Awaited<ID> = await ctx.execute() return response }
  • 返回类型为Promise<ErrorValueID>
  • 若客户端已持有_id则直接返回,否则通过 GraphQL 选择集select("id")惰性查询。

ErrorValueID是 Dagger 的标量类型之一,对应 GraphQL Schema 中的scalar ErrorValueID。其 TypeScript 类型别名定义在 type-aliases/ErrorValueID.md:

type ErrorValueID = string & { __ErrorValueID: never }

即它是一个带 branded 标记的字符串,用于在类型层面区分普通字符串与 Dagger 对象标识符。在 GraphQL Schema 中(core/schema/testdata/base_schema.graphqls):

type ErrorValue implements Node { """A unique identifier for this ErrorValue.""" id: ID! """The name of the value.""" name: String! """The value.""" value: JSON! } """A unique identifier for an object.""" scalar ErrorValueID

注意ErrorValue实现了Node接口,这与id()方法的存在直接对应。

2.name():读取附加值的名称

name = async (): Promise<string> => { if (this._name) { return this._name } const ctx = this._ctx.select("name") const response: Awaited<string> = await ctx.execute() return response }
  • 返回类型为Promise<string>
  • 对应核心 Go 结构体中Name string字段(core/error.go),文档描述为 “The name of the value”。

name是扩展信息的键。例如错误扩展{"code": 42}中,键"code"就会成为一个ErrorValue.name

3.value():读取 JSON 载荷

value = async (): Promise<JSON> => { if (this._value) { return this._value } const ctx = this._ctx.select("value") const response: Awaited<JSON> = await ctx.execute() return response }
  • 返回类型为Promise<JSON>
  • 对应核心 Go 结构体中Value JSON字段(core/error.go),文档描述为 “The value”。

JSON是 Dagger 的另一个 branded 标量,定义在 type-aliases/JSON.md:

type JSON = string & { __JSON: never }

其文档描述为 “An arbitrary JSON-encoded value”,即任意 JSON 编码的字符串。在 Go 端,它对应core.JSON类型,底层就是json.RawMessage语义。

四、从 GraphQL 到 TypeScript:ErrorValue 的完整数据链路

1. Schema 层:Error.values 与 ErrorValue

在 Dagger 的基础 GraphQL Schema 中(core/schema/testdata/base_schema.graphqls),Error类型声明了:

type Error implements Node { id: ID! message: String! """The extensions of the error.""" values: [ErrorValue!]! withValue(name: String!, value: JSON!): Error! }

即:

  • Error.values返回一个[ErrorValue!]!列表——这是获取ErrorValue对象的唯一入口
  • Error.withValue(name, value)用于向错误追加一个新的附加值,返回值是新的Error
  • 对应的scalar ErrorIDscalar ErrorValueID分别作为两个对象类型的标识符。

2. 解析器层:withValue 如何产生 ErrorValue

Schema 注册位于 core/schema/error.go:

dagql.Fields[*core.Error]{ dagql.Func("withValue", s.withValue). Doc(`Add a value to the error.`), }.Install(dag) dagql.Fields[*core.ErrorValue]{}.Install(dag)

withValue的实现(core/schema/error.go):

func (s *errorSchema) withValue(ctx context.Context, self *core.Error, args struct { Name string `doc:"The name of the value."` Value core.JSON `doc:"The value to store on the error."` }) (*core.Error, error) { return self.WithValue(args.Name, args.Value), nil }

底层Error.WithValue采用不可变风格:克隆当前错误后追加一个ErrorValue并返回新错误对象(core/error.go):

func (e *Error) WithValue(name string, value JSON) *Error { cp := e.Clone() cp.Values = append(cp.Values, &ErrorValue{ Name: name, Value: value, }) return cp }

3. 扩展信息如何最终暴露

ErrorValue在内部服务于错误扩展(extensions)机制。Error.Extensions()会把Values中每个ErrorValue反序列化为键值对(core/error.go):

func (e *Error) Extensions() map[string]any { ext := map[string]any{} for _, v := range e.Values { var val any json.Unmarshal(v.Value, &val) ext[v.Name] = val } return ext }

此外,当引擎需要把普通 Go error 包装为 DaggerError对象时,NewErrorFromErr(core/error.go)会检查错误是否实现了dagql.ExtendedError接口;若实现了,就把其Extensions()中的每个键值对通过withValue选择器逐条写入ErrorValue,最终组合成一个 Dagger 查询序列。

从这些源码可以推断:ErrorValue既是 Dagger 内部错误扩展的持久化载体,也是用户通过 GraphQL/客户端查询错误附加信息的结构化入口。

五、JSON 载荷的取值语义与测试验证

value()返回的 JSON 可以承载任意 JSON 数据类型。仓库中的测试用例 core/error_test.go 系统验证了ErrorValue.Value对各种 JSON 类型的处理:

测试场景ErrorValue.Value反序列化结果
简单字符串"hello world""hello world"
数字42float64(42)
布尔值truetrue
nullnullnil
对象{"file": "test.go", "line": 123}map[string]any{...}
数组["a", "b", "c"][]any{"a","b","c"}
多值组合多个 ErrorValue合并后的 map

特别地,测试TestError_Extensions_PreventDoubleEncoding(core/error_test.go)确保Value中的 JSON 被正确反序列化为结构化对象,而不会以原始 JSON 字符串的形式再次编码(避免双重/三重编码问题)。

这些测试说明:当你在 TypeScript 端调用value()拿到JSON字符串后,可以安全地JSON.parse出原始结构;当你在 Go/引擎侧看到扩展信息时,它们已经是反序列化后的map[string]any

六、典型使用方式:遍历 Error.values

虽然ErrorValue类本身不建议直接构造,但它是消费 Dagger 错误扩展信息的关键类型。典型的使用模式是从Error对象出发:

import { connect } from "@dagger.io/dagger" const result = await connect(async (client) => { // ... 执行可能失败的操作,捕获 dagger.Error 类型错误 try { await client.container() .from("alpine:3.20") .withExec(["sh", "-c", "exit 1"]) .stdout() } catch (e) { // 假设 e 是带有 values 扩展的 Dagger 错误 const err = e as any // values 为 ErrorValue[],每个元素可调用 id() / name() / value() for (const ev of err.values ?? []) { const name = await ev.name() const value = await ev.value() // JSON 字符串,可 JSON.parse console.log(`extension[${name}] =`, JSON.parse(value)) } } })

几点实践提示:

  • Error.values在 Schema 中是非空数组[ErrorValue!]!,但具体某个错误是否携带扩展取决于产生错误的一方是否调用过withValue
  • 每个ErrorValue都可以独立调用id()获取标识符,之后可通过 Schema 中的loadErrorValueFromID(id: ErrorValueID!): ErrorValue!(见 core/schema/testdata/base_schema.graphqls)从 ID 重新加载对象;
  • value()返回的JSON是 branded string 类型,取值后需要自行JSON.parse还原为运行时对象。

七、SDK 代码生成:ErrorValue 从何而来

ErrorValue类并非手写代码,而是由 Dagger 的 SDK 代码生成器从 GraphQL Schema 自动生成。TypeScript 客户端源文件 sdk/typescript/src/api/client.gen.ts 即产物之一,官方 API 参考文档(含本文所讲的 ErrorValue.md)也是基于同一 Schema 生成的。因此:

  • 若上游 Schema 中ErrorValue类型发生变更,生成的类与文档会同步更新;
  • 你看到的方法签名(id/name/value)与 Schema 字段(id: ID!/name: String!/value: JSON!)一一对应,一一映射,不存在额外的隐藏行为。

八、总结

ErrorValue虽然只是Error对象的一个小组件,但它承载着 Dagger 结构化错误扩展的核心设计:

  1. 数据模型name+value(JSON)两个字段,定义于 core/error.go,实现持久化对象接口;
  2. Schema 契约ErrorValue implements Node,包含idnamevalue三字段,通过Error.valueswithValueError关联(base_schema.graphqls);
  3. 客户端体验:TypeScript 端ErrorValue类继承BaseClient,以惰性查询方式暴露id()name()value()三个异步方法,构造器仅供内部使用(client.gen.ts);
  4. 取值语义value是任意 JSON 编码的字符串,底层在 Go 端反序列化为map[string]any,测试用例完整覆盖了字符串、数字、布尔、null、对象、数组等场景(error_test.go)。

掌握ErrorValue,就掌握了在 Dagger 中读取结构化错误上下文的标准方式——无论是调试模块故障、透传自定义错误码,还是在引擎层面消费扩展信息,都能做到心中有数。

【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询