티스토리 뷰

Github Repo

https://github.com/wanted-wecode-subjects/eight-percent-subject

개요

  • 회원, 계좌, 입/출금 API 만들기

기간

  • 2021.11.11 - 2021.11.13

개발 환경

  • TypeScript
  • NestJS
  • Sqlite3

사용 라이브러리

  • bcrypt
  • passport
  • typeorm
  • class-validator
  • class-transformer
  • passport-jwt
  • moment

구현 사항

요구사항

  • sqlite 사용
  • 거래내역 조회
    • 계좌의 소유주만 요청 가능
    • 거래일시 필터링
    • 출금/입금 필터링
    • 페이지네이션
    • 거래일시, 거래금액, 잔액, 거래종류(출금/입금), 적요
  • 입금
    • 계좌의 소유주만 요청 가능
  • 출금
    • 계좌의 소유주만 요청 가능
    • 계좌 잔액 내에서만 출금 가능
    • 잔액을 넘긴 출금 요청에 적절한 에러처리
  • 기타
    • 유닛 테스트 구현
    • functional test 구현
    • 거래내역이 1억건 넘어갈 때를 고려
      • 1억건이 넘는 조회에 대한 설계 작성

DB 모델링

typeOrm foreign key가 안 들어올 때

@GetUser 데코레이터로 user에 대한 정보를 받아서 account 서비스에 넘긴 뒤 account를 생성하였는데 실제 테이블에 들어가서 확인해보니 NULL값으로 되어 있었습니다.
즉, foreign key가 제대로 입력되지 않았습니다.

그래서 jwtStrategy로 가서 user에 대한 정보를 모두 리턴하였습니다.

jwt.strategy.ts

  async validate(payload: any) {
    const { user_id, loginedAt } = payload;
    const user = await this.usersService.findOneByUserId(user_id);

    const tokenLoginedAt = new Date(loginedAt).getTime();
    const userLoginedAt = new Date(user.loginedAt).getTime();

    if (tokenLoginedAt !== userLoginedAt) {
      throw new UnauthorizedException('올바르지 않은 토큰입니다');
    }
    return { ...user };
  }

이후 테이블로 가서 확인해보니 해당 데이터가 입력되었습니다.
하지만 쓸데없는 정보나 보안상 이슈가 될 수 있는 비밀번호 같은 데이터가 들어가 논란이 생길 수 있었습니다.
그래서 기존에 줘야하던 정보(user_id, loginedAt) 이외에 user의 id 값을 넘겨보았습니다.

  async validate(payload: any) {
    const { user_id, loginedAt } = payload;
    const user = await this.usersService.findOneByUserId(user_id);

    const tokenLoginedAt = new Date(loginedAt).getTime();
    const userLoginedAt = new Date(user.loginedAt).getTime();

    if (tokenLoginedAt !== userLoginedAt) {
      throw new UnauthorizedException('올바르지 않은 토큰입니다');
    }
    return { id: user.id, user_id, loginedAt };
  }

이후 account를 생성한 뒤 테이블을 확인한 결과, 해당 row에 foreign key가 입력이 된 것을 확인할 수 있었습니다.

회고

Fact(사실)

  • 저번 프로젝트에서 비즈니스 로직을 컨트롤러 단에서 처리하였다.

Feeling(느낀점)

  • 해당 기능과 관련있는 커스텀 repository를 생성하지 않아 헷갈려서 비즈니스 로직을 컨트롤러 단에서 처리한 점이 아쉬웠다.

Finding(교훈)

  • 커스텀 repository를 정의하여 위와 같은 이슈가 발생하지 않도록 해야 겠다.

Future action(향후 계획)

  • 비즈니스 로직은 서비스 단에서 처리한다.
  • 트랜잭션을 사용하는 기능은 서비스 단에서 처리한다.
  • 도메인별 커스텀 repository를 정의한다.

Feedback(피드백)

  • 컨트롤러에서는 외부 요청과 응답에 대한 부분을 담당한다.
  • 서비스에서는 비즈니스 로직을 처리한다.
  • repository에서는 DB를 통해 데이터를 가져오거나 처리한다.
Comments