jQueryで書いたAjaxを、Fetch APIで書く
はじめに
今まで作ってきたTodoApp(3つのシリーズ)のサーバーとの通信部分を、RailsをAPIサーバーとして完全に切り離した時を想定して(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); }); }; }