[23.11.10] TIL

yy·2023년 11월 9일

개발일지

목록 보기
28/122

오늘 할 일

(->)3. queryraw 사용해보기
(->)4. soft delete join으로 구현해보는 방법 찾기

💥👊 트러블슈팅

1. 외래키와 싸우기

1:N 의 관계를 가지는 테이블에서 1의 위치의 있는 데이터를 지우려고 하니 아래와 같은 에러가 떴다.

Foreign key constraint failed on the field: CategoryId

await prisma.menus.create({
      data: {
        CategoryId: Number(categoryId),
        UserId: Number(userId),
        name,
        description,
        image,
        price,
        order: Number(orderPlus),
      },
    });

이런 코드였는데 자꾸 에러가 떠서 의존하고 있는 테이블명 모두를 써줬다.
그리고 몇 시간 뒤에 아무리 생각해도 위의 코드가 맞을텐데 왜 안되지? 싶어서 다시 해봤는데 이번에는 외래키설정되어있는 데이터 모두 잘 삭제가 되는것이다?!
대체 이유가 뭘까...🧐


2. joi와 싸우기

회원가입에서 닉네임이 비밀번호에 들어가지 않도록 만들기
처음엔 조이로 커스텀 유효성 검사를 만들어서 진행했다.

const checkPassword = function (value, helpers, options) {
  const { nickname } = options.context;
  if (value.includes(nickname)) {
    return helpers.error('any.custom');
  }
  return value;
};

const createSignUp = joi.object({
  nickname: joi.string().alphanum().min(3).max(15).messages({
    'string.min': 'nickname를 3글자 이상으로 작성해주세요.',
    'string.max': 'nickname을 15글자 이하으로 작성해주세요.',
    'string.empty': 'nickname을 입력해주세요.',
  }),
  password: joi
    .string()
    .alphanum()
    .min(8)
    .max(20)
    .custom(checkPassword, 'any.custom')
    .messages({
      'string.min': 'password를 8글자 이상으로 작성해주세요.',
      'string.max': 'password를 20글자 이하으로 작성해주세요.',
      'string.empty': 'password를 입력해주세요.',
      'any.custom': 'password에 nickname이 포함되면 안됩니다.',
    }),
  type: joi.string().valid('OWNER', 'CUSTOMER').messages({
    'any.only': 'CUSTOMER와 OWNER 중 선택하여 입력해주세요.',
  }),
});

password의 custom부분을 보면 checkPassword라는 함수를 넣었고, 만약 에러가 발생하면 'any.custom '라는 에러이름이 뜨도록 했다.
checkPassword라는 함수는 매개변수로 value, helpers, options를 받는다. value는 password를 받고, helpers 는.. 공식문서를 보면 아래와 같이 나와있다.이름이랑 같게 도와주는 역할인가보다..
options는 내가 사용할 nickname이 들어있는 객체이다.
그래서 내가 만든 함수를 보게 되면 nickname이라는 값을 options.context에서 받아와서 password인 value에 포함되어있으면 any.custom이라는 에러를 발생하고, 아니면 password를 반환하는 함수다.

이제 실행하면 아래와 같이 에러가 떴다
보다시피 nickname과 password가 같은 값이 전혀아닌데도 any.custom 에러가 뜬 것.

혼란하다 혼란해. 사실 처음엔 options.context 에 nickname이 없어서 아래와 같이 context안에 명확하게 nickname을 넣어주는 작업을 했다.

const validation = await createSignUp.validateAsync(req.body, {
      context: {
        nickname: req.body.nickname,
      },
    });

그럼 custom을 쓰는 방법밖에 없을까. 아니 더 있었다.

password: joi
    .string()
    .alphanum()
    .min(8)
    .max(20)
    // .custom(checkPassword, 'any.custom')
    .disallow(joi.ref('nickname'))
    .messages({
      'string.min': 'password를 8글자 이상으로 작성해주세요.',
      'string.max': 'password를 20글자 이하으로 작성해주세요.',
      'string.empty': 'password를 입력해주세요.',
      'any.custom': 'password에 nickname이 포함되면 안됩니다.',
      'any.invalid': 'password에 nickname이 포함되면 안됩니다.',
    }),
  type: joi.string().valid('OWNER', 'CUSTOMER').messages({
    'any.only': 'CUSTOMER와 OWNER 중 선택하여 입력해주세요.',
  }),
});

위의 코드 중 disallow를 사용하는 방법이었는데 내가 원하는걸 완전히 해주지는 못했다. nickname = "qqqq", password = "qqqq1234"일때도 걸러줘야하는데 그러지못하고 password = "qqqq"일 때만 'any.invalid' 에러를 발생해준다.

이것저것 다 찾아보다가 결국엔 api코드에 이런 코드 더 넣었다.

if (password.includes(nickname)) {
      return res
        .status(400)
        .json({ mesaage: 'password에 nickname이 포함되면 안됩니다.' });
    }

업로드중..조이 왤케 어려운겨!

[참고자료]
https://joi.dev/api/?v=17.9.1#anycustommethod-description

profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글