はじめに
Fetch APIを使った処理のエラーハンドリングはどうするのが正解なのか、色々調べながら試してみて、とりあえず下記のような形式で落ち着いたので紹介したいと思います。
実際のコード
今回はReactを使ったPOSTメソッドでの処理を例に挙げてみます。
バリデーションエラーメッセージがあることも考慮して作りました。
// APIを叩く関数
export const post = async (apiEndpoint, token, dataBody) => {
try {
const res = await fetch(apiEndpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(dataBody),
});
const data = await res.json();
if (res.ok) {
return data;
}
if (data.errors) {
return data;
}
// catchの中で一緒に処理するために例外をスロー
throw new Error(`${res.status} ${res.statusText}`);
} catch (error) {
console.error("Error:", error.message);
console.log(error.stack);
return {
errors: ["予期しないエラーが発生しました"],
};
}
};
// 呼び出し側の処理
const handleSubmit = async (e) => {
e.preventDefault();
const result = await apiClient.post(apiEndpoint, token, {
folder: { name: folderName, parent_id: parentId },
});
if (result.errors) {
setErrorMessage(result.errors);
return;
}
handleSuccess();
};
バリデーションエラーメッセージがある場合はそれを返して表示させて、コンソールには特に何も表示しないようにしています。
422以外のエラーでバリデーションメッセージが特にない場合や、例外が発生した場合は、catchで専用のエラーメッセージを返しています。
また、下記のようにcatchで2行で書いている箇所は1行で書くこともできます。
// 変更前
console.error("Error:", error.message);
console.log(error.stack);
// 変更後
// これならスタックトレースも表示される
console.error("Error:", error);
しかし、throw new Error("message")
のようにしてエラーオブジェクトを使って例外をスローし、エラーオブジェクトをそのまま出力すると、Error:
というプレフィックスが付加されます。
なので、console.error("Error:", error);
としていると、コンソールにError: Error: message
といった風に表示されてしまいます。
それならばError:
をわざわざつける必要は無いと思ったのですが、実際にネットワークエラーなどで例外がスローされた場合はError:
というプレフィックスはつかないみたいなので、なるべく形式を統一するためにconsole.error("Error:", error.message);
でError:
が付かない形式でメッセージだけを取り出して表示するようにしました。
その場合はスタックトレースは表示されないので、console.log(error.stack);
のようにして表示させています。
あとがき
改めてコードを見るとスマートじゃないですね。。POST以外にも対応した形式で作れた方がいいでしょうし、改善点がたくさんありそうです。。
間違っている点や改善点、もっといい方法がありましたら是非取り入れたいと思いますので、ご教授いただけますと幸いです。