[Nest] Nest WikiDocs (4.11) (1)

ShinJuYong·2022년 4월 11일
0

Nest

목록 보기
4/13
post-thumbnail

오류수정

interface EmailOptions {
  to: string;
  subject: string;
  html: string;
}
// ....
    const mailOptions: EmailOptions = {
      to: emailAddress,
      subject: '가입 인증 메일',
      html: `
        가입확인 버튼를 누르시면 가입 인증이 완료됩니다.<br/>
        <form action="${url}" method="POST">
          <button>가입확인</button>
        </form>
      `
    }

해당하는부분에서 from 속성이 빠져있어서 메일을 보낼따마다 error가 발생했다
from : "보내는사람이메일"을 추가하면 오류해결

이메일인증

가입 확인을 누르면
/email-verify엔드포인트로 요청이와 log가 출력이된다

해당 엔드포인트의 로직도 Service로 위임한다

로그인

컨트롤러는 요청과 응답처리만
실질적인 로직은 Service로

  @Post('/login')
  async login(@Body() dto: UserLoginDto): Promise<string> {
    const { email, password } = dto;
    return await this.usersService.login(email, password);
  }
  async login(email: string, password: string): Promise<string> {
    // todos
    // 1. email, password 가진 유저가 db에있다면 처리, 없으면 에러
    // 2. JWT를 발급해 전달

    throw new Error('method not implemented');
  }

유저정보조회

위와 마찬가지로 로직을 분리한다

  @Get('/:id')
  async getUserInfo(@Param('id') userId: string): Promise<UserInfo> {
    return await this.usersService.getUserInfo(userId)
  }
  async getUserInfo(userId: string): Promise<string> {
    // todos
    // 1. userId를 DB에서 조회해 없다면 에러
    // 2. 조회된 데이터를 UserInfo 타입으로 전달

    throw new Error('Method not implemented');
  }

커스텀 프로바이더

일반적으로 사용한다면 문제가 생기지 않지만, 테스트코드에 MOCK을 사용하게 된다면 커스텀프로바이더를 사용해야한다.

  • Nest 프레임워크가 만들어주는 인스턴스 대신 직접 생성을 하고 싶은 경우
  • 이미 존재하는 클래스를 재사용 하고자 할때.
  • 테스트를위해 MOCK버전으로 프로바이더를 재정의하려는 경우

모듈

Nest에서 모듈은 App이 실행되기 위해 Root모듈이 존재하며 이 RootModule에서 다른 모듈로 구성을해 각각 맡은 로직을 나눈다

export declare function Module(metadata: ModuleMetadata): ClassDecorator;

export interface ModuleMetadata {
    imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
    controllers?: Type<any>[];
    providers?: Provider[];
    exports?: Array<DynamicModule | Promise<DynamicModule> | string | symbol | Provider | ForwardReference | Abstract<any> | Function>;
}

import : 이 모듈에서 사용하기 위한 프로바이더를 가지고있는 다른 모듈을 불러온다.
controllers/providers : 모듈 전반에서 컨트롤러와 프로바이더를 사용할 수 있도록 Nest가 객체를 생성하고 주입할 수있도록 해준다.
export : 이 모듈에서 사용하는 Component를 다른 모듈에서 import에서 사용하려면, export를 시켜야한다.

예시 : 모듈 A, B, C
A에서 B를 가져오고 C에서 A를 가져온다면 C모듈이 B모듈을 가져갈수 있도록 export해야한다.

유저모듈 분리

앱모듈에서 유저 관리 기능을 유저모듈로 분리한다.
nest g mo Users

users.module.ts

import { Module } from '@nestjs/common';
import { EmailService } from 'src/email/email.service';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [],
  controllers: [UsersController],
  providers: [UsersService, EmailService],
})
export class UsersModule {}

app.module.ts

import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule],
  controllers: [],
  providers: [],
})
export class AppModule {}

이메일모듈 분리

이메일 기능또한 모듈로 분리하여 관리하도록 생성한다

nest g mo Email

email.module.ts

import { Module } from '@nestjs/common';
import { EmailService } from './email.service';

@Module({
  providers: [EmailService],
  exports: [EmailService],
})
export class EmailModule {}

users.module.ts

import { Module } from '@nestjs/common';
import { EmailModule } from 'src/email/email.module';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [EmailModule],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

환경변수 구성하기

환경변수패키지와 유효성 검사를위한 라이브러리부터 설치한다
yarn add @nestjs/config
yarn add joi

이메일환경변수 관리

emailConfig.ts를 src/config에 작성한다

import { registerAs } from '@nestjs/config';

export default registerAs('email', () => ({
  service: process.env.EMAIL_SERVICE,
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASSWORD,
  },
  baseUrl: process.env.EMAIL_URL,
}));

동적환경변수 모듈 등록

.env파일을 dist에 복사할 수 있도록 nest-cli.json에서 옵션을 바꿔준다

{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      {
        "include": "./config/env/*.env",
        "outDir": "./dist"
      }
    ]
  }
}

AppModule에 ConfigModule을 동적모듈로 등록한다

import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { EmailModule } from './email/email.module';
import { ConfigModule } from '@nestjs/config';
import emailConfig from './config/emailConfig';

@Module({
  imports: [
    UsersModule,
    EmailModule,
    ConfigModule.forRoot({
      envFilePath: [`${__dirname}/config/env/.${process.env.NODE_ENV}.env`],
      load: [emailConfig],
      isGlobal: true,
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

envFilePath : NODE_ENV의 값이 stage라면 dist파일아래의 .stage.env의 절대 경로를 가지게된다
load : 앞에 구성해둔 ConfigFactory를 지정한다.
isGlobal : 전역 모듈로 동작하게 만들어 어느 모듈에도 사용하도록 지정한다.

emailService에 등록해준다

  // 생성자
  constructor(
    @Inject(emailConfig.KEY) private config: ConfigType<typeof emailConfig>,
  ) {
    this.transporter = nodemailer.createTransport({
      service: config.service,
      host: 'smtp.naver.com',
      port: 587,
      auth: {
        user: config.auth.user,
        pass: config.auth.pass,
      },
    });
  }

@Inject() : 앞서만든 환경변수의 key인 email을 문자열로 넣어주면된다.
이후 원래 하드코딩돼있던 변수들을 환경변수로 교체해준다.

(1) 마무리.

글이 너무길어져서 (2)로 이어짐.

0개의 댓글