inkyu0103 / badminton-app

https://staging-mobae.xyz
1 stars 0 forks source link

refactor: add login error handling #137

Closed inkyu0103 closed 1 year ago

inkyu0103 commented 1 year ago

설명

로그인 시 발생할 수 있는 에러를 처리합니다.

특히 토큰 관련하여 401 에러를 throw 하는 경우가 많은데, 에러 이유를 명확하게 하는 message를 담아주도록 변경합니다.

그리고 가능하다면 테스트도 작성해봅니다 😄

131 도 이어서 진행합니다

관련 이슈

Fix #136

변경사항

현재 accessToken은 메모리에, refresh token은 cookie에 저장하는 방식을 선택하고 있습니다. refreshToken이 만료된 경우에는 cookie를 삭제하고 401 error를 던지도록 변경하였습니다.

try~catch 문을 service단이 아닌, controller 단에 적용하여 catch한 error의 유형에 따라 다른 응답을 반환할 수 있도록 바꾸었습니다. (물론 지금은 Expire밖에 없지만요)

그리고 말많고 탈많던 테스트도 추가했습니다 🥳

스크린샷

없습니다.

vercel[bot] commented 1 year ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
badminton-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 14, 2023 11:42am
inkyu0103 commented 1 year ago

jest-e2e.json 에서 setupFilesAfterEnv 옵션을 사용해서 테스트 전 후로 한 번씩만 DB 연결 작업을 하는 줄 알았는데, 잘못된 부분이었다. 공식 문서에는 다음과 같이 작성되어있다.

setupFilesAfterEnv

inkyu0103 commented 1 year ago

드디어 되는구나 image

그동안 왜 오류가 발생했을까? 구조를 잘 모르니까 삽질하는데 시간을 너무 많이 잡아먹어서 슬프다

처음에는, 테스팅 모듈을 만들기 위해 다음과 같이 작성했다.

const moduleRef = await Test.createTestingModule({
      imports: [ AuthModule ],
}).compile()

그럼 다음과 같은 오류가 발생한다.

    Nest can't resolve dependencies of the AuthService (AuthRepository, ?, JwtService, UsersService). 
    Please make sure that the argument MailerService at index [1] is available in the AuthModule context.

    Potential solutions:
    - Is AuthModule a valid NestJS module?
    - If MailerService is a provider, is it part of the current AuthModule?
    - If MailerService is exported from a separate @Module, is that module imported within AuthModule?
      @Module({
        imports: [ /* the Module containing MailerService */ ]
      })

나름 친절하게 잠재적인 ? 해답도 알려준다.

Q.Is AuthModule a valid NestJS module? A. 넵

Q.If MailerService is a provider, is it part of the current AuthModule? A. 잉 provider가 아니네요

auth.module.ts 파일을 열어보자

@Module({
  imports: [
    JwtModule.registerAsync({
      useFactory: () => ({
        secret: process.env.JWT_SECRET_KEY,
      }),
    }),
  ],
  providers: [
    AuthService,
    AuthRepository,
    UsersService,
    UsersRepository,
    LocalStrategy,
    JwtStrategy,   
    MailerService  // 요기에 추가해주면 되겠지?
  ],
  controllers: [AuthController],
})
export class AuthModule {}

그런데도 안된다.

사실 문제는 MailerModule 뿐만 아니라, PrismaModule에서도 발생하고 있었는데, 두 모듈의 공통점은 Global Module로 사용하고 있는 점이다.

일반적으로 하나의 모듈에서 다른 모듈의 서비스를 사용하기 위해서는, 다음과 같이 설정을 해야한다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService] // 요렇게 exports 하고, 다른 Module에서 CatsModules을 import 해야한다.
})
export class CatsModule {}

그러나 MailerModule과 PrismaModule은 Global 모듈이기 때문에 해당 과정을 생략하고, 곧바로 서비스단에서 dependency injection을 통해 사용할 수 있었다.

근데 이게 가능한게, global module들이 최상단 모듈인 app module에 import 되어있었기 때문에 가능한 일이었는데, 현재 테스트하고자 하는 module은 auth 모듈에 존재하는 api를 대상으로만 하는 것이기 때문에, global module들이 전혀 적용되지 않은 상태이다.

따라서 다음과 같이 global하게 적용되던 module들을 같이 import해주면 문제를 해결할 수 있다.

const moduleRef = await Test.createTestingModule({
      imports: [ AuthModule , PrismaModule, MailerModule],
}).compile()