[Nest.js] REST API 활용한 CRUD with REST API ( Prisma, JWT)

‍정진철·2023년 5월 5일
1

Nestjs

목록 보기
1/1

nestjs 프로젝트 폴더 생성

nest new <생성하고자 하는 프로제트 폴더 명>
npm or yarn 중 하나의 패키지 선택하면 다음과 같은 설치 완료된 화면 볼 수 있다

VSCode에 설치된 폴더 목록들

Moudle 생성

모듈(Module)

NestJS 애플리케이션은 모듈 단위로 구성됩니다. 모듈은 관련된 컴포넌트를 그룹화하여 애플리케이션을 구성하는 데 사용됩니다. 즉, NestJS 애플리케이션은 다수의 모듈로 이루어져 있으며, 각 모듈은 서로 독립적으로 존재하며 필요한 다른 모듈과의 의존성을 가질 수 있습니다.

그러면 아래와 같은 폴더가 vscode 내 자동 생성 된다.

이렇게 모듈을 추가하면 모듈들을 총괄하는 app 모듈에 import해올 수 있고 해당 모듈들을 사용할 수 있다.

Controller, Service 생성

컨트롤러(Controller)

컨트롤러는 NestJS 애플리케이션의 라우팅 매커니즘을 정의합니다. 컨트롤러는 HTTP 요청을 처리하고 해당 요청에 대한 응답을 반환하는 역할을 담당합니다. 또한 컨트롤러는 서비스와의 상호작용을 통해 비즈니스 로직을 처리합니다.

서비스(Service)

서비스는 NestJS 애플리케이션에서 비즈니스 로직을 수행하는데 사용되는 컴포넌트입니다. 서비스는 컨트롤러와 같은 다른 컴포넌트에서 호출되며, 데이터베이스와 같은 외부 리소스와 상호작용할 수 있습니다. 서비스는 NestJS의 의존성 주입(Dependency Injection)을 활용하여 필요한 다른 서비스나 컴포넌트를 쉽게 주입받을 수 있습니다.

Service

아래와 같은 회원가입, 로그인 시 반환되는 결과를 service 에 제공해주고 컨트롤러에서 서비스에 기재된 함수들을 가져와 특정 HTTP 메소드와 URL 과 매핑 시켜준다.

Controller

response



Connnecting to DB with Prisma

도커 compose

데이터베이스 postgres 를 사용하기 위해 docker 를 실행시킨다.


Prisma

npm i -D prisma
npm i @prisma/client
npx prisma init
프리즈마 패키지 설치 후 설정 파일 생성


schema 에서 데이터베이스 모델 생성

prisma와 데이터베이스 연결할 url 수정

빨간색 박스 순서대로 도커 컴포즈 파일에 입력한 user,password,port No, DB Name 입력

npx prisma migrate dev

npx prisma migrate 명령어는 Prisma 데이터베이스 마이그레이션을 생성하고 실행하는 데 사용됩니다.
Prisma는 데이터베이스 스키마와 모델을 동기화하기 위해 데이터베이스 마이그레이션을 사용합니다. 데이터베이스 마이그레이션은 데이터베이스 스키마의 변경 사항을 추적하고 적용하는 프로세스입니다. Prisma 마이그레이션은 새로운 모델을 추가하거나 기존 모델의 필드를 변경하는 등의 스키마 변경을 처리할 수 있습니다.
npx prisma migrate 명령어를 실행하면 prisma/migrations 디렉토리에 마이그레이션 파일이 생성됩니다. 이 파일에는 데이터베이스 스키마 변경 내용이 포함되며, 마이그레이션을 실행하여 데이터베이스를 업데이트할 수 있습니다. 이를 통해 Prisma를 사용하여 애플리케이션의 데이터베이스 스키마를 쉽게 변경할 수 있습니다.

npx prisma studio

해당 명령어 실행시 localhost:5555로 연결돼어 데이터베이스 상황을 쉽게 살펴볼 수 있다.

prisma module, service 생성

프리즈마를 다른 모듈 서비스를 구현함에 있어 사용하기 위해 프리즈마 전용 모듈과 서비스 생성

prisma.service.ts

프리즈마 환경설정 , 위에서 입력한 env 파일의 URL 그대로 입력.

prisma.module.ts

원래는 다른 모듈에서 프리즈마 모듈을 가져오기 위해서는 매번 서비스를 실행하는 모듈 마다(auth.module.ts)에 constructor를 생성 해줘야 하지만 @Global 성질을 넣어줌에 따라 굳이 imports 시키지 않아도 사용 가능해진다.

auth.service.ts

app.module.ts

Dto 생성

일반적으로 유저가 보낼 데이터에 대한 형식 정의

auth.dto.ts

dot 폴더 내 index.ts

auth.controller.ts

Pipes

https://docs.nestjs.com/pipes
반드시 넣어야 할 항목에 기입을 하지 않거나 올바르지 않은 형식으로 입력 시 오류 뱉는 validator 적용하기

npm i class-validator class-transformer --save

auth.dto.ts

main.ts

내가 pipes를 사용할 것이라고 알림

빈 객체 전송 시

올바르지 않은 형식의 데이터 전송 시

하지만 만약에 DTO에 정의되지 않은 정보를 보낸다면?

위와 같이 정의 하지 않은 객체 전송을 막아야함
whitelist 를 true 값으로 설정하면 말 그대로 내가 허락한 dto 객체만 전송 받는다.


SignUp, SingIn 로직 구현

Hased Password with Argon

SignUp

npm i argon2

auth.service.ts

dto.password : 사용자가 입력한 비밀번호
hash : argon 라이브러리를 통한 암호화된 비밀번호
dto.email : 유저가 입력한 이메일
user : 유저가 입력한 email, 해쉬화 된 비밀번호를 기반으로 데이터베이스에 저장된 유저 정보
delete user.hash : 리턴값으로 해쉬화된 암화 반환 시 보안 위험성 대두되므로 사전에 삭제

prisma 스키마 보완

참고로 북마크와 유저는 N:1 관계 즉, 하나의 유저는 여러개의 북마크를 가질 수 있고 하나의 북마크는 하나의 유저만 가질 수 있음. 이를 스키마에 적용시킨다
User 테이블에 bookmarks 속성을 추가시킴에 따라 하나의 유저는 여러개의 bookmark를 가질 수 있다.

userId : 북마크 소유주
userId를 기본키로 사용하는데 User 테이블의 id를 reference로 받는다 즉, userId는 외래키다.



Error 처리

다음과 같이 현재 email 속성은 unique하여야 하는데 중복된 이메일을 가지고 회원가입 시도 시 에러를 처리 하는 로직을 구성해야 한다.

try ~ catch 로 감쏴서 해당 오류가 Prisma에 내장된 오류 + 해당 에러 코드가 P2002라면 사전에 지정한 오류 문구를 내뱉도록 한다.

export class AuthService {
  constructor(
    private prisma: PrismaService,
  ) {}
async signUp(dto: AuthDto) {
    // generate the password hash
    const hash = await argon.hash(dto.password);
    // save the new user in the db
    try {
      const user = await this.prisma.user.create({
        data: {
          email: dto.email,
          hash,
        },
      });
delete user.hash;
      return user;
} catch (error) {
      if (
        error instanceof
        PrismaClientKnownRequestError
      ) {
        if (error.code === 'P2002') {
          throw new ForbiddenException(
            'Credentials taken',
          );
        }
      }
      throw error;
    }
  }

signIn

findUnique의 프리즈마 함수를 이용해 사전에 작성했던 유니크한 이메일 속성을 찾는다. 또한 argon의 verify 기능을 가지고 유저한 입력한 패스워드와 기존에 등록된 유저의 해쉬화된 암호화 비교해 크리덴셜한 유저를 가려낸다.


JWT 적용하기

npm i @nestjs/passport @nestjs/jwt passport-jwt -D @types/passport-jwt
@nestjs/jwt -> 토큰에 sign을 하기 위한 라이브러리

jwt module import

auth.service.ts

JWT 발급 함수

userId 와 email을 payload로서 토큰에 심어 JWT를 발급한다.

signIn 함수 return 값을 signToken의 결과값으로 반환


JWT 사용자 인증

JwtStrategy 클래스는 JWT를 사용하여 사용자 인증을 수행합니다. JwtStrategy 클래스의 jwtFromRequest 속성에서는 HTTP 요청 헤더에서 JWT를 추출하는 방법을 지정하고, secretOrKey 속성에서는 JWT 시크릿 키를 설정합니다. 이 JWT 시크릿 키는 ConfigService에서 가져와 설정합니다.

jwt.strategy.ts

해당 토큰 발급 이후 validate 함수를 통해 토큰 유효성 점검

Guards

특정 API 호출 시 JWT 인증 과정을 적용시키 위해 Guard 적용

토큰 인증 (Headers)

/users/me 로 GET 요청 시 헤더의 Authorizaiton 속성의 값인 'Bearer ~~' 형식에서 ~~ 부분에 해당하는 토큰 점검 (payload 추출)

payload

profile
WILL is ALL

0개의 댓글