[what-to-wear-today] 401, 404 에러 핸들링을 해보다.

ekil·2022년 12월 1일
0

생애첫

목록 보기
2/2
post-thumbnail

배경

지난 포스팅에서는 what-to-wear-today: 도시 이름을 입력하면 현재 기온에 맞는 옷차림을 알려주는 서비스netlify로 배포한 이야기를 다뤘습니다.

깃허브에 올린 코드를 클론하면 API key가 없어 401 에러가 발생하기에 아예 배포를 하기로 한 거였는데요.

배포는 했지만, 언젠가 API key가 만료되거나 어떤 오류가 발생해 401 에러가 발생할 가능성이 여전히 남아있을 것이라 생각했습니다.

이에 어떤 에러가 발생한 상태이며 어떤 조치를 취하면 좋은지를 사용자에게 알릴 수 있는 페이지를 만들기로 했습니다.

그리고 도시 이름 철자를 틀리는 등, OpenWeatherMap 서비스에 등록돼 있지 않은 도시 이름을 입력하면 404 에러가 발생한다는 것도 확인할 수 있었습니다.

그래서 이 두 에러를 핸들링해 보기로 했어요.

📍 그냥 할 수 있을 것 같아서 구글링하지 않고 제 생각대로 구현한 것이라 미흡한 점이 있을 수 있습니다! 유튜브로 에러 핸들링 관련 영상 몇 개 보고 그냥 해봤어요.

에러 코드 받기

OpenWeatherMap에서 정보를 받아오기 위해 Axios 라이브러리를 사용했습니다.

이때 에러가 발생하면 알려달라고 Window의 alert 메서드를 사용하고만 있었습니다.

const searchWeather = async (event) => {
  if (event.key === 'Enter') { // 사용자가 Enter 키 누르면
    try {
      // await, axios로 날씨 정보 받아와 저장하라는 코드
    } catch (error) {
      alert(error); // 에러 정보 알려달라.
    }
  }
};

날씨 정보 받아와 저장하라는 코드는 지금 당장 중요한 게 아니라 생략했습니다. 깃허브에서 살펴볼 수 있어요.

catch 문 안에서 error 키워드로 에러 정보를 받을 수 있음을 확인했습니다. error를 콘솔에 출력해보고, error.response.status로 접근하면 상태 코드를 받을 수 있음을 확인했어요.

state 추가

서버가 보내주는 응답 코드는 매번 바뀌는 값입니다.

그 값이 무엇이냐에 따라 다른 처리를 해주고 싶었습니다.

변화하는 값이고, {} 블록 바깥에서도 그 값에 접근할 수 있어야 하므로 useState를 이용해 상태 코드를 저장하기로 했습니다.

const [responseCode, setResponseCode] = useState(0);

그리고 앞에서 살펴본 코드에 상태 코드를 변경하는 코드를 추가했습니다.

에러가 발생했을 때 각기 다른 처리를 해주려 하므로 alert 메서드를 사용한 코드는 지워줬어요.

const searchWeather = async (event) => {
  if (event.key === 'Enter') { // 사용자가 Enter 키 누르면
    try {
      // await, axios로 날씨 정보 받아와 저장하라는 코드
      setResponseCode(data.status);
    } catch (error) {
      setResponseCode(error.response.status);
    }
  }
};

에러 대처 고민

401 에러

401 상태 코드는 Unauthorized 에러를 의미합니다. 인증을 위해 추가 정보가 필요한 상황 등, 인증과 관련한 문제가 있을 때 보내주는 코드입니다. 이 포스팅에서도 추가 정보를 확인할 수 있어요.

netlify에 API key를 등록해두었기에, 이 에러는 발생 가능성이 그리 높지 않을 것 같았어요. 게다가 제가 만든 서비스는 로그인이나 회원가입 기능이 없거든요.

Seoul을 치려다 알파벳 하나라도 잘못 치면 바로 발생할 수 있는 404 에러처럼 일상적인 상황이 아닌 것 같았습니다.

그래서 401 에러에 대해서는 상황을 안내하는 새 페이지를 만들기로 했습니다.

404 에러

404 상태 코드는 Not Found 에러를 의미합니다. 요청 넣은 그 주소, 리소스를 찾을 수 없다는 의미입니다.

OpenWeatherMap 서버에서는 도시 이름을 잘못 입력하거나, OpenWeatherMap에 등록되어 있지 않은 도시명을 입력했을 때 404 코드를 보내주었어요.

401보다 자주 마주칠 수 있는 상황이었습니다.

이때 새 페이지를 만들어 상황을 안내하면, 다시 시작 페이지로 돌아가는 버튼을 추가해야 했습니다. 사용자는 자신이 검색한 검색어를 확인할 수도 없었죠. 그 상황이 조금 짜증날 것 같았습니다.

만약 모달창을 띄워 상황을 안내한다 해도 비슷할 것 같았습니다. 모달창이 검색창을 가려 사용자는 자신의 검색어를 확인하지 못할 수 있고, 옷차림 정보를 기대하고 엔터 키를 눌렀다가 모달창이 빡 나타나면 당황+짜증이 날 것 같았어요.

길을 걸으면서 어떻게 하면 좋을지 고민했습니다.

결과(날씨와 옷차림 정보)를 띄워줄 때와 같이, 어떤 문제가 발생한 것이며 어떤 처리를 하면 좋을지 안내하는 문구가 나타나면 좋겠다는 결론에 이르게 되었어요. 사용자가 덜 놀라고, 검색창을 가리지 않아 자신이 무엇이라 검색했는지도 쉽게 확인할 수 있을 것이기 때문이에요.

그래서 404 에러에 대해서는 상황을 안내하는 문구를 보여주기로 했습니다.

에러 핸들링 코드 추가하기

401 에러

401, 404 외에 다른 에러도 당연히 발생할 수 있을 거라고 생각했어요.

지금 당장 처리하진 않을 것이지만, 다음에 처리할 때가 있을 거라 생각하고 switch문을 이용했습니다.

앞서 만들었던 state인 responseCode가 401인 케이스와 default 케이스 둘을 추가했습니다.

switch (responseCode) {
  case 401:
    return <ErrorPage />; // 따로 만든 401 에러 페이지 컴포넌트
  default:
    return (
      // 서비스 제목, 검색창, 결과 화면 등을 위한 JSX 코드
    );
}

ErrorPage라는 컴포넌트를 새로 만들었어요. 전체 코드는 깃허브에서 확인할 수 있습니다.

이런 화면이 나타나도록 했습니다.

401 코드를 받을 때 볼 수 있는 화면이라 API key를 주석 처리함으로써도 볼 수 있었을 것 같은데, 그때는 이 생각을 못했습니다.

그래서 react-router-dom으로 /error 경로일 때 이 페이지를 보여달라고 했어요.

App 컴포넌트를 이렇게 수정했습니다.

function App() {
  return (
    <Routes>
      <Route path='/' element={<Home />}></Route>
      <Route path='/error' element={<ErrorPage />}></Route>
    </Routes>
  );
}

localhost에서는 url 뒤에 /error를 추가해 이 페이지를 확인할 수 있었는데, 배포한 url에서는 /error를 입력하니 404 에러가 발생했습니다. 리액트로 만든 SPA(Single Page Application)였기 때문인데요. 이 내용은 저번 글에서 살짝 언급한 바 있습니다!

/error를 입력해 확인하는 것보다 API key 정보를 없애보고 이 페이지를 잘 보여주는지 확인해 보는 게 더 좋을 것 같아요.

게다가 이 글을 작성하며 다시 보니, 에러 페이지에 원래 페이지로 돌아가는 버튼이 없네요. 인증 에러가 발생하면 서비스를 이용하기 어려울 테니 필요 없을까요? 고민해 봐야겠습니다.

404 에러

404 에러도 마찬가지로 switch문을 이용하려 했습니다.

그런데, JSX 문법에서는 switch문이나 if ... else문을 이용할 수 없습니다!

저는 검색창을 보여주면서 그 아래에 404 에러 관련 메시지를 나타내고 싶었기에 JSX 코드를 적는 return문 안에 코드를 추가하고 싶었는데요.

고민하다가 굳이 switch문을 쓸 필요가 없음을 깨달았습니다.

뭐가 문제인지 답이 명확히 떠오르지 않을 땐 차분히 상황을 글로 정리해보는 걸 추천해요.

저는 노션에 이렇게 적어보았습니다.

(content라는 변수를 let 키워드로 정의한 뒤, 조건에 따라 그 내용을 바꿔주는 방법도 시도해 봤는데요. 서비스에 딱 접속했을 땐 서버에 아무런 요청을 보내지 않은 상태잖아요. 그래서 데이터를 담을 변수가 비어있는 상태인데 그 변수 객체에 접근하려 해서인지 오류가 발생했습니다.)

이렇게 정리했어요.

{Object.keys(result).length !== 0 && ( // result 변수(=데이터 객체 담을 변수)의 길이가 0이 아니라면
  // 결과 보여주는 JSX 코드
)}

{responseCode === 404 && ( // 응답 코드가 404라면
  // 에러 메시지 보여주는 JSX 코드
)}

result 변수는, 서버에서 준 날씨 정보 객체를 담을 변수인데요. 그 길이가 음수가 될 순 없으니, 0이 아니라면, 이라고 조건을 적었습니다.

의미 전달을 명확히 하기 위해 0보다 크다면, 이라고 쓰는 게 나을 것 같기도 하네요.

최종 코드

Home 컴포넌트에서 서버 통신해 데이터도 받아오고, 응답 코드 state도 관리하고, UI도 만들었는데요.

역할에 맞게 컴포넌트를 분리하고 싶은데,, 솔직히 말할게요. 하다가 말았습니다... 언젠가 수정하겠습니다.

switch (responseCode) {
  case 401:
    return <ErrorPage />; // 따로 만든 401 에러 페이지 컴포넌트를 리턴해라.
  default:
    return (
      // 서비스 제목, 검색창 나타낼 JSX 코드
      
      {Object.keys(result).length !== 0 && ( // result 변수(=데이터 객체 담을 변수)에 값이 있다면,
  	  // 결과(날씨와 옷차림 정보) 보여주는 JSX 코드
      )}

      {responseCode === 404 && ( // 응답 코드가 404라면
      // 에러 메시지 보여주는 JSX 코드
      )}
    );
}

화면 보기

401 에러 안내

노트북처럼 화면이 큰 기기에서 보면 위와 같이 나타납니다.

반응형 웹페이지로 만들었기에, 모바일에서는 이렇게 확인할 수 있습니다.

404 에러 안내

노트북처럼 화면이 큰 기기에서 보면 위와 같이 나타납니다.

반응형 웹페이지로 만들었기에, 모바일에서는 이렇게 확인할 수 있습니다.

마무리

에러가 발생했음을 그냥 콘솔에 남겨 달라거나, Window의 alert 메서드 이용해 알려달라는 간단한 처리는 해봤지만, 이런 식의 처리는 처음 해봤습니다.

모든 에러에 대응할 페이지를 만든 것은 아니지만, 가장 자주 발생할 것 같은 404 에러에 대해 사용자에게 현재 상황을 알릴 수 있는 문구를 추가한 것이 뿌듯했습니다. :>

📍 깃허브에서 전체 코드와 서비스 간단 설명을 확인할 수 있습니다.

📍 배포한 서비스는 여기에서 둘러볼 수 있습니다!

profile
좋아하는 일을 잘함으로써 먹고살고 싶은 프론트엔드 개발자입니다.

0개의 댓글