프로그래머스 2020 Dev-Matching : 웹 프론트엔드 과제 복기
https://github.com/woohyeonjo/ilovecat
에러를 잘 처리하는 것은 사용자에겐 향상된 UX를 제공하고 개발자에겐 에러에 대한 확실한 인지와 개선을 할 수 있도록 한다. 그렇다면 좋은 에러 처리란 무엇일까? 검색을 하다가 자바스크립트 에러 핸들링 : 신뢰 할 만한 가이드라는 글을 읽게되었고 그를 바탕으로 프로젝트에 에러 핸들링을 해보았다. 하지만 여전히 좋은 에러 처리가 무엇인지는 잘 모르겠다. 많이 해보고 겪어봐야 느낌이 올 것 같다.
발생한 지점에서 바로 에러를 처리하면 최하위의 모든 지점에서 에러를 처리해줘야하니 최상위로 보내서 처리하는 것이 좋겠다고 생각하였다. 이 프로젝트에서는 App 컴포넌트가 최상위가 되겠다.
// theCatAPI.js
/* eslint-disable no-useless-catch */
const API_ENDPOINT = 'https://api.thecatapi.com/v1';
const request = async url => {
try {
const response = await fetch(url);
if(response.ok) {
const data = await response.json();
return data;
} else {
const errorData = await response.json();
throw errorData;
}
} catch(e) {
throw {
message: e.message,
status: e.status
};
}
};
const api = {
fetchCats: async keyword => {
/*
keyword로 breed를 찾고 각 breed의 id로 이미지를 찾는다.
*/
try {
const breeds = await request(`${API_ENDPOINT}/breeds/search?q=${keyword}`);
const requests = breeds.map(async breed => {
return await request(`${API_ENDPOINT}/images/search?limit=20&breed_ids=${breed.id}`);
});
const responses = await Promise.all(requests);
const result = Array.prototype.concat.apply([], responses);
return {
isError: false,
data: result
};
} catch(e) {
return {
isError: true,
data: e
};
}
},
fetchRandomCats: async () => {
/*
랜덤으로 20개의 고양이 사진을 리턴한다.
*/
try {
const result = await request(`${API_ENDPOINT}/images/search?limit=20`);
return {
isError: false,
data: result
};
} catch(e) {
return {
isError: true,
data: e
};
}
}
};
export { api };
async
, await
으로 처리하는 것이였다. 따라서 try-catch로 에러 핸들링을 하였다.fetch API
는 request
함수 안에서만 사용된다.response
가 ok
일 때만 정상 데이터가 리턴된다.fetch API
요청에 대한 에러는 { message: String, status: String }
형태로 throw
된다.{ isError: boolean, data: Object }
형태로 다시 상위로 throw
된다. const searchingSection = new SearchingSection({
$target,
keywords,
onSearch: async keyword => {
loading.toggleSpinner();
const response = await api.fetchCats(keyword);
if(!response.isError){
setItem('data', response.data);
resultsSection.setState(response.data);
loading.toggleSpinner();
} else {
error.setState(response.data);
}
},
onRandom: async () => {
loading.toggleSpinner();
const response = await api.fetchRandomCats();
if(!response.isError){
setItem('data', response.data);
resultsSection.setState(response.data);
loading.toggleSpinner();
} else {
error.setState(response.data);
}
}
});
error code
에 따라 다른 에러 화면으로 랜더링된다. // Error.js
export default class Error {
constructor({ $target }) {
this.$target = $target;
this.errorData = null;
this.render();
}
setState(nextData){
this.errorData = nextData;
this.render();
}
render() {
if(!this.errorData) return;
this.$target.innerHTML = '';
const errorSection = document.createElement('section');
errorSection.className = 'error-section';
const errorImage = document.createElement('img');
errorImage.className = 'error-image';
errorImage.src = '/src/img/squarecat.jpg';
const statusCode = document.createElement('p');
statusCode.className = 'status-code';
statusCode.innerText = this.errorData.status;
const errorMessage = document.createElement('p');
errorMessage.className = 'error-message';
errorMessage.innerText = this.errorData.message;
const returnBtn = document.createElement('p');
returnBtn.className = 'return-btn';
returnBtn.innerText = '돌아가기';
returnBtn.addEventListener('click', () => {
location.reload();
});
errorSection.appendChild(errorImage);
errorSection.appendChild(statusCode);
errorSection.appendChild(errorMessage);
errorSection.appendChild(returnBtn);
this.$target.appendChild(errorSection);
}
}
프론트엔드 개발 프로젝트를 어떻게 시작할지 막막하던 차에 너무 좋은 글 보고 깨달음 많이 얻고 갑니다. 아직 코린이지만 위 글에서 fetch()를 async/await이랑 같이 쓴 부분에 대해 궁금해서 글 남겨 봅니다. 제가 알기로 fetch()는
Response 객체를 래핑한 Promise 객체
를 반환하는 함수여서 따로 async/await이나 try catch 문없이Promise의 후속 처리 메서드
인then
이랑catch
를 사용하여 동기적인 후속 처리나 에러처리가 가능한 것으로 알고 있는데 위와 같이 한 이유가 있을까요?참고: https://velog.io/@sdc337dc/javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%86%B5%EC%8B%A0-fetch