$ npm i -g @nestjs/cli
$ nest new project-name
nest new nestjs_test
라 하면 바로 프로젝트를 생성해준다.
다 설치가 되면 아래와 같이 src 파일이 설치가 되고
npm run start:dev
로 HTTP 요청을 수신하는 애플리케이션을 시작할 수 있다.
:dev로 실행하면 수시로 바뀌는 코드에 따라 현 상태를 바로 확인 할 수 있다.
컨트롤러는 들어오는 요청(request)을 처리하고 응답(response)을 클라이언트에 반환한다.
nestjs의 공식홈페이지에 따라 cat이라는 CRUD폴더를 만들어보자.
nestjs를 바로 만들 수 있는 CLI의 CRUD생성기가 주어진다.
nest g resource cats
이라고 해도 되고,
nest g res cats
라고 해도 된다. 여기서 g는 generate이다.
resource로 생성하게 되면 CRUD에 필요한 모든 파일이 만들어지므로 나중에 만들어보고 하나씩 만들어보자.
controllers만 만들고 싶다면 nest g co [name]
라고 치면 된다.
다른 명령어를 알고 싶다면, nest --help
를 치면 나온다.
생성되서 cats.controller.ts에 들어가보면 기본 컨트롤러를 정의하는 데 필수인 @Controller() 데코레이터를 사용한다.
그리고 @Controller('cats')라고 되어있는데 localhost:3000/cats
이렇게 라우트에 대해 경로를 지정할 수 있다.
controllers에서
@Get()
findAll():string {
return 'This action returns all cats';
}
이렇게 주어지면, 아래와 같이 들어가면 다음과 같은 리턴이 나온다.
findAll() 메서드 앞에 있는 @Get() HTTP 요청 메서드 데코레이터는 Nest에 HTTP 요청에 대한 특정 엔드포인트에 대한 핸들러를 생성하도록 지시한다. 엔드포인트는 HTTP 요청 메서드(이 경우 GET) 및 라우트 경로에 해당된다.
이 엔드포인트에 GET 요청이 있을 때 Nest는 요청을 커스텀 findAll() 메서드로 라우팅한다.
여기서 선택한 메서드 이름은 완전히 임의적이다. 분명히 경로를 바인딩할 메서드를 선언해야 하지만 Nest는 선택한 메서드 이름에 어떤 의미도 부여하지 않는다.
즉, 굳이 findAll이라 안해도 된다.
그냥 이름만 저렇게 쓴거다!
여기서 Get에 대해 잘 모르겠다면 HTTP 메서드를 검색해서 찾아보길 추천한다.
Param 때 http://localhost:3000/cats/1
이렇게 주소를 쓰면 id의 값이 무엇인지 읽는다.
@Get(':id')
findOne(@Param('id') id: string) {
return this.catsService.findOne(+id);
}
findOne(id: number) {
return `This action returns a #${id} cat`;
}
Query일 때 http://localhost:3000/cats/1?password=1234
이렇게 주소를 쓰면 password의 값이 무엇인지 읽는다.
@Get(':id')
findOne(@Query('password') id: string) {
return this.catsService.findOne(+id);
}
프로바이더는 Nest의 기본 개념이다. 대부분의 기본 Nest 클래스는 서비스, 리포지토리, 팩토리, 헬퍼등 프로바이더로 취급될 수 있다. 프로바이더의 주요 아이디어는 종속성으로 주입할 수 있다는 것이다.
즉, 객체는 서로 다양한 관계를 만들 수 있으며 객체의 인스턴스를 "연결"하는 기능은 대부분 Nest 런타임 시스템에 위임될 수 있다.
만들어져 있던 CatsService는 하나의 속성과 두개의 메서드가 있는 기본 클래스다.
유일한 새로운 기능은 @Injectable() 데코레이터를 사용한다는 것입니다. @Injectable() 데코레이터는 CatsService가 Nest IoC 컨테이너에서 관리할 수 있는 클래스임을 선언하는 메타데이터를 첨부한다.
@Injectable()로 주입해야할 것들을 만들고, controllers에서 클래스 생성자(constructor)를 통해 주입된다.
service.ts
@Injectable()
export class CatsService {
findAll() {
return `This action returns all cats`;
}
}
controllers.ts
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findAll() {
return this.catsService.findAll();
}
}
말은 어렵게 써놨지만 3줄 요약하자면,
1. 라우팅 역할을 하는 controllers에서 함수를 쓰고 싶음
2. 그래서 Providers에서 controllers에 쓰고 싶은 함수를 만들어 언제든지 의존성 주입 가능한 상태로 만듬(나 이런거 만들었어! 등록할게!! 쓰고 싶으면 생성자 만들어서 써!!!)
3. controllers에서 생성자로, 쓰고 싶은 애들을 데리고 옴
물론 예를들어 controllers에서 add함수를 쓰고 싶은데 귀찮아서 함수를 따로 만들지 않고 바로 작성하면 되긴하지만...
SOLID 규칙을 지키면서 코드를 치는 습관을 기르면 좋을 것 같다!
이것에 관련된 설명을 해주는 블로그들이 많으니 참고하면 좋다. (좋은 글 감사합니다)
https://limkydev.tistory.com/77
https://medium.com/crocusenergy/nestjs-providers-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%8B%A4%EC%8A%B5-e811bccb809a
모듈은 @Module() 데코레이터로 주석이 달린 클래스이고, @Module() 데코레이터는 Nest가 애플리케이션 구조를 구성하는데 사용하는 메타데이터를 제공한다.
각 애플리케이션에는 루트 모듈이라는 하나 이상의 모듈이 있다.
루트 모듈은 Nest가 애플리케이션 그래프를 빌드하는데 사용하는 시작점이다.
모듈은 기본적으로 프로바이더를 캡슐화한다.
즉, 현재 모듈에 직접 포함되거나 가져온(import) 모듈에서 내보내지(export) 않은 프로바이더를 삽입할 수 없다. 따라서 모듈에서 내보낸 프로바이더를 모듈의 공용 인터페이스 또는 API로 간주할 수 있다.
위에서 만든 CatsController와 CatsService는 동일한 애플리케이션 도메인에 속한다.
밀접하게 관련되어 있으므로 기능 모듈로 이동하는 것이 좋다.
cats.module.ts
import { Module } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CatsController } from './cats.controller';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
만약 모듈을 생성하고 싶으면 nest g module cats
or nest g mo cats
라고 치면 된다.
이렇게 export로 CatsModule을 내보냈으면 루트 모듈(app.module.ts)에서 받아야한다.
app.module.ts
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
만약에 여러 다른 모듈간에 CatsService의 인스턴스를 공유하고 싶다고 해보자.
이렇게 하려면 먼저 아래와 같이 모듈의 exports 배열에 CatsService 프로바이더를 추가하여 내보내기를 해야한다.
import { Module } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CatsController } from './cats.controller';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
그러면 이제 CatsModule을 가져오는 모든 모듈은 CatsService에 액세스할 수 있으며 이를 가져오는 다른 모든 모듈과 동일한 인스턴스를 공유한다.
또한 가져온 모듈을 다시 내보낼 수 있는데, 아래 예에서 CommonModule은 CoreModule로 가져오고 내보내므로 이 모듈을 가져오는 다른 모듈에서 사용할 수 있다.
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}