【JavaScript】fetchとaxiosの非同期処理の違いまとめ

JavaScript

JavaScriptで非同期処理を実装する際によく利用されるFetch APIaxiosの違いについて紹介します。

前提知識: fetchもaxiosも戻り値はPromise

fetchaxiosも戻り値は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.oktrueになります。ですので、fetchでは『200系 or 200系以外』という判別方法になります。

一方、axiosの場合はresponse.statusに具体的なHTTPレスポンスステータスコードが記述されています。

レスポンスありのエラーハンドリングについて

『レスポンスありのエラーハンドリング』とは404や500などの200系以外のHTTPレスポンスステータスコードが返された時の処理についてです。

fetchの場合、ステータスコードにかかsわらずレスポンスが返された場合はfulfilledなPromiseオブジェクトが返されます。
ですので、レスポンスありのエラーハンドリングはresponse.okfalseの条件下に記述します。

一方axiosの場合、200系以外のレスポンスが返された場合はデフォルトでrejectedなPromiseオブジェクトを返すため1catchあるいは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の通信自体が失敗した時の処理についてです。

レスポンスがない場合はfetchaxiosrejectedな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)やってます。フォローしてもらえるとうれしいです!

参考資料


  1. validateStatusオプションを利用すれば挙動を変更できます