Learn プログ

-マナビメモ-

jQueryで書いたAjaxを、Fetch APIで書く

はじめに

今まで作ってきたTodoApp(3つのシリーズ)のサーバーとの通信部分を、RailsAPIサーバーとして完全に切り離した時を想定して(Riot.jsやReactを使ったときはjQueryは使わないだろうから)、jQueryからFetch APIを使ったものにしてみた。

参考

注意

csrfTokenはAPIサーバーとして切り離した時は関係ない。 そのかわり、corsに対応するため

fetch(url, {
  mode: 'cors', 
  credentials: 'include' 
})

が必要。credentialsはCookieやBASIC 認証などの認証情報。

loadTasks()

jQuery

function loadTasks() {
  return (dispatch) => {
    dispatch(toggleLoading(true));
    $.ajax({
      url: '/api/tasks.json',
      dataType: 'json',
      success: (res) => {
        setTimeout(() => {
          dispatch(tasksloaded(res.tasks));
          dispatch(toggleLoading(false));
        }, 2000)
      },
      error: (xhr, status, err) => {
        dispatch(toggleLoading(false));
        dispatch(tempErrorMessage('API Error'));
        console.log('/api/tasks.json', status, err.toString());
      },
    });
  };
}

Fetch API

まずサーバー側のエラーを直接はキャッチ出来ないらしいので、下のようにチェックしてエラーを投げる。 今後全てのメソッドに使う。

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  } else {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}
function loadTasks() {
  return (dispatch) => {
    const csrfToken = document.getElementsByName('csrf-token').item(0).content;
    dispatch(toggleLoading(true));
    fetch('/api/tasks.json', {
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken,
      },
    }).then((response) => {
      // ここでエラーチェック
      checkStatus(response);
      return response.json();
    }).then((json) => {
      setTimeout(() => {
        dispatch(tasksloaded(json.tasks));
        dispatch(toggleLoading(false));
      }, 2000)
    }).catch((err) => {
      dispatch(toggleLoading(false));
      dispatch(tempErrorMessage('API Error'));
      console.error(err);
    });
  };
}

addTask()

jQuery

function addTask(newTask) {
  return (dispatch) => {
    dispatch(toggleLoading(true));
    $.ajax({
      url: '/api/tasks.json',
      type: 'POST',
      dataType: 'json',
      data: { name: newTask },
      success: (res) => {
        dispatch(newTaskAdded(res.id, res.name));
        dispatch(toggleLoading(false));
      },
      error: (xhr, status, err) => {
        dispatch(toggleLoading(false));
        dispatch(tempErrorMessage('API Error'));
        console.log('/api/tasks.json', status, err.toString());
      },
    });
  };
}

Fetch API

function addTask(newTask) {
  return (dispatch) => {
    const csrfToken = document.getElementsByName('csrf-token').item(0).content;
    dispatch(toggleLoading(true));
    fetch('/api/tasks.json', {
      method: 'POST',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken,
      },
      body: JSON.stringify({ name: newTask }),
    }).then((response) => {
      // ここでエラーチェック
      checkStatus(response)
      return response.json();
    }).then((json) => {
      dispatch(newTaskAdded(json.id, json.name));
      dispatch(toggleLoading(false));
    }).catch((err) => {
      dispatch(toggleLoading(false));
      dispatch(tempErrorMessage('API Error'));
      console.error(err);
    });
  };
}

toggleLoading()

jQuery

function toggleComplete(id, isComplete) {
  return (dispatch) => {
    $.ajax({
      url: `/api/tasks/${id}`,
      type: 'PATCH',
      dataType: 'json',
      data: { isComplete },
      success: (res) => {
        dispatch(completeChanged(res.id, res.isComplete));
      },
      error: (xhr, status, err) => {
        dispatch(tempErrorMessage('API Error'));
        dispatch(completeChanged(id, !isComplete));
        console.log(`/api/tasks/${id}`, status, err.toString());
      },
    });
  };
}

Fetch API

function toggleComplete(id, isComplete) {
  return (dispatch) => {
    const csrfToken = document.getElementsByName('csrf-token').item(0).content;
    fetch(`/api/tasks/${id}`, {
      method: 'PATCH',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken,
      },
      body: JSON.stringify({ isComplete }),
    }).then((response) => {
      // ここでエラーチェック
      checkStatus(response)
      return response.json();
    }).then((json) => {
      console.log(json);
      dispatch(completeChanged(json.id, json.isComplete));
    }).catch((err) => {
      dispatch(toggleLoading(false));
      dispatch(tempErrorMessage('API Error'));
      console.error(err);
    });
  };
}

deleteTasks()

jQuery

function deleteTasks(ids) {
  return (dispatch) => {
    dispatch(toggleLoading(true));
    $.ajax({
      url: '/api/tasks/del_tasks',
      type: 'DELETE',
      dataType: 'json',
      data: { ids },
      success: () => {
        dispatch(deletedTasks(ids));
        dispatch(toggleLoading(false));
      },
      error: (xhr, status, err) => {
        dispatch(tempErrorMessage('API Error'));
        dispatch(toggleLoading(false));
        console.log('/api/tasks/del_tasks', status, err.toString());
      },
    });
  };
}

Fetch API

function deleteTasks(ids) {
  return (dispatch) => {
    const csrfToken = document.getElementsByName('csrf-token').item(0).content;
    dispatch(toggleLoading(true));
    fetch('/api/tasks/del_tasks', {
      method: 'DELETE',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken,
      },
      body: JSON.stringify({ ids }),
    }).then((response) => {
      // ここでエラーチェック
      checkStatus(response)
    }).then(() => {
      dispatch(deletedTasks(ids));
      dispatch(toggleLoading(false));
    }).catch((err) => {
      dispatch(toggleLoading(false));
      dispatch(tempErrorMessage('API Error'));
      console.error(err);
    });
  };
}

deleteTask()

jQuery

function deleteTask(id) {
  return (dispatch) => {
    dispatch(toggleLoading(true));
    $.ajax({
      url: `/api/tasks/${id}`,
      type: 'DELETE',
      dataType: 'json',
      success: () => {
        dispatch(deletedTask(id));
        dispatch(toggleLoading(false));
      },
      error: (xhr, status, err) => {
        dispatch(tempErrorMessage('API Error'));
        dispatch(toggleLoading(false));
        console.log('/api/tasks/del_tasks', status, err.toString());
      },
    });
  };
}

Fetch API

function deleteTask(id) {
  return (dispatch) => {
    const csrfToken = document.getElementsByName('csrf-token').item(0).content;
    dispatch(toggleLoading(true));
    fetch(`/api/tasks/${id}`, {
      method: 'DELETE',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken,
      },
    }).then((response) => {
      // ここでエラーチェック
      checkStatus(response)
    }).then(() => {
      dispatch(deletedTask(id));
      dispatch(toggleLoading(false));
    }).catch((err) => {
      dispatch(toggleLoading(false));
      dispatch(tempErrorMessage('API Error'));
      console.error(err);
    });
  };
}