내일배움캠프 TIL (230312): [NestJS] must be a number conforming to the specified constraints 타입 에러 해결

Jiumn·2023년 3월 29일
0

Axios post 요청 시 에러 발생

오늘의 할 일은 워크샵 수강 신청 API와 프론트 통신 연결을 진행하는 것.

// 워크샵 문의 신청하기
function orderWorkshop() {
  let query = window.location.search;
  let param = new URLSearchParams(query);
  let workshopId = param.get('workshopId');

  const category = document.querySelector('.workshop-category').textContent;
  const company = document.getElementById('company').value;
  const name = document.getElementById('name').value;
  const email = document.getElementById('email').value;

  const phone_number = document.getElementById('phone_number').value;
  const wish_date = document.getElementById('wish_date').value;
  let wish_location =
    document.getElementById('input-address').value +
    ' ' +
    document.getElementById('input_addr_detail').value;
  const member_cnt = document.getElementById('member_cnt').value;
  const purpose = document.getElementById('purpose').value;
  const etc = document.getElementById('etc').value;

  let orderForm = new FormData();
  orderForm.append('company', company);
  orderForm.append('name', name);
  orderForm.append('email', email);
  orderForm.append('phone_number', phone_number);
  orderForm.append('wish_date', wish_date);
  orderForm.append('wish_location', wish_location);
  orderForm.append('member_cnt', member_cnt);
  orderForm.append('etc', etc);
  orderForm.append('category', category);

  const user_id = 1;

  axios
    .post(`/api/workshops/${workshopId}/order`, {
      workshop_id: workshopId,
      user_id: user_id,
      orderWorkshopDto: {
        company,
        name,
        email,
        phone_number,
        wish_date,
        wish_location,
        member_cnt,
        etc,
        category,
      },
    })
    .then((res) => {
      alert(res);
    })
    .catch((err) => {
      console.log(err);
    });
}

프론트에서 axios로 post 요청을 보내는 코드를 작성했으나 에러가 발생했다.
브라우저 콘솔을 확인해보니 post 요청이 안 되고 get 요청만 되는 것으로 보였다.

제출하는 함수가 작동하는 button 태그의 속성이 submit 타입이라서 요청 없이 바로 리다이렉트되는 것이 문제인 것 같았다. form 태그에 addEventListerner 메서드를 통해 submit 이벤트 발동 시 e.preventDefault()를 콜백함수로 지정했다. preventDefault() 메서드는 해당 이벤트에 대한 브라우저의 기본 동작을 실행하지 않도록 만든다.

(사실 form data를 사용하지 않고 input 태그 안의 value만 받아와서 onclick 메서드로 전달해줘도 된다.)

const form = document.getElementById('form');

form.addEventListener('submit', function (e) {
  e.preventDefault();

위 코드를 추가해주니 post 요청 자체는 정상 작동했다.

하지만 또 다른 에러 메시지가 반환됐다.

{
  "success": false,
  "timestamp": "2023-03-12T05:12:37.733Z",
  "statusCode": 400,
  "message": [
    "property workshop_id should not exist",
    "property user_id should not exist",
    "property orderWorkshopDto should not exist",
    "단체명을 입력해 주세요",
    "단체명을 정확히 입력해 주세요",
    "신청자의 성함을 입력해 주세요",
    "신청자의 성함을 정확히 입력해 주세요",
    "이메일을 입력해 주세요",
    "이메일을 정확히 입력해 주세요",
    "email must be an email",
    "전화번호를 입력해 주세요",
    "전화번호를 정확히 입력해 주세요",
    "희망하는 날짜를 선택해 주세요",
    "희망하는 날짜를 정확히 선택해 주세요",
    "워크샵을 희망하시는 이유를 적어주세요",
    "purpose must be a string",
    "원하시는 워크샵 수행 위치를 기입해 주세요",
    "wish_location must be a string",
    "희망하시는 인원을 적어 주세요",
    "member_cnt must be a number conforming to the specified constraints",
    "etc must be a string",
    "online, offline 둘 중 하나를 택해 주세요",
    "category must be a string"
  ],
  "error": "Bad Request"
}

메시지의 형태를 보니 nestjs의 class-validator 데코레이터에서 발생하는 문제로 보였다.

    "property workshop_id should not exist",
    "property user_id should not exist",
    "property orderWorkshopDto should not exist",

우선 이 부분 에러 해결을 위해 workshop_id, user_id를 body로 보내주지 않고 orderWorkshopDto를 키로 지정하지 않고 중괄호 안에 데이터 값만 보냈다.
workshop_id와 user_id는 body로 전달되기는 하지만 dto로 전달되는 값이 아니라서 중괄호 안에 입력하면 에러가 발생하는 듯)

axios
    .post(`/api/workshops/${workshopId}/order`, {
      company,
      name,
      email,
      phone_number,
      member_cnt,
      wish_date,
      category,
      purpose,
      wish_location,
      etc,
    })
    .then((res) => {
      alert(res.data.data.message);
      location.href = '/mypage/workshops';
    })
    .catch((err) => {
      console.log(err);
      if (err.response.data.statusCode === 401) {
        alert('로그인 후 이용 가능합니다.');
      }
    });
}

그 결과 대체로 에러 메시지는 해결되었지만 member_cnt 값에서 "member_cnt must be a number conforming to the specified constraints" 에러가 사라지지 않았다.


[NestJS] must be a number conforming to the specified constraints - body dto 타입 에러 해결

해당 에러는 entity에 선언된 제약 조건과 일치하지 않은 값이 전달되어 발생하는 에러다.

  @IsNumber()
  @IsNotEmpty({ message: '희망하시는 인원을 적어 주세요' })
  @ApiProperty({
    example: 20,
    description: '워크샵에 참가하길 희망하는 총 인원',
    required: true,
  })
  @Column('int', { name: 'member_cnt', nullable: false })
  member_cnt: number;

entity에 따르면 인원수(member_cnt)는 number 타입으로 전달되어야 하는데 전달되는 과정에서 number가 아닌 다른 타입으로 전달되는 것으로 보였다.

entity 파일의 해당 컬럼 부분에 @Type(() => Number) 데코레이터를 추가해서 해결했다.

  @Type(() => Number) // 숫자 타입으로 변환
  @IsNumber()
  @IsNotEmpty({ message: '희망하시는 인원을 적어 주세요' })
  @ApiProperty({
    example: 20,
    description: '워크샵에 참가하길 희망하는 총 인원',
    required: true,
  })
  @Column('int', { name: 'member_cnt', nullable: false })
  member_cnt: number;
profile
Back-End Wep Developer. 꾸준함이 능력이다.

0개의 댓글