JavaScriptで非同期処理を実装する際によく利用されるFetch APIとaxiosの違いについて紹介します。
目次
前提知識: fetchもaxiosも戻り値はPromise
fetch
もaxios
も戻り値はPromiseです。ですので、成功時(fulfilled
)の戻り値はthen()
あるいはawait
で取得します。
Promiseの詳細解説はJavaScriptの非同期処理で理解必須!Promiseの概要・挙動まとめで紹介しています。
fetchの戻り値のサンプルコード
thenを利用する場合
const logTodoResponse = () => {
fetch("http://localhost:4000/todos/1", {
method: "GET",
}).then((response) => console.log(response));
};
// 実行結果
logTodoResponse();
// Response {
// size: 0,
// [Symbol(Body internals)]: {
// ...
async/awaitを利用する場合
const logTodoResponse = async () => {
const response = await fetch("http://localhost:4000/todos/1", {
method: "GET",
});
console.log(response);
};
// 実行結果
logTodoResponse();
// Response {
// size: 0,
// [Symbol(Body internals)]: {
// ...
axiosの戻り値のサンプルコード
thenを利用する場合
const logTodoResponse = () => {
axios
.get(`http://localhost:4000/todos/1`)
.then((response) => console.log(response));
};
// 実行結果
logTodoResponse();
// {
// status: 200,
// statusText: 'OK',
// headers: {
// ...
// ...
async/awaitを利用する場合
const logTodoResponse = async () => {
const response = await axios.get(`http://localhost:4000/todos/1`);
console.log(response);
};
// 実行結果
logTodoResponse();
// {
// status: 200,
// statusText: 'OK',
// headers: {
// ...
// ...
fetchとaxiosの比較表
fetchとaxiosの違いをまとめた表が以下になります。
データ取得 | HTTPメソッド指定方法 | ステータスコード取得 | 例外処理(responseなし) | 例外処理(responseあり) | |
---|---|---|---|---|---|
fetch | response.json() | methodプロパティで指定 | response.okの真偽値 | response.okで判断 | catchで処理 |
axios | response.data | aliasで指定可能 | response.status | catchで処理 | catchで処理かつ、レスポンス有無で分岐 |
以下ではそれぞれの観点について説明をします。
データ取得について
戻り値をresponse
とした場合、fetch
のリクエストレスポンスはresponse.json()
で参照できます。axios
の場合はresponse.data
で参照できます。
fetchを利用したデータ取得のサンプルコード
thenを利用する場合
const getTodo = () => {
const todo = fetch("http://localhost:4000/todos/1", {
method: "GET",
}).then((response) => response.json());
return todo; // { id: 1, content: 'go somewhere', completed: true }
};
// 実行結果
// 戻り値はPromiseなので、then()を利用してデータを参照する
getTodo().then((todo) => console.log(todo));
// { id: 1, content: 'go somewhere', completed: true }
async/awaitを利用する場合
const getTodo = async () => {
const response = await fetch("http://localhost:4000/todos/1", {
method: "GET",
});
return response.json(); // { id: 1, content: 'go somewhere', completed: true }
};
// 実行結果
// async関数はPromiseを返すので、then()を利用してデータを参照する
getTodo().then((todo) => console.log(todo));
// { id: 1, content: 'go somewhere', completed: true }
axiosを利用したデータ取得のサンプルコード
thenを利用する場合
const getTodo = () => {
const todo = axios
.get(`http://localhost:4000/todos/1`)
.then((response) => response.data);
return todo; // { id: 1, content: 'go somewhere', completed: true }
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// { id: 1, content: 'go somewhere', completed: true }
async/awaitを利用する場合
const getTodo = async () => {
const response = await axios.get(`http://localhost:4000/todos/1`);
return response.data; // { id: 1, content: 'go somewhere', completed: true }
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// { id: 1, content: 'go somewhere', completed: true }
HTTPメソッドの指定方法について
fetch
でHTTPメソッド(getやpostなど)を指定する場合はmethod
プロパティを利用します。
axios
の場合もmethod
プロパティで指定できますが、axios.get
のようなエイリアスが用意されています。
以下ではPOSTメソッドを例にfetch
と、axios
のエイリアスメソッドの違いについて紹介します。
fetchを利用した場合のHTTPメソッドの指定方法
const postTodo = async () => {
const postItem = { content: "go shopping", complated: false };
const response = await fetch("http://localhost:4000/todos", {
method: "POST",
body: JSON.stringify(postItem),
headers: {
"Content-Type": "application/json",
},
});
return response.json();
};
// 実行結果
postTodo().then((todo) => console.log(todo));
// { content: 'go shopping', complated: false, id: 3 }
axiosのエイリアスによるHTTPメソッドの指定方法
const postTodo = async () => {
const postItem = { content: "go", complated: false };
const response = await axios.post(
`http://localhost:4000/todos`,
postItem
);
return response.data;
};
// 実行結果
postTodo().then((todo) => console.log(todo));
// { content: 'go shopping', complated: false, id: 3 }
HTTPレスポンスステータスコードについて
fetch
の場合はHTTPレスポンスステータスコードが200系の場合、response.ok
はtrue
になります。ですので、fetch
では『200系 or 200系以外』という判別方法になります。
一方、axios
の場合はresponse.status
に具体的なHTTPレスポンスステータスコードが記述されています。
レスポンスありのエラーハンドリングについて
『レスポンスありのエラーハンドリング』とは404や500などの200系以外のHTTPレスポンスステータスコードが返された時の処理についてです。
fetch
の場合、ステータスコードにかかsわらずレスポンスが返された場合はfulfilled
なPromiseオブジェクトが返されます。
ですので、レスポンスありのエラーハンドリングはresponse.ok
がfalse
の条件下に記述します。
一方axios
の場合、200系以外のレスポンスが返された場合はデフォルトでrejected
なPromiseオブジェクトを返すため1、catch
あるいはthen
の第2引数で処理をします。
fetchを利用したエラーハンドリング例(レスポンスあり)
thenを利用する場合
const getTodo = () => {
// 存在しないリソースを参照する(404エラー発生)
const todo = fetch("http://localhost:4000/todos/4", {
method: "GET",
}).then((response) => {
if (response.ok) {
console.log(response);
return response.json();
} else {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
console.log("response is not ok");
return {};
}
});
return todo;
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// response is not ok
// { }
async/awaitを利用する場合
const getTodo = async () => {
// 存在しないリソースを参照する(404エラー発生)
const response = await fetch("http://localhost:4000/todos/4", {
method: "GET",
});
if (response.ok) {
return response.json();
} else {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
console.log("response is not ok");
return {};
}
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// response is not ok
// { }
axiosを利用したエラーハンドリング例(レスポンスあり)
thenを利用する場合
const getTodo = () => {
const todo = axios
.get(`http://localhost:4000/todos/4`) // 存在しないリソースを参照する(404エラー発生)
.then((response) => response.data)
.catch((error) => {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
console.log(
`Error! code: ${error.response.status}, message: ${error.message}`
);
return error.response.data;
});
return todo;
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// Error! code: 404, message: Request failed with status code 404
// {}
async/awaitを利用する場合
const getTodo = async () => {
const response = await axios
.get(`http://localhost:4000/todos/4`) // 存在しないリソースを参照する(404エラー発生)
.catch((error) => {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
console.log(
`Error! code: ${error.response.status}, message: ${error.message}`
);
return error.response;
});
return response.data;
};
// 実行結果
getTodo().then((todo) => console.log(todo));
// Error! code: 404, message: Request failed with status code 404
// {}
レスポンスなしのエラーハンドリングについて
『レスポンスなしのエラーハンドリング』とはネットワークエラー等でAPIの通信自体が失敗した時の処理についてです。
レスポンスがない場合はfetch
もaxios
もrejected
なPromiseオブジェクトを返します。
fetch
の場合、レスポンスが返ってくるとfulfilled
なPromiseオブジェクトを返すため、catch
あるいはthen
の第2引数で処理する内容がレスポンスなしのエラーハンドリングになります。
一方、axios
の場合は200系以外のレスポンスが返ってくるとデフォルトでrejected
なPromiseオブジェクトを返すため、response
の有無でさらに条件分岐をさせる必要があります。
fetchを利用したエラーハンドリング例(レスポンスなし)
const getTodo = async () => {
// レスポンスが返ってこないエラーを再現するため、不正なポートを利用
const response = await fetch(`http://localhost:1234/todos/1`, {
method: "GET",
}).catch((error) => {
// レスポンスなしのエラーハンドリング(実際には必要に応じた例外処理を実装する)
throw new Error(`No response! ${error.message}`);
});
if (response.ok) {
return response.json();
} else {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
return {};
}
};
// 実行結果
getTodo()
.then((todo) => console.log(todo))
.catch((error) => console.log(error));
// Error: No response! request to http://localhost:1234/todos/1 failed, reason: connect ECONNREFUSED 127.0.0.1:1234
// at ...
// at ...
// at ...
axiosを利用したエラーハンドリング例(レスポンスなし)
const getTodo = async () => {
const response = await axios
.get(`http://localhost:1234/todos/1`) // レスポンスが返ってこないエラーを再現するため、不正なポートを利用
.catch((error) => {
if (error.response) {
// レスポンスありのエラーハンドリング(実際には必要に応じた例外処理を実装する)
console.log(
`Error! code: ${error.response.status}, message: ${error.message}`
);
return error.response;
} else {
// レスポンスなしのエラーハンドリング(実際には必要に応じた例外処理を実装する)
throw new Error(`No response! ${error.message}`);
}
});
return response.data;
};
// 実行結果
getTodo()
.then((todo) => console.log(todo))
.catch((error) => console.log(error));
// Error: No response! connect ECONNREFUSED 127.0.0.1:1234
// at ...
// at ...
// at ...
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!
参考資料
- validateStatusオプションを利用すれば挙動を変更できます ↩