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

# はじめに
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で確認する
出会ったことのないエラーに遭遇すると、とりあえずエラー文で検索するのですが、そこでいい感じの記事に出会えないと、軽く詰みます。

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

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

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

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

```
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)`のように`{}`が付いていて、それを消したら無事データが渡されました、という流れです。

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

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