0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【GraphQL】message: "Variable 'input' has coerced Null value for NonNull type 'ID!'エラー解決

Posted at

はじめに

TypeScriptととReduxを用いて、amplify GraphQLのTodoアプリチュートリアルを試してます。
mutationのdelete機能を使って、作ったtodoを削除しようとしたのですがタイトルの通り、

message: "Variable 'input' has coerced Null value for NonNull type 'ID!'

というエラーがコンソールに現れました。

該当コード

App.tsxは全体像、todoSlice.tsは一部だけ抜粋しておきますが、完成形はこのようなロジックになっております。

App.tsx
import DeleteForeverIcon from "@material-ui/icons/DeleteForever";
import Signin from "./Signin";
import scss from "./App.module.scss";
import {
  addTodo,
  AddTodosType,
  deleteTodo,
  fetchTodos,
  IdType,
  selectTodos,
} from "./features/todo/todoSlice";
import { useForm } from "react-hook-form";
import { useEffect } from "react";
import { useAppDispatch, useAppSelector } from "./app/hooks";
import { withAuthenticator } from "@aws-amplify/ui-react";

const App = () => {
  const {
    register,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm();

  const dispatch = useAppDispatch();
  const todos = useAppSelector(selectTodos);

  useEffect(() => {
    const getTodos = async () => {
      await dispatch(fetchTodos());
    };
    getTodos();
  }, []);

  const handleAddTodo = async (data: AddTodosType) => {
    await dispatch(addTodo(data));
    await dispatch(fetchTodos());
    reset();
  };

  const handleDelete = async (id: IdType) => {
    await dispatch(deleteTodo(id));
    await dispatch(fetchTodos());
    console.log(id);
  };

  return (
    <div className={scss.root}>
      <div className={scss.header}>
        <Signin />
      </div>
      <div className={scss.main_container}>
        <h2>Amplify Todos</h2>
        <form onSubmit={handleSubmit(handleAddTodo)}>
          <input
            className={scss.input}
            placeholder="Name"
            {...register("name", { required: true })}
          />
          <input
            className={scss.input}
            placeholder="Description"
            {...register("description", { required: true })}
          />
          <button className={scss.button} type="submit">
            Create Todo
          </button>
        </form>

        <div className={scss.todo_wrapper}>
          {todos.map((todo: any, index: any) => (
            <div key={todo.id ? todo.id : index} className={scss.todo}>
              <div className={scss.left_wrapper}>
                <p className={scss.todoName}>{todo.name}</p>
                <p className={scss.todoDescription}>{todo.description}</p>
              </div>
              <DeleteForeverIcon onClick={() => handleDelete(todo.id)} />
            </div>
          ))}
        </div>
      </div>
      <div className={scss.footer}>footer</div>
    </div>
  );
};

export default withAuthenticator(App);

todoSlice.ts
export const deleteTodo = createAsyncThunk(
  "todo/deleteTodo",
  async (id: IdType) => {
    console.log(id);
    const todoDetails = {
      id: id,
    };
    try {
      await API.graphql({
        query: deleteTodoGraph,
        variables: { input: todoDetails },
      });
    } catch (err) {
      console.log(err);
    }
  }
);

結論からいうと、

todoSlice.ts
  async (id: IdType) => { //ここがおかしかった
    console.log(id);
    const todoDetails = {
      id: id,
    };

↑のコードをasync({id}: IdType) => { のように{}を付けてしまっていて、それによって、idの値がundifinedになってしまっていました。

console.logで確認する

出会ったことのないエラーに遭遇すると、とりあえずエラー文で検索するのですが、そこでいい感じの記事に出会えないと、軽く詰みます。

そういうときに教わった、エラー解決のための手順なのですが、

  • エラー文の理解
  • エラーを解決するための仮説立て
  • 仮説に基づいた調査

以上3つを意識すると、漠然と答えを探し求めるより早く答えにたどり着けるそうです。

実際今回も、まず下記エラー文を日本語訳してみました。

message: "Variable 'input' has coerced Null value for NonNull type 'ID!'

変数「input」がNonNull型の「ID!」に対してNull値を強要しています。

その結果に対して、**「input: に入れている値(型?)がnullになっているのかな?」という仮設を立て、「じゃあ、その値がnullになっていることを確かめるためには、どこかでconsole.log()などでデータがきちんと入っていることを確認すればいいのかな」**という結論のもと調査に入りました。

検証

todoSlice.ts
export const deleteTodo = createAsyncThunk(
  "todo/deleteTodo",
  async (id: IdType) => { // ここ
    console.log(id);
    const todoDetails = {
      id: id,
    };
    try {
      await API.graphql({
        query: deleteTodoGraph,
        variables: { input: todoDetails }, //ここ
      });
    } catch (err) {
      console.log(err);
    }
  }
);

idの値はApp.tsxから渡ってきています。まずこの下でconsole.log()をすると、結果はundefinedだったので、次にApp.tsxのidを渡す箇所でconsole.log()をすると、データは入ってました。

じゃあtodoSlice.tsxの方だな、とよくコードを見るとasync({id}: IdType)のように{}が付いていて、それを消したら無事データが渡されました、という流れです。

エラーときちんと向き合う

実装を先に進めたいがために、エラー文をなんとなく読んで、検索して出てきた答えと当てはまればオッケー、というような感じで進んできましたが、やっぱりきちんとエラーの意味を理解して「このエラーは何を言っているのか」、ということをしっかりと把握する必要性を感じました。

実際、エラーをきちんと理解できるようになれば、今後も自走でコードを書いていける状況になるわけなので、今のうちにエラーとしっかり向き合う癖を付けておこうと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?