为什么我在进行突变时会收到 "Cannot return null for non-nullable field" 错误?
Why am I getting a "Cannot return null for non-nullable field" error when doing a mutation?
我正在尝试服务器端的 (Apollo) GraphQL,但遇到了一个可能很愚蠢的问题。我正在尝试注册用户,但不断收到下面链接图片中显示的错误。问题是什么?忽略非常简单的身份验证流程,因为我只是在测试 GraphQl
以下是相关代码片段:
架构
export default `
type User {
id: ID!
name: String!
email: String!
}
type Query {
allUsers: [User]
currentUser: User
}
type Mutation {
createAccount(name: String!, email: String!, password: String!): User
loginUser(email: String!, password: String!): User
updatePassword(email: String!, password: String!, newPassword: String!): User
deleteAccount(email: String!, password: String!): User
}
`
解析器
createAccount: async (
parent,
{ name, email, password },
{ User },
info
) => {
try {
// Check for invalid (undefined) credentials
if (!name || !email || !password) {
return 'Please provide valid credentials';
}
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return 'Email is already in use';
}
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
} catch (error) {
return error.message;
}
},
解析器的最大问题是,在任何情况下,您 return 不是 User
对象,而是 return 字符串。您的架构指定 createAccount
可以 return 一个 User
或 null
(如果它是 User!
,它将是不可空的,然后 null
也不是有效类型)。
当您 return 解析器中的一个字符串时,因为它需要一个对象,它会将其强制转换为一个对象,然后开始寻找该对象的 User
属性(如 name
和 email
)。这些属性不存在,因为它们是您的 User
对象的非空属性,returning null/undefined 会导致错误。
您的解析器应该只抛出它需要抛出的任何错误。然后它们将作为 errors
数组的一部分在您的响应中被 returned。例如:
// Check if there is a user with the same email
const foundUser = await User.findOne({ email })
if (foundUser) throw new Error('Email is already in use')
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
现在,如果您有重复的电子邮件,回复将如下所示:
{
"data": {
"createAccount": null
},
"errors": [
{
"message": "Email is already in use",
"locations": [
{
"line": 4,
"column": 3
}
],
"path": [
"createAccount"
]
}
]
}
如果你想操纵你的错误在客户端上的显示方式,你应该为你的 Apollo 服务器中间件使用 formatError
或 formatResponse
配置选项。使用自定义错误也是一种很好的做法,允许您添加自定义属性,如 code
以更轻松地在客户端识别错误类型。
最后,无需检查您的解析器中是否定义了名称、电子邮件或密码——您的模式已经将这些输入标记为非空,这意味着 GraphQL 将自动 return 如果有任何错误他们中的一个不见了。
我正在尝试服务器端的 (Apollo) GraphQL,但遇到了一个可能很愚蠢的问题。我正在尝试注册用户,但不断收到下面链接图片中显示的错误。问题是什么?忽略非常简单的身份验证流程,因为我只是在测试 GraphQl
以下是相关代码片段:
架构
export default `
type User {
id: ID!
name: String!
email: String!
}
type Query {
allUsers: [User]
currentUser: User
}
type Mutation {
createAccount(name: String!, email: String!, password: String!): User
loginUser(email: String!, password: String!): User
updatePassword(email: String!, password: String!, newPassword: String!): User
deleteAccount(email: String!, password: String!): User
}
`
解析器
createAccount: async (
parent,
{ name, email, password },
{ User },
info
) => {
try {
// Check for invalid (undefined) credentials
if (!name || !email || !password) {
return 'Please provide valid credentials';
}
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return 'Email is already in use';
}
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
} catch (error) {
return error.message;
}
},
解析器的最大问题是,在任何情况下,您 return 不是 User
对象,而是 return 字符串。您的架构指定 createAccount
可以 return 一个 User
或 null
(如果它是 User!
,它将是不可空的,然后 null
也不是有效类型)。
当您 return 解析器中的一个字符串时,因为它需要一个对象,它会将其强制转换为一个对象,然后开始寻找该对象的 User
属性(如 name
和 email
)。这些属性不存在,因为它们是您的 User
对象的非空属性,returning null/undefined 会导致错误。
您的解析器应该只抛出它需要抛出的任何错误。然后它们将作为 errors
数组的一部分在您的响应中被 returned。例如:
// Check if there is a user with the same email
const foundUser = await User.findOne({ email })
if (foundUser) throw new Error('Email is already in use')
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
现在,如果您有重复的电子邮件,回复将如下所示:
{
"data": {
"createAccount": null
},
"errors": [
{
"message": "Email is already in use",
"locations": [
{
"line": 4,
"column": 3
}
],
"path": [
"createAccount"
]
}
]
}
如果你想操纵你的错误在客户端上的显示方式,你应该为你的 Apollo 服务器中间件使用 formatError
或 formatResponse
配置选项。使用自定义错误也是一种很好的做法,允许您添加自定义属性,如 code
以更轻松地在客户端识别错误类型。
最后,无需检查您的解析器中是否定义了名称、电子邮件或密码——您的模式已经将这些输入标记为非空,这意味着 GraphQL 将自动 return 如果有任何错误他们中的一个不见了。