NestJS 07 | Create and Get Products

임종성·2021년 9월 8일
5

NestJS

목록 보기
7/13
post-thumbnail

지금까지 User라는 하나의 Entity만 사용하여 ORM을 처리했습니다. 이제 User와 OneToMany 관계인 Product Entity를 생성하여 유효한 사용자가 Product Entity를 생성하고 정보를 조회하는 기능을 구현해보겠습니다.

Product Entity

먼저 Relation을 제외한 Product Entity를 생성해줍니다.

  • @Column 내에서 먼저 type을 정하고, name, nullable, length와 같은 설정을 해줄 수 있습니다.
  • name은 Database 상에서 저장되는 Column의 이름을 설정해줍니다.
  • 생성시간을 정의해고자 할 때는 CURRENT_TIMESTAMP()를 default로 설정해줍니다.

currentTime Blocker

Default 값을 CURRENT_TIMESTAMP(6)으로 지정하면 ER_INVALID_DEFAULT: Invalid default value for 'created_at' 에러가 나타나며 Database 연결이 되지 않았습니다. 구글링을 통해 MySQL 설정에서 sql_mode에서 "NO_ZERO_IN_DATE,NO_ZERO_DATE"를 제거하는 방법을 시도해봤는데, 해결되지 않아 CURRENT_TIMESTAMP()로 변경하여 시도하니 잘 되었습니다. Column Type은 datetimetimestamp 두 경우 모두 같은 결과가 나왔습니다.

OneToMamy Relationship

Product Entity를 만들었으니, User와 Product의 관계를 설정해줘야 합니다. 한 명의 User가 여러 Product를 제작할 수 있고, 하나의 Product는 자신을 제작한 한 명의 User만 관계가 형성되므로 OneToMany 관계입니다. TypeOrm에서 관계 형성은 다음과 같이 해줍니다.

하나의 User에 대응하여 다수의 Product가 관계될 수 있으므로, @ManyToOne Decorator를 사용합니다. @ManyToOne Decorator의 parameter를 살펴보면,

  • Product Entity 안에 User Column이 들어가는 것이므로 Type을 Users라고 설정해줍니다.
  • User에서 Product에 접근하기 위해 user.products를 사용한다는 것을 명시합니다.
  • Column의 option으로 onDeleteonUpdate를 설정해주었는데, user의 Data를 지우거나 수정해도 그와 연관된Product의 Data가 영향받지 않도록 No Action으로 지정해줍니다.

User Entity에도 @OneToMany Decorato로 Column을 생성합니다. User에서 저장되는 Product는 다수이므로 Column Type을 Product[]과 같이 배열로 설정합니다.

Create Product

UserProduct의 관계를 형성해주었으니 이제 Product를 생성해봅시다.

productCreatDto

Product를 생성하기 위해 Product의 이름, 색깔, 사이즈가 필요합니다. 회원가입을 할 때 사용했던 것처럼 Product의 데이터 전송 객체(Dto)를 작성해줍니다.

ProductController

Product와 관련된 Request에 대응하는 Controler를 작성합니다. Guard와 Pipe를 활용하여 유효성 검사를 한 후 Service에서 Data를 처리해줍시다.

생성자에서 ProductService를 호출하며 Dependency Injection을 해줍니다. 우리가 Product를 생성하기 위해 필요한 Data는 생성하는 User의 정보와 Product의 Data입니다.

  • @UseGuards를 통해 유효한 JWT를 가진 User가 Request를 보내는지에 대한 판별을 하고, 유효하다면 JWT Payload에 포함되어 있는 User의 정보를 @GetUser 데코레이터를 통해 user Parameter로 추출할 수 있습니다.
  • @Body에서 생성하고자 하는 Product의 Data를 Dto 타입에 맞게 가져오고, ValidationPipe로 유효성 검사를 해줍니다.
  • 추출한 User 정보와 Product 정보로 Service의 createProduct 함수를 실행하여 Response로 반환합니다.

ProductService

ProductService에서 userproductCreatDto Data로 Product를 생성하여 DB에 저장하는 로직을 작성합니다.

product Type에 맞게 user, productCreateDto의 Data와 createUserId가 포함된 객체를product에 할당해줍니다. 그 후 productcreate하여 save하여 Database에 저장합니다.

Create Product

PostMan으로 Login하여 발급받은 JWT를 Header에 넣고 Product를 생성해봅시다.

User 정보와 Product 정보가 반환되며 제대로 생성되는 것을 확인할 수 있습니다!

Get Product by Using QueryBuilder

Product를 생성했으니 이제 다양한 조건에 따라 적절하게 QueryBuilder를 사용하여 Product의 정보를 불러와봅시다.

without User Information

특정 User가 생성한 Product의 정보를 가져오는데, User의 Information은 제외하고 연관된 Product의 정보만 불러오기 위해 InnerJoin을 사용합니다.

With User Information

관계된 User의 정보도 불러오고 싶은 경우 InnerJoinAndSelect를 사용합니다.

단순히 InnerJoinAndSelect만 사용하니 비밀번호를 포함한 모든 User의 정보를 불러왔습니다. 불필요하거나 민감한 정보를 제외하기 위해 InnerJoinSelect를 따로 사용해줍니다.

Concatenate

ProductName과 ProductColor, 그리고 10을 곱한 ProductSize로 새로운 ProductCode Column을 만들고 싶습니다. CONCAT, ROUND, AS를 활용해봅시다. GetMany를 사용하면 Database에 있는 Data만 불러오기 때문에 GetRawMany를 사용합니다.


Comment

NestJS를 사용한지 1주일 남짓이 지나며 어느정도 큰 그림이 그려지기 시작했습니다. Architecture뿐 아니라 Pipe, Intercepter, Guard, Exception Filter, Swagger 등 여러가지 기능에 대해 살펴보고, 실습을 통해 조금이나마 활용하며 이해를 도왔습니다.

이제 협업 프로젝트를 본격적으로 진행하게 되는데, 가장 걱정되는 점은 Jest 방식의 Unit Test와 QueryBuilder를 활용한 Data 처리 방식입니다. Django에서 ORM을 사용할때는 SQL문을 깊게 이해하지 않아도 활용가능했지만, TypeOrm은 SQL문을 직관적으로 사용하는 느낌이 강하기에 SQL Query에 대해 많이 공부해야겠다고 생각했습니다.

NestJS Unit Test는 사실상 1주일동안 가장 시간을 많이 투자한 부분입니다. Unit Test를 하기 위해서는 Test Code에 대해 어떤 Input과 Output이 도출되는지와 Test Function에 대한 의미를 정확히 파악해야합니다. jest.fn(), jest.spyOn(), mockImplemen, expect().ToHaveBeenCalledWith()등과 같은 함수들의 동작방식을 이해하고 제대로 사용하는 데도 시간이 걸렸고, 테스트 방식도 spyOn을 사용하거나 UserStub과 같이 가짜 Data를 활용하거나, 함수의 호출 여부만 확인하는 등 천차만별이었기 때문에 많이 헤맸습니다.

그래도 어느정도 방향성은 잡게되었고, 이제 본격적으로 프로젝트를 진행하며 많이 성장할 것이라고 생각합니다. 협업이 끝날 즈음에는 NestJS, TypeOrm, Jest 셋 모두 능숙하게 다룰수 있도록 더 노력해보려 합니다.

profile
어디를 가든 마음을 다해 가자

0개의 댓글