GraphQLを使用していると、「Cannot return null for non-nullable field "X"」というエラーに遭遇することがあります。このエラーは、nullを許可しないフィールドに対してnullが返されたときに発生します。本記事では、このエラーの原因と解決方法について詳しく説明します。

エラーの原因

このエラーは主に以下の理由で発生します:

1. スキーマ定義とリゾルバの不一致

2. データベースからのnullデータ

3. 外部APIからの予期しないレスポンス

解決方法

1. スキーマの見直し

まず、GraphQLスキーマを確認しましょう。問題のフィールドが本当にnon-nullableである必要があるかを再考します。もし可能であれば、フィールドをnullableに変更することでエラーを回避できます。

type Query {
  user(id: ID!): User
}

type User {
  id: ID!
  name: String  # nameをString!からStringに変更
}

2. リゾルバの修正

リゾルバ関数内でnullチェックを行い、適切なデフォルト値を設定します。

const resolvers = {
  Query: {
    user: (parent, { id }, context) => {
      const user = fetchUserFromDatabase(id);
      return {
        id: user.id,
        name: user.name || 'Unknown'  // nameがnullの場合はデフォルト値を設定
      };
    }
  }
};

3. エラーハンドリングの実装

Apollo ServerなどのGraphQLサーバーでは、カスタムエラーハンドリングを実装できます。これにより、nullが返された場合でもエラーをクライアントに適切に伝えることができます。

const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (error) => {
    if (error.message.startsWith('Cannot return null for non-nullable field')) {
      return new Error('データの取得に失敗しました。後ほど再試行してください。');
    }
    return error;
  },
});

4. データの整合性確認

データベースやAPIからのデータが常に期待通りの形式で返されることを確認します。必要に応じて、データクレンジングやバリデーションを実装しましょう。

function validateUserData(user) {
  if (!user.name) {
    user.name = 'Unknown';
  }
  return user;
}

const resolvers = {
  Query: {
    user: async (parent, { id }, context) => {
      const user = await fetchUserFromDatabase(id);
      return validateUserData(user);
    }
  }
};

まとめ

「Cannot return null for non-nullable field "X"」エラーは、GraphQLの型システムとデータの整合性に関する重要な問題を示しています。スキーマ設計の見直し、リゾルバの適切な実装、そしてデータの検証を通じて、このエラーを効果的に解決できます。これらの対策を実施することで、より堅牢なGraphQLアプリケーションを構築することができるでしょう。