각 Layer 별 Error Handling

Gaeun·2023년 1월 3일
0

wecode TIL

목록 보기
16/24
post-custom-banner

1. 각 레이어 별 에러

1-1. Controller Error

컨트롤러는 표현 계층, 즉 입력과 출력에 관련한 부분을 담당한다.

HTTP 통신을 처리하는 웹 서버의 관점에서는 http request (요청 입력), http response (응답 출력)을 담당하는 레이어이다. 따라서 통신이 처음 시작될 때, 사용자로 부터 받은 정보를 클라이언트(프론트엔드)가 전달해주면, 해당 입력에 대한 유효성 검증을 처리하며 에러 및 예외가 발생할 수 있다.

KEY_ERROR가 대표적이다. Request로 들어와야하는 정보 가운데 누락된 key가 있을 때를 지칭한다. 클라이언트가 키를 누락시켰다는 것은, request body라는 객체 안에 email 이라는 특정 키가 없는 것을 말한다.

// 에러 핸들링 전
console.log(req.body) // { password : 'myPassword' } 

const { email, password } = req.body

console.log(email) // undefined
console.log(password) // 'myPassword'

if (!email) {
    throw new Error('KEY_ERROR')
} // 에러 발생 시점

----------------------------------------------------------------
// 에러 핸들링 후

// 키에러가 발생하지 않으나, 값이 빈 상태

console.log(req.body) // { email: '', password: 'myPassword' }

const { email, password } = req.body

console.log(email)    // ''
console.log(password) // 'myPassword''

if (!email) {
    const err = new Error('KEY_ERROR')
    err.statusCode = 400;
    throw err
} // 에러 발생하지 않음.

입출력 외에도 컨트롤러가 하는 일을 따로 정해두었다면, 해당 작업중 발생 가능한 에러를 사전에 핸들링 해두는 것이 좋습니다. 사용자 입력이 잘못되었다면, 주로 400번대 http status code를 보낸다.

1-2. Service Error

서비스 레이어는 주로 비즈니스 로직과 규칙을 설정하는 곳이다. 이 곳에는 보통 기획에 따른 비즈니스 규칙에서 비롯된,개발자가 직접 의도한 예외와 관련된 에러가 발생한다.

에러의 발생 위치는 Service 단 하위에 위치한 계층의 모듈과, 직접 이곳에서 호출하는 서비스 모듈의 에러가 발생할 수 있다.

만일 비즈니스 규칙에 위반되는 사항이 발생가능하다면 꼭 이곳에서 필히 해당 문제의 경우에 상응한 Status Code와 함께 에러를 발생시켜야 한다. 사용자의 요청의 문제가 아니라 내부 처리 과정 중 문제라면 500번대 Status Code를 보내는 것이 일반적이다.

//service/userService.js

const userDao = require('../models/userDao')

// 정규 표현식을 이용한 비밀번호 유효성 검증
const signUp = async (name, email, password, profileImage) => {
    const pwValidation = new RegExp(
      '^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,20})'
    );
    if (!pwValidation.test(password)) {
        const err = new Error('PASSWORD_IS_NOT_VALID');
        err.statusCode = 409;
        throw err;
    }
    const createUser = await userDao.createUser(
        name,
        email,
        password,
        profileImage
        );
      
    return createUser;
  };
  
  module.exports = {
      signUp
  }

1-3. Dao Error

데이터 액세스 계층은 주로 영속적인 저장소와 관련된 코드를 작성하는 곳 이다. 주로 데이터 베이스 드라이버가 위치하는 곳이기 때문에 데이터 베이스에 의존적인 에러가 발생할 수 있다.

아울러 Node + Express와는 다른 외부 시스템으로서 연동되어 있고, 이 때 주로 비동기 호출을 하기 때문에, 비동기 에러 핸들링에 적합한 방법을 이용해야 한다. 만일 데이터베이스의 문제로 에러가 발생한다면 500번대 status code를 보낸다. 나머지 예외적인 사항(데이터 없음, 이상 현상)에서는 적절한 status code 및 에러를 던지면 된다.

const { DataSource } = require('typeorm');

const myDataSource = new DataSource({
    type: process.env.TYPEORM_CONNECTION,
    host: process.env.TYPEORM_HOST,
    port: process.env.TYPEORM_PORT,
    username: process.env.TYPEORM_USERNAME,
    password: process.env.TYPEORM_PASSWORD,
    database: process.env.TYPEORM_DATABASE
})

myDataSource.initialize()
  .then(() => {
    console.log("Data Source has been initialized!");
  })
  .catch((err) => {
    console.error("Error during Data Source initialization", err);
    myDatasource.destroy()
  });

const createUser = async ( name, email, password, profileImage ) => {
	try {
		return await myDataSource.query(
		`INSERT INTO users(
			name,
			email,
			profile_image,
			password
		) VALUES (?, ?, ?, ?);
		`,
		[ name, email, password, profileImage ]
	  );
	}
	catch (err) {
    const err = new Error('INVALID_DATA_INPUT');
    err.statusCode = 500;
    throw err;
	}
};

module.exports = {
  createUser
}

2. Summary

  • Controller - Service - Dao 각 레이어 별로 각기 다른 목적을 위한 에러 핸들링이 적용
  • 에러가 발생하는 위치와 실제 에러 메세지를 던지는 위치가 실제와 상이할 수 있음
  • 각 레이어별 에러 핸들링 시 동기, 비동기적 에러 처리에 유의하여 코드를 작성
profile
🌱 새싹 개발자의 고군분투 코딩 일기
post-custom-banner

0개의 댓글