1. ホーム
  2. javascript

[解決済み] 変異を行う際に「Cannot return null for non-nullable field」エラーが発生するのはなぜですか?重複

2022-02-25 14:57:47

質問

私はサーバー側で(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;
  }
},

解決方法は?

このリゾルバの最大の問題は、様々なシナリオで User オブジェクトを返すのではなく、文字列を返しています。スキーマでは createAccount を返すことができます。 User または null (であった場合 User! であれば、non-nullableとなり、その後 null も有効な型ではありません)。

リゾルバで文字列を返すと、リゾルバはオブジェクトを期待しているので、それを1つにまとめ、それから User のように)そのオブジェクトの nameemail ). これらのプロパティは存在せず、あなたの User オブジェクトに対して 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;

さて、メールが重複している場合、応答は次のようになります。

{
  "data": {
    "createAccount": null
  },
  "errors": [
    {
      "message": "Email is already in use",
      "locations": [
        {
          "line": 4,
          "column": 3
        }
      ],
      "path": [
        "createAccount"
      ]
    }
  ]
}

クライアントに表示されるエラーの内容を変更したい場合には formatError または formatResponse をApolloサーバーミドルウェアの設定オプションとして使用します。また、カスタムエラーを使用するのもよい方法です。 code を使用すると、クライアント側でエラーの種類をより簡単に特定することができます。

最後に、name、email、passwordがリゾルバ内で定義されているかどうかを確認する必要はありません。スキーマにはすでにこれらの入力がnon-nullとしてマークされているので、GraphQLはこれらのいずれかが欠けている場合に自動的にエラーを返します。