error handling (with typescript)

amazing_hamster·2023년 8월 22일

express

목록 보기
2/2

errorGenerator

errorGenerator라는 별도의 함수를 두고 error가 발생할 때 동적으로 statusCode를 넣어주는 방식으로 변경!

기존의 에러 핸들링

userController.ts의 일부


export const signUpUser = async (
  req: IRequest,
  res: Response,
  next: NextFunction
) => {
  try {
    const { name, email, password } = req.body;
    if (!name || !email || !password) {
      //ErrorGenerate 만들기
      throw new Error("항목을 빠짐없이 입력해주세요");
    }

    const newUser = await createUserService(name, email, password);

    res.status(200).json(newUser);
  } catch (error) {
    next(error);
  }
};

try catch를 이용해서 error가 발생하면 next를 이용하거나
throw new Error를 이용한 early return 방식 사용해서 errorMiddleware로 넘기는 방식

logger.ts


function errorMiddleware(error : Error, req : Request, res : Response, next : NextFunction) : void {

  logger.error(error);
  res.status(400).send(error.message);
}

errorMiddleware의 모습 기존에는 statusCode를 400으로 박아놓고 사용

변경 후

error.ts

export interface IError extends Error {
  statusCode?: number | null | undefined;
}

errorGenerator를 보여주기 전에 먼저 사용할 에러에 대한 type을 선언해줌
기본 Error type을 extends 해줬다
null 이랑 undefined가 들어간 이유는 statusCode에서 숫자가 안 들어오게 될 때를 다뤄주기 위함이다!

errorGenerator.ts

import { IError } from "error";

export const errorGenerator = (
  errorMessage: string,
  statusCode: number
): IError => {
  const error: IError = new Error(errorMessage);
  error.statusCode = statusCode;
  return error;
};

errorMessage와 statusCode를 인자로 넣어준다.
new Error에 errorMessage를 넣어서 에러를 생성해주고, error 객체에 statusCode를 넣어준다!

userValidator.ts


export const validateUpdateUser = (
  req: IRequest,
  res: Response,
  next: NextFunction
) => {
  const updateValue = req.body;

  const schema = joi.object({
    name: joi.string().min(2).max(20).optional().pattern(nameReg),
    description: joi.string().optional(),
    uploadFile: joi.any(),
  });

  const { error } = schema.validate(updateValue);

  if (error) {
    const err = errorGenerator(error.details[0].message, 400);
    next(err);
  }
  next();
};

errorGenerator에 에러메세지랑 에러코드를 보내주고 next(err)로 에러미들웨어로 에러를 보내준다.

userController.ts

export const signUpUser = async (
  req: IRequest,
  res: Response,
  next: NextFunction
) => {
  try {
  
    const { name, email, password } = req.body;

    const newUser = await createUserService(name, email, password);

    res.status(200).json(newUser);
  } catch (error) {
    next(error);
  }
};

userService.ts

export const createUserService = async (
  name: string,
  email: string,
  password: string
): Promise<IUser> => {
  const user = await findUserByEmail(email);

  if (user) throw errorGenerator("이미 존재하는 이메일 입니다.", 400);

  const hashedPassword = await bcrypt.hash(password, 10);
  const createdUser = await create(name, email, hashedPassword);

  return createdUser;
};

error.message를 errorGenerator의 첫번째 인자로 넘겨주고 상황에 맞는 statusCode를 직접 넘겨준다.
thorw ,next()로 넘기는 건 기존과 동일

logger.ts

function errorMiddleware(
  error: IError,
  req: Request,
  res: Response,
  next: NextFunction
): void {
  if (error.statusCode === null || error.statusCode === undefined)
    error.statusCode = 500;

  logger.error(
    `statusCode: ${error.statusCode} | Error Message: ${error.message} `
  );

  res.status(error.statusCode).send(error.message);
}

기존에는 statusCode를 직접 상수로 써주었지만 지금은 error.statusCode로 넘겨준다!
그리고 내가 핸들링해주지 못한 에러의 경우 statusCode가 없을테니까 statusCode가 null이거나 undefind 일 경우엔 statusCode를 500으로 해서 처리~

0개의 댓글