@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'.",
}
]
}
}
响应中的丢失数据
如果一个字段预期具有一个值,并且该字段未定义,则该字段被认为是“丢失的数据”。这也是一种意外的状态,当它与 @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。