728x90
    
    
  Dependency Injection (DI)
DI는 객체나 클래스가 자신의 의존성(다른 객체나 서비스)을 직접 생성하지 않고, 외부에서 주입해주는 디자인 패턴입니다. 이 방식은 **Inversion of Control (IoC)**에 기반합니다. IoC는 객체의 생성과 의존성 관리를 프레임워크나 컨테이너가 대신 처리하는 방식입니다.
NestJS에서의 DI와 IoC 예시
- Controller와 Service를 연결할 때, @Injectable() 데코레이터를 사용하여 Service를 주입받을 수 있습니다.
- NestJS는 IoC 컨테이너를 사용하여 의존성을 주입합니다.
예시: DI와 IoC
import { Injectable } from '@nestjs/common';
@Injectable()
export class MoviesService {
  private movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  getAllMovies() {
    return this.movies;
  }
  getMovieById(id: number) {
    return this.movies.find(movie => movie.id === id);
  }
}위의 MoviesService는 NestJS에서 DI를 통해 주입받을 수 있는 서비스입니다.
Controller에서 DI 사용
import { Controller, Get, Param } from '@nestjs/common';
import { MoviesService } from './movies.service';
@Controller('movies')
export class MoviesController {
  constructor(private readonly moviesService: MoviesService) {}
  @Get()
  getAllMovies() {
    return this.moviesService.getAllMovies();
  }
  @Get(':id')
  getMovieById(@Param('id') id: number) {
    return this.moviesService.getMovieById(id);
  }
}위의 MoviesController는 MoviesService를 생성자에서 주입받아 사용합니다. 이 방식이 바로 **Inversion of Control (IoC)**입니다.
Injectable과 Module Provider의 관계
NestJS에서 Service는 @Injectable() 데코레이터를 사용해 정의되며, 이를 Module의 프로바이더에 등록하여 의존성을 주입받을 수 있습니다. 프로바이더는 클래스가 NestJS IoC 컨테이너에서 관리되는 방식을 의미합니다.
// movies.module.ts
import { Module } from '@nestjs/common';
import { MoviesService } from './movies.service';
import { MoviesController } from './movies.controller';
@Module({
  imports: [],
  controllers: [MoviesController],
  providers: [MoviesService],  // 여기서 MoviesService를 프로바이더로 등록
})
export class MoviesModule {}2. GET /movies 로직 service로 전환하기
Controller에서 서비스로 전환
- GET movie 요청을 처리하는 Controller에서 Service로 로직을 전환합니다.
기존 Controller 로직 (GET)
@Get()
getAllMovies() {
  return [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
}Service로 전환된 코드 (GET)
// movies.service.ts
@Injectable()
export class MoviesService {
  private movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  getAllMovies() {
    return this.movies;
  }
}// movies.controller.ts
@Get()
getAllMovies() {
  return this.moviesService.getAllMovies(); // Service 호출
}3. GET /movies/:id 로직 service로 전환하기
GET movie by ID 로직을 Service로 분리
기존 Controller 로직 (GET by ID)
@Get(':id')
getMovieById(@Param('id') id: number) {
  const movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  return movies.find(movie => movie.id === id);
}Service로 전환된 코드 (GET by ID)
// movies.service.ts
@Injectable()
export class MoviesService {
  private movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  getMovieById(id: number) {
    return this.movies.find(movie => movie.id === id);
  }
}// movies.controller.ts
@Get(':id')
getMovieById(@Param('id') id: number) {
  return this.moviesService.getMovieById(id); // Service 호출
}4. POST /movies 로직 service로 전환하기
POST 요청을 처리하는 로직을 Service로 이동
기존 Controller 로직 (POST)
@Post()
createMovie(@Body() movie: { title: string }) {
  const newMovie = { id: Date.now(), title: movie.title };
  return newMovie;
}Service로 전환된 코드 (POST)
// movies.service.ts
@Injectable()
export class MoviesService {
  private movies = [];
  createMovie(title: string) {
    const newMovie = { id: Date.now(), title };
    this.movies.push(newMovie);
    return newMovie;
  }
}// movies.controller.ts
@Post()
createMovie(@Body() movie: { title: string }) {
  return this.moviesService.createMovie(movie.title); // Service 호출
}5. PATCH /movies/:id 로직 service로 전환하기
PATCH 요청으로 영화 데이터를 수정하는 로직을 Service로 이동
기존 Controller 로직 (PATCH)
@Patch(':id')
updateMovie(@Param('id') id: number, @Body() movie: { title: string }) {
  const updatedMovie = { id, title: movie.title };
  return updatedMovie;
}Service로 전환된 코드 (PATCH)
// movies.service.ts
@Injectable()
export class MoviesService {
  private movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  updateMovie(id: number, title: string) {
    const movie = this.movies.find(movie => movie.id === id);
    if (movie) {
      movie.title = title;
      return movie;
    }
    return null;
  }
}// movies.controller.ts
@Patch(':id')
updateMovie(@Param('id') id: number, @Body() movie: { title: string }) {
  return this.moviesService.updateMovie(id, movie.title); // Service 호출
}6. DELETE /movies/:id 로직 service로 전환하기
DELETE 요청으로 영화 데이터를 삭제하는 로직을 Service로 이동
기존 Controller 로직 (DELETE)
@Delete(':id')
deleteMovie(@Param('id') id: number) {
  return `Movie with ID ${id} deleted`;
}Service로 전환된 코드 (DELETE)
// movies.service.ts
@Injectable()
export class MoviesService {
  private movies = [
    { id: 1, title: 'Inception' },
    { id: 2, title: 'Interstellar' },
  ];
  deleteMovie(id: number) {
    const index = this.movies.findIndex(movie => movie.id === id);
    if (index > -1) {
      this.movies.splice(index, 1);
      return `Movie with ID ${id} deleted`;
    }
    return null;
  }
}// movies.controller.ts
@Delete(':id')
deleteMovie(@Param('id') id: number) {
  return this.moviesService.deleteMovie(id); // Service 호출
}전체적인 흐름 정리
NestJS에서 GET, POST, PATCH, DELETE 요청을 Service로 전환하는 방식은 코드의 재사용성과 유지보수성을 높여줍니다. Controller에서는 요청을 받아서 Service로 전달하고, 실제 비즈니스 로직은 Service에서 처리하게 됩니다.
- Controller는 HTTP 요청을 받아서 Service로 전달
- Service는 실제 비즈니스 로직을 처리
- Repository는 데이터베이스와 상호작용하여 데이터 저장 및 조회를 처리
728x90
    
    
  '개발자 성장 로드맵 > 백엔드' 카테고리의 다른 글
| Nest.js 요청 사이클 구조 완전 정리 — Postman을 활용한 API 테스트 (2) | 2025.07.22 | 
|---|---|
| 웹 개발 필수! HTTP 요청과 상태 코드의 모든 것 (1) | 2025.07.21 | 
| Next.js와 Express.js의 차이점 (7) | 2025.07.21 | 
| 서버 개발의 시작! 백엔드 개발자 되는 법 (0) | 2025.06.21 |