fetch 함수 사용 시 중복 코드 함수화

중복 코드 존재

fetch 함수 사용시, then, catch 처리가 계속해서 중복되었다. 때문에 매우 코드가 길어지는 현상이 발생했다.

export const setRole = btn => {
    const id = btn.value;

    // id가 roleType + id인 select의 선택값을 가지고 온다.
    const roleValue = document.getElementById("roleType" + id).value;

    if (roleValue == null) {
        return;
    }

    fetch(`/users/${id}/role`, {
        method: "PATCH",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            roleName: roleValue
        })
    })
        .then((res) => {
            if (!res.ok) {
                return res.text().then(body => {
                    const error = new Error(`HTTP Error! status : ${res.status}, message : ${body}`);
                    error.status = res.status;
                    throw error;
                })
            }
            return res.text();
        })
        .then((data) => {
            alert("결과 : " + data);
            location.reload();
        })
        .catch(error => {
            alert(error.message);
            if (error.status == 403) {
                location.href = "/access-denied";
            }
        });
};

export const deleteUser = id => {
    fetch(`/users/${id}`, {
        method: "DELETE",
        headers: {
            "Content-Type": "application/json",
        },
    })
        .then((res) => {
            if (!res.ok) {
                return res.text().then(body => {
                    const error = new Error(`HTTP Error! status : ${res.status}, message : ${body}`);
                    error.status = res.status;
                    throw error;
                })
            }
            return res.text();
        })
        .then((data) => {
            alert("결과 : " + data);
            location.reload();
        })
        .catch(error => {
            alert(error.message);
            if (error.status == 403) {
                location.href = "/access-denied";
            }
        });
}

이는 유저가 도서 대출을 할 때, 관리자가 도서 관리를 할 때도 동일하게 처리해야 하기 때문에, 따로 중복되는 코드를 util.js로 빼주도록 하였다.

util.js에서 중복 코드를 함수로 리팩토링

util.js에서 중복 코드를 함수로 작성했다. response를 text로 보내주는 경우에만 사용하기 위해서 함수명은 fetchTextRequest로 지었고, handlerError 함수는 json으로 오든 text로 오든 상관이 없어서 그냥 handleError로 지었다.

// 공통 fetch 텍스트 요청 함수
export const fetchTextRequest = async (url, method, body = null) => {
    const options = {
        method: method,
        headers: {
            "Content-Type": "application/json",
        },
    };

    if (body) {
        options.body = JSON.stringify(body);
    }

    const response = await fetch(url, options);

    if (!response.ok) {
        const responseText = await response.text();
        const error = new Error(`HTTP Error! status: ${response.status}, message: ${responseText}`);
        error.status = response.status;
        throw error;;
    }

    return await response.text();
};

// 공통 에러 처리 함수
export const handleError = (error) => {
    alert(error.message);
    if (error.status === 403) {
        location.href = "/access-denied";
    }
};

그리고 이 함수를 호출하는 js파일인 manageMember.js 파일에서는, 간편하게 사용이 가능하다.

import { fetchTextRequest, handleError } from "./util.js";

export const setRole = async btn => {
    const id = btn.value;

    // id가 roleType + id인 select의 선택값을 가지고 온다.
    const roleName = document.getElementById("roleType" + id).value;

    if (roleName == null) {
        return;
    }

    try {
        const data = await fetchTextRequest(`/users/${id}/role`, "PATCH", { roleName });
        alert("결과 : " + data);
        location.reload();
    } catch (error) {
        handleError(error);
    }
};

export const deleteUser = async (id) => {
    try {
        const data = await fetchTextRequest(`/users/${id}`, "DELETE");
        alert("결과 : " + data);
        location.reload();
    } catch (error) {
        handleError(error);
    }
};

또한, 이는 관리자가 도서를 관리하는 manageBook.js, 유저가 도서를 대출하는 rent.js에서도 동일하게 사용이 가능할 것 같아 함께 리팩토링 해주었다.

managebook.js

import {fetchTextRequest, handleError} from "./util.js";

export const addBook = async () => {
    const bookName = document.getElementById("addBookName").value;
    const isbn = document.getElementById("addBookIsbn").value;

    try {
        const data = await fetchTextRequest(`/books/add`, "POST", {bookName, isbn});
        alert("결과 : " + data);
        location.reload();
    } catch (e) {
        handleError(e);
    }
};

export const deleteBook = async id => {

    try {
        const data = await fetchTextRequest(`/books/${id}`, "DELETE");
        alert("결과 : " + data);
        location.reload();
    } catch(e) {
        handleError(e);
    }

};

export const setModifySection = btn => {
    const idInput = document.getElementById("bookId");
    const bookNameInput = document.getElementById("bookName");
    const isbnInput = document.getElementById("isbn");

    bookNameInput.value = btn.dataset.name;
    isbnInput.value = btn.dataset.isbn;
    idInput.value = btn.dataset.id;
};

export const modifyBook = async () => {
    const id = document.getElementById("bookId").value;
    const bookName = document.getElementById("bookName").value;
    const isbn = document.getElementById("isbn").value;

    try {
        const data = await fetchTextRequest(`/books/${id}`, "PUT", {bookName, isbn});
        alert("결과 : " + data);
        location.reload();
    } catch (e) {
        handleError(e);
    }
};

rent.js

import {fetchTextRequest, handleError} from "./util.js";

export const rent = async id => {
    try {
        const data = await fetchTextRequest(`/books/${id}/rent`, "POST");
        alert("결과 : " + data);
    } catch (e) {
        handleError(e);
    }
};

export const unRent = async id => {
    try {
        const data = await fetchTextRequest(`/books/${id}/unrent`, "POST");
        alert("결과 : " + data);
    } catch (e) {
        handleError(e);
    }
};

댓글

개발자  김철준

백엔드 개발자 김철준의 블로그입니다.

주요 프로젝트