오랜만의 삽질기가 아닌 회고이다 ㅋㅋ

 

일반적으로 "컨트롤러"는 웹 애플리케이션에서 클라이언트의 요청을 처리하고 응답을 반환하는 역할을 담당한다.

NestJS 프레임워크에서는 컨트롤러를 사용하여 API 엔드포인트를 정의하고 해당 엔드포인트에 대한 로직을 구현한다.

따라서, EmailService 클래스가 API와 상호작용하는 부분을 담당한다면 해당 클래스는 일종의 "서비스"로 볼 수 있다.

그리고 이 서비스를 사용하는 컨트롤러에서 실제 API 엔드포인트를 정의하고 EmailService를 호출하여 비즈니스 로직을 처리할 수 있다.

고 해서... 이메일 컨트롤러를 따로 만들었는데 그냥 유저 컨트롤러에 통합하기로 결정하면서,

import { Controller, Post, Body } from '@nestjs/common';
import { EmailService } from './email.service';

@Controller('email')
export class EmailController {
  constructor(private readonly emailService: EmailService) {}

  @Post('/validate')
  validateEmail(@Body('email') email: string): boolean {
    return this.emailService.validateEmailFormat(email);
  }

  @Post('/check-duplicate')
  async checkDuplicateEmail(@Body('email') email: string): Promise<boolean> {
    return this.emailService.checkDuplicateEmail(email);
  }
}
//위의 코드에서 @Controller() 데코레이터로 '/email' 경로에 대한 컨트롤러를 정의하였습니다. 
그리고 validateEmail()와 checkDuplicateEmail() 메서드는 각각 /validate와 /check-duplicate 경로에 
대한 POST 요청 핸들러입니다. 이 핸들러들은 클라이언트로부터 전달된 이메일 값을 받아서 
EmailService의 메서드를 호출하여 비즈니스 로직을 처리하고 결과를 반환합니다.

따라서, 위 코드에서 EmailController는 API 관점에서 볼 때 "컨트롤러" 역할을 하며, 
실제 비즈니스 로직은 EmailService 클래스 내에 구현되어 있습니다.

이걸 없애버리고,

import { Controller, Post, Body } from '@nestjs/common';
import { User } from '../../domains/entities/User.entity';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  // ... 다른 메서드들 ...

  @Post('/validate-email')
  validateEmail(@Body('email') email: string): boolean {
    return this.userService.validateEmailFormat(email);
  }
}
//@Controller() 데코레이터로 '/users' 경로에 대한 컨트롤러를 정의하였습니다. 
그리고 validateEmail() 메서드는 /validate-email 경로에 대한 POST 요청 핸들러입니다. 
클라이언트로부터 전달된 이메일 값을 받아서 UserService의 validateEmailFormat() 메서드를
호출하여 이메일 유효성 검사를 수행하고 결과를 반환합니다.

위와 같이 유저 컨트롤러에 이메일 유효성 검사 API 엔드포인트를 정의해주었다. 만약 다른 기능과 관련된 API 엔드포인트가 많거나 복잡해진다면, 관련 기능들을 별도의 컨트롤러(EmailController)로 분리하는 것도 고려해볼 수 있겠으나, 유효성 검사의 특성 상 그리 복잡해 질 확률은 상당히 낮기 때문에 과감하게 컨트롤러 통합을 감행하였다.

 

그리고 어쩌다보니 NestJS의 의존성 주입에 대해 확실하게 이해한 것 같아 정리해보려고 한다.

NestJS에서의 "의존성 주입(Dependency Injection)"은 클래스 또는 컴포넌트가 필요로 하는 의존성을 외부에서 제공받는 개념을 말한다(다른 프레임워크도 마찬가지이긴 하다). 이를 통해 코드의 유연성과 재사용성을 높일 수 있다.

NestJS에서 의존성 주입은 @Injectable() 데코레이터와 constructor를 사용하여 구현된다.

@Injectable() 데코레이터를 클래스에 적용하면 해당 클래스는 의존성 주입 가능한 클래스로 간주되며,

해당 클래스의 생성자(constructor)에 필요한 의존성을 매개변수로 선언하면 NestJS가 자동으로 해당 의존성을 주입한다.

예를 들어, 다음과 같이 EmailService가 UserService에 의존하는 경우를 생각해보자.

import { Injectable } from '@nestjs/common';
import { UserService } from './user.service';

@Injectable()
export class EmailService {
  constructor(private readonly userService: UserService) {}

  // 이메일 서비스의 로직 구현
}
//위 코드에서 EmailService는 생성자에 UserService를 필요로 하며, 해당 의존성은 자동으로 주입됩니다.
이렇게 함으로서 EmailService 내부에서 UserService 인스턴스에 접근하여 사용할 수 있습니다.

따라서, NestJS에서 "의존성 주입"은 외부 모듈, 서비스, 컴포넌트 등 다른 클래스나 객체들과 협력하고 
상호작용하기 위해 필요한 의존성을 자동으로 제공받는 것입니다. 
이는 스프링 프레임워크에서도 비슷한 개념으로 사용되지만 구체적인 구현 방식과 문법은 조금 다를 수 있습니다.

+ Recent posts