프리온보딩 과제 7

Tasic·2021년 11월 29일
2
post-thumbnail

과제 정보 요약
구현 기간 : 21.11.22(18시) ~ 21.11.28 (22시)
자세한 내용은 Github 참고

들어가며

  • 이번 과제는 기존과 다르게 개인 과제 이고, 기간도 1주일로 넉넉하였습니다.
  • 그래서 이번 프로젝트는 Django로 우선 구현하고 완료 후에 Nest.js로 구현하는 것을 도전하기로 하였습니다.

프로젝트 구상

  • 이번 프로젝트의 핵심기능은 user가 trimId(차량)를 입력했을 때, 입력된 trimId를 이용해서 카닥에서 제공해주신 API를 이용해서 해당 차량의 앞/뒤 타이어 정보를 알아내서 알아낸 정보가 특정형식에 만족하면 DB에 저장하는 것입니다.
  • 저는 API에서 제공하는 정보가 앞/뒤 타이어로 나뉘어 있긴 하지만 어쨌든 타이어라는 공통적인 사항이기 때문에, 테이블에 앞/뒤 타이러라고 따로 컬럼을 나누지 않고 저장할 수 있도록 DB설계를 하였습니다. 즉 trimId에 해당되는 차량의 앞뒤 타이어가 다르면 2개의 row가 저장된다고 보시면 됩니다.
  • 또한 Data의 중복을 피하기 위해서 tires 테이블을 만들어서 타이어 정보가 중복되지 않도록 저장하고, user와 tire간의 관계는 user_tires라는 중간테이블로 맺었습니다.

Django

Nest.js

구현

입력데이터 예시

[
  {
    "id": "candycandy",
    "trimId": 5000
  },
  {
    "id": "mylovewolkswagen",
    "trimId": 9000
  },
  {
    "id": "bmwwow",
    "trimId": 11000
  },
  {
    "id": "dreamcar",
    "trimId": 15000
  }
]

타이어 정보를 등록하는 로직은 django와 nest.js와 조금 차이가 있습니다.
그래서 각각 설명하도록 하겠습니다.

django

  • 위와 같은 형태로 요청이 들어오면, UserTireRegisterSerializer 를 이용해서 데이터를 받습니다. many=True 옵션이 있으면 데이터를 여러개 받을 수 있습니다. 즉 위에 예시처럼 데이터를 받을 수 있습니다.
serializer = UserTireRegisterSerializer(data=request.data, many=True)
  • 유효성 검사는 Serializer 자체에서 해결하였고, 추가로 입력된 값이 1개 부터 5개 사이인지만 체크하였습니다.
  • 그 후, list를 순회하면서 다음과 같은 로직을 진행하였습니다.
    1. id가 등록된 user인지 검사
    2. tirmId를 이용하여 타이어 정보 요청
    3. 취득한 정보를 데이터 베이스에 등록
  • 단 list를 순회하다가 1,2 중 한곳에서 에러가 발생하면 (없는 id, 없는 trimId) 400 Error를 발생시켰습니다.
  • 여러번 DB에 create하다가 error가 발생하면, 롤백해야되는 상황이 생길 수 있으므로 transaction를 걸었습니다.
  • 또한 데이터 입력은 get_or_creat()를 사용해서 진행하였습니다
tire_obj, _ = Tire.objects.get_or_create(**tire)
UserTire.objects.get_or_create(user=user_obj, tire=tire_obj)

nest.js

  • ParseArrayPipe를 이용해서 TrimRegistrationDto를 받을 수 수 있도록 설정하였습니다.
  • 다만 ParseArrayPipe의 경우에는 Array의 길이를 체크하는 옵션이 없기 때문에, ParseArrayPipe를 상속받은 ParseArrayMaxMinLenPipe라는 pipe를 구현하여 적용하였습니다.
  @Post('/register-tires')
  @HttpCode(200)
  @UseGuards(AuthGuard())
  registerTires(
    @Body(new ParseArrayMaxMinLenPipe({ items: TrimRegistrationDto }, 1, 5))
    trimRegistrationDto: TrimRegistrationDto[],
  ) {
    return this.userService.registerTires(trimRegistrationDto);
  }
  • 그 후, Array를 순회하면서 다음과 같은 로직을 진행하였습니다. 이부분이 Django로 구현하는 것과 차이 점이 있습니다.
  • 우선 중복된 trimId, user 가 있다고 판단하고, 최대한 중복을 줄이기 위해서 노력하였습니다. 왜냐면 trimId의 경우에는 외부 API를 사용하기 때문에, 최대한 요청을 줄이는 것이 효율적이라고 판단하였습니다. 따라서 아래와 같이 처리하였습니다.
  async registerTires(trimRegistrationDto: TrimRegistrationDto[]) {
    // 등록하기 편하게 아래와 같이 trimID기준으로 data를 조작한다. 타이어 정보도 획득한다.
    // [{trimID : {id:[ids..], tires:[dto...]}}]
    const organizedData = trimRegistrationDto.reduce((pre, cur) => {
      if (pre[cur.trimId]) {
        pre[cur.trimId].id.add(cur.id);
      } else {
        pre[cur.trimId] = {
          id: new Set([cur.id]),
          tires: this.getTireInfo(cur.trimId),
        };
      }
      return pre;
    }, {});
  • 정리된 data형식은 다음과 같습니다.
    # 입력된 값 중 5000번 trimId을 입력한 user는 cardoc, cardoc2이고 
    # 5000번 trimId에 해당되는 타이어 요소는 tires입니다,
    [ 
      {
        "5000" : {
          "id":["cardoc", "cardoc2"],
          "tires":[
                   {"width": 260, "aspectRatio:60", "wheelSize":15}, 
                   {"width": 255, "aspectRatio:50", "wheelSize":16}
                  ]
               }
       }
     ]
  • 하지만 Typeorm의 경우에는 get_or_create() 가 없었고, 공통으로 사용되는 기능이기 때문에, Repository를 상속받아서 직접 구현하였습니다.
  • django의 get_or_creat()를 참고하였습니다.
export class ExtendedRepository<Entity> extends Repository<Entity> {
  async getOrCreate(dto: any): Promise<Entity> {
    const instance = await this.findOne(dto);
    if (instance) return instance;

    return this.save(dto);
  }
}

마치며

  • django에서 처음으로 DB저장용이 아닌 용도로 Serialize를 만들었는데, 기존에 사용했던 방식과 달랐기 때문에 새로웠고 로직구성이 더 명확하게 느꼈습니다.
  • nest.js의 경우에는 처음으로 nest.js와 typescript를 도전해봤는데, 상당히 좋은 경험이였습니다. 하지만 nest.js와 typescript를 이해하고 한 프로젝트가 아니기 때문에, 에러처리와 효율성 측면에서 부족한 부분이 있습니다. 추후 문법과 구조들을 학습하면서 리펙토링을 하면 좋을 것 으로 생각됩니다.
profile
블로그 옮겼습니다 (https://jotasic.github.io)

0개의 댓글