跳至主要内容
版本: v18.0.0

@catch 指令

可以在 Relay 查询/片段/突变中的字段中添加 @catch 指令,以声明如何在运行时处理异常和意外值。使用 @catch 允许 Relay 在响应数据中提供异常,而不是返回 null 值(这是默认行为)。

当 GraphQL 响应包含 字段错误 时,Relay 会查找这些错误,如果该字段或父字段存在 @catch 指令,则会响应 {ok: true, value: "你的值"}{ok: false, errors: [...]}

如果在错误来源字段上直接捕获 @catch 错误,则会在该字段上提供错误。以下是一个示例

query MyQuery {
viewer {
name @catch
age
}
}

如果 name 包含错误,则会在响应数据中的 name 字段上提供错误,如下所示

{
viewer: {
name: {
ok: false,
errors: [
{
message: "Couldn't get name",
path: ['viewer', 'name']
}
]
}
age: 39
}
}

但是,如果 @catch 存在于字段的祖先之一上,则该错误会冒泡到那里,如下所示

query MyQuery {
viewer @catch {
name
age
}
}
{
viewer: {
ok: false,
errors: [
{
message: "Couldn't get name",
path: ['viewer', 'name']
}
]
}
}

可以用 @catch 捕获什么?

负载错误

负载错误是在执行给定字段的响应时,由于服务器端异常而发生的错误。在这种情况下,GraphQL 服务器在应该存在值的地方提供 null 值,以及一个单独的错误对象。

当你在字段上使用 @catch 时,Relay 会获取这些错误并将它们内联提供给你,使它们更容易处理,并且不再不可见。

另一个很好的副作用是,如果一个字段是可空的,你现在将知道 null 是由于异常还是真正的 null,因为形状将包含 {ok: true} 和值 null,或者 {ok: false} 和实际的错误。

@catch 下面的 @required(action: THROW)

如果你有一个 @required(action: THROW) 并且其祖先包含一个 @catch,那么 @required 错误不会抛出异常,而是会冒泡并以与普通错误相同的方式提供。以下是一个示例

query MyQuery {
viewer @catch {
name @required(action: THROW)
age
}
}
{
viewer: {
ok: false,
errors: [
{
message: "Relay: Missing @required value at path 'viewer.name' in 'MyQuery'.",
}
]
}
}

响应中的丢失数据

以下是在 Relay 中可能出现丢失数据的位置的示例

如果一个字段预期具有一个值,并且该字段未定义,则该字段被认为是“丢失的数据”。这也是一种意外的状态,当它与 @catch 作为祖先一起发生时,它也会被捕获,如下所示

{
viewer: {
ok: false,
errors: [
{
message: "Relay: Missing data for one or more fields in MyQuery",
}
]
}
}

@catch 如何与 @throwOnFieldError 相互作用?

使用 @throwOnFieldError 使字段能够在发生字段错误时抛出 JavaScript 异常。通过使用 @catch,你告诉 Relay 你不希望在这种情况下发生 JavaScript 异常。相反,你请求将错误提供在数据对象中,并具有与上面列出的相同行为和规则(包括冒泡到父字段)。

重要的是要注意,你仍然可以在没有 @throwOnFieldError 的情况下使用 @catch。它仍然会在数据对象中提供错误。但是其他不在 @catch 下的字段仍然不会抛出异常,因为 @throwOnFieldError 将缺失。

阅读更多关于 @throwOnFieldError 的信息 此处

@catch 参数

to: RESULT(默认)

@catch(to: RESULT) 启用上面描述的行为,即为包含错误的相同或子字段内联提供错误。这是默认参数,这意味着你可以写 @catch@catch(to: RESULT),行为将相同。

to: NULL

@catch(to: NULL) 将为你提供与 @catch 之前存在的行为完全相同的行为。如果字段包含错误,则该字段将为 null。