为什么我在进行突变时会收到"无法为非可空字段返回null"错误?

Col*_*ndo 5 javascript node.js express graphql apollo-server

我在服务器端尝试(Apollo)GraphQL并且一直有一个可能很愚蠢的问题.我正在尝试注册用户,但不断收到下面链接图片中显示的错误.问题是什么?忽略非常简单的auth流程,因为我只是测试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
}

`
Run Code Online (Sandbox Code Playgroud)

解析器

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;
  }
},
Run Code Online (Sandbox Code Playgroud)

Dan*_*den 9

解析器的最大问题是,在任何数量的场景中User,您返回一个字符串,而不是返回一个对象.您的模式指定createAccount可以返回a Usernull(如果是User!,它将是不可为空的,然后null也不是有效类型).

当您在解析器中返回一个字符串时,因为它期望一个对象,它会将其强制转换为一个对象,然后开始User在该对象上查找属性(如nameemail).这些属性不存在,并且因为它们是User对象的非null属性,所以返回null/undefined会导致错误.

你的解析器应该只是抛出它需要抛出的任何错误.然后它们将作为errors响应中数组的一部分返回.例如:

// 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;
Run Code Online (Sandbox Code Playgroud)

现在,如果您有重复的电子邮件,响应将如下所示:

{
  "data": {
    "createAccount": null
  },
  "errors": [
    {
      "message": "Email is already in use",
      "locations": [
        {
          "line": 4,
          "column": 3
        }
      ],
      "path": [
        "createAccount"
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

如果你想操纵你的错误是如何显示在客户端上,你应该利用formatErrorformatResponse配置选项为您阿波罗服务器中间件.使用自定义错误也是一种很好的做法,允许您添加自定义属性,code以便更轻松地识别客户端上的错误类型.

最后,没有必要检查您的解析器中是否定义了名称,电子邮件或密码 - 您的架构已将这些输入标记为非空,这意味着如果缺少任何这些输入,GraphQL将自动返回错误.

  • 我的天,就我而言,我忘记在 DataSource API 回调上使用 return 语句。这篇文章有助于了解该领域的原因!谢谢。 (2认同)