[Week8] Node.js 기반의 REST API 구현(13)

Younha Lee·2026년 3월 4일

TIL

목록 보기
38/60

JWT와 예외 처리를 활용한 API 리팩토링

지난 시간에는 비동기를 활용해 주문 API를 완성했고, 이번 시간에는 JWT와 Request의 Headers를 활용해서 API 전반에 JWT를 적용하는 방향으로 코드를 수정해 볼게요.
추가적으로 try...catch 를 활용한 예외 처리 방법도 함께 배워봤어요.

JS 에러 객체 (Error Object)

에러가 발생하면 에러 메시지가 나오며 어떤 에러인지, 어느 부분에서 발생한 것인지를 알려줘요. 이렇게 에러 원인을 파악할 수 있는 이유는 자바스크립트에 '에러 객체'가 존재하기 때문이에요.

  • Error(): 런타임 오류 발생 시 던져지는 기본 오류 객체예요.
  • SyntaxError(): 구문이 이상한 경우 던져지는 오류 객체예요.
  • ReferenceError(): 잘못된 참조를 알려주는 오류 객체예요.
  • 그 외에도 EvalError() , RangeError() 등등 다양하게 존재해요.
let error = new Error('에러 객체');

console.log(error.name); // Error
console.log(error.message); // 에러 객체
console.log(error.stack);
/*
Error: 에러 객체
    at Object.<anonymous> (경로 생략)
    ...
*/

try-catch 와 throw 구문

try...catchtry 블록 안에서 코드를 실행시키고, 예외 또는 에러가 발생한 경우 즉시 실행을 중지한 뒤 catch 블록에서 에러를 처리하는 구문이에요.

try {
  // 실행할 코드
} catch (err) {
  console.log(err); // 에러 발생 시 처리할 코드
}

기존에 사용하던 if-else 예외 처리와의 큰 차이점은 '실행 중인 코드가 중간에 멈추느냐'의 차이예요. if-else 의 경우 에러가 발생하더라도 코드가 계속 실행될 수 있는 반면, try...catch 는 즉시 코드를 멈추고 예외 처리를 진행한다는 점에서 훨씬 안전해요.

throw
throw 키워드는 개발자가 직접 예외를 발생시킬(던질) 수 있는 키워드예요. 예외가 던져지면 해당 함수의 실행은 중지되고 catch 블록으로 예외가 넘어가요. (catch 가 없다면 프로그램이 강제 종료돼요!)

try {
  let obj = {
    email: 'kim@mail.com'
  }
  if (!obj.name) {
    throw new SyntaxError("객체에 이름이 없습니다.");
  } else {
    console.log(obj.name);
  }
} catch (err) {
  console.log(err.name); // SyntaxError
  console.log(err.message); // 객체에 이름이 없습니다.
}

추가적으로 finally 블록을 같이 사용하면, 에러 발생 여부와 상관없이 무조건 실행시켜야 하는 코드를 작성할 수 있어요.

try {
  // 동작 코드
} catch (err) {
  // 에러 처리 코드
} finally {
  // 항상 동작하는 코드
}

JWT 복습 및 모듈 내장 에러

JWT(JSON Web Token)를 다시 복습해 볼게요.

const jwt = require('jsonwebtoken');

// 토큰 생성 (Sign)
const token = jwt.sign({ name: "bar" }, process.env.PRIVATE_KEY);
console.log(token);

// 토큰 검증 및 디코딩 (Verify)
const decoded = jwt.verify(token, process.env.PRIVATE_KEY);
console.log(decoded); // { name: 'bar', iat: 172737848 }

jsonwebtoken 모듈에는 기본적으로 제공되는 내장 에러 객체들이 있어요. 이를 활용해 예외 처리를 깔끔하게 할 수 있어요.

  • TokenExpiredError: 토큰의 유효기간이 만료된 경우 발생하는 에러예요.
  • JsonWebTokenError: 토큰이 유효하지 않을 때 발생하는 에러예요.
  • NotBeforeError: 현재 시간이 토큰의 nbf(Not Before) 설정 시간 이전일 때 발생하는 에러예요.

주문 & 장바구니 API에 JWT 적용하기

로그인할 때 생성된 토큰을 쿠키 등에 저장하고, 프론트엔드에서 요청 시 Request Headers 안의 Authorization 에 담아서 보내준다고 가정해 볼게요.
백엔드에서는 받아온 요청에서 토큰을 꺼내 jwt.verify() 를 통해 올바른 사용자인지 확인하고 데이터를 사용해요.

장바구니 담기, 조회, 삭제 기능 등에서도 동일하게 JWT를 이용해 사용자 정보를 가져오도록 수정했고, 이번에는 앞서 배운 try...catch 를 사용해 예외 처리까지 추가해 주었어요.

// 컨트롤러 부분
const someController = (req, res) => {
  // ...
  const userId = decodeUserId(req, res);

  // 발생한 에러 객체의 타입에 따라 알맞은 응답을 내려줘요.
  if (userId instanceof jwt.TokenExpiredError) {
    return res.status(StatusCodes.UNAUTHORIZED).json({
      message: "로그인 세션이 만료되었어요.",
    });
  }

  if (userId instanceof jwt.JsonWebTokenError) {
    return res.status(StatusCodes.BAD_REQUEST).json({
      message: "토큰이 이상해요. 다시 확인해 주세요.",
    });
  }
  
  // ... 정상 로직 처리
}

// 토큰 디코딩 공통 함수
const decodeUserId = (req, res) => {
  try {
    const token = req.headers.authorization;
    const decoded = jwt.verify(token, process.env.PRIVATE_KEY);
    
    return decoded.userId;
  } catch (err) {
    console.log(err.name);
    console.log(err.message);

    // 에러가 발생하면 에러 객체 자체를 리턴해서 컨트롤러가 처리하게 해요.
    return err;
  }
};



헤더의 jwt로 인가를 구현한 캡쳐본입니다.

profile
할 땐 하고 놀 땐 노는 일일놀놀입니다.

0개의 댓글