Sercive란?
- @Injectable 데코레이터로 감싸져서 모듈에 제공, 이 서비스 인스턴스는 어플리케이션 전체에서 사용될 수 있음.
- 서비스는 컨트롤러에서 데이터 유효성 검사, 데이터베이스에 아이템을 생성하는 등의 작업을 처리하는 부분
Provider 등록하기
- 프로바이더는 모듈에서 등록이 가능하다 모듈 파일 내의 providers 항목에 해당 모듈에서 사용하고자 하는 Provider를 넣으면 된다.
모든 게시물을 가져오는 service 만들기
- 클라이언트에서 요청을 보내면 먼저 컨트롤러로 가게되는데 컨트롤러에서 알맞은 요청 경로에 라우팅해서
해당 핸들러로 가게된다. 그 후에 요청을 처리해주기 위해서 서비스로 들어가며 그 요청에 맞는 로직을 서비스에서 처리해준 후
컨트롤러에 리턴해주고, 컨트롤러에서 클라이언트로 결과값을 보내줌.
=> 컨트롤러는 요청을 처리하고 결과값을 리턴해주는 역할을 한다.
Board Model 정의하기
모델을 정의하기 위해서는 class나 Interface를 이용한다.
- Interface: 변수의 타입만을 체크
- Class: 변수의 타입 체크, 인스턴스 생성이 가능
uuid 모듈은 값을 유니크하게 만들어줄 수 있다.
- npm i uuid
게시물 생성하기 Controller
- 클라이언트에서 보내온 값들을 핸들러에서 어떻게 가져올까?
node.js: app.post('/', (req, res) => {
console.log(req.body)
})
nest.js: @Body body를 이용해서 가져온다.
@post()
createBoard(@Body() body) {
console.log('body', body)
}
3-5. Data transfer Object(DTO)
- DTO? : 계층간 데이터 교환을 위한 객체임
(DB에서 데이터를 얻어 서비스나 컨트롤러 등으로 보낼 때 사용하는 객체)
DTO는 데이터가 네트워크를 통해 전송되는 방법을 정의하는 객체임
interface나 class를 이용해서 정의 될 수 있음(Class 사용을 장려하는 편)
- DTO를 사용하는 이유
1. 데이터 유효성 검사에 효율적임
2. 더 안정적인 코드로 만들어줌. 타입스크립트의 타입으로 사용되기도함
3. 코드의 유지보수를 더 편리하게 만들어줌
- DTO 파일을 Class로 작성하는 이유
인터페이스와 다르게 런타임에서 작동하기 때문에 파이프 같은 기능을 이용할 때 더 유용함
- ID로 특정 게시물 가져오기
- ID로 특정 게시물 지우기
deleteBoard(id:string):void {
// filter는 참 값을 반환하는 모든 값으로 새로운 배열을 구성한다. 즉, 거짓을 반환한 값은 제외된 배열이 생성됨.
// 원래 존재하던 boards 배열에서 필터를 돌리는데 배열 안에 id값이 입력한 id값과 일치하지 않는 것들을 배열로 만듦
// 즉, ID 값을 제외한 나머지 요소들만이 새롭게 배열로 만들어지고 boards에 할당이 된다.
this.boards = this.boards.filter((board) => board.id !== id)
}
- 특정 게시물 업데이트 하기
- NestJS Pipes
Pipe란? @Injection() 데코레이터로 주석이 달린 클래스이다.
파이프는 data transformation(데이터 변형)과 data validation(데이터 유효성 검사)을 위해 사용이 된다.
파이프는 컨트롤러 경로 처리기에 의해 처리되는 인수에 대해 작동한다.
Nest는 메소드가 호출되기 직전에 파이프를 삽입하고, 파이프는 메소드로 향하는 인수를 수신하고 이에 대해 작동함
Handler-level Pipes: 핸들러 레벨에서 @UsePipes() 데코레이터를 이용해서 사용 가능하다.
(이 파이프는 모든 파라미터에 적용이 된다.)
Parameter-level Pipes: 파라미터 레벨의 파이프기 때문에 특정한 파라미터에게만 적용이 되는 파이프임
Global Pipes: 어플리케이션 레벨의 파이프이며, 클라이언트에서 들어오는 모든 요청에 적용이 된다.
(가장 상단 영역인 main.ts에 넣어준다.)
파이프를 이용한 유효성 체크
필요 모듈
1. class-validator
2. class-transformer
dto파일에 @IsNotEmpty()가 class-validator임(데코레이터로 유효성을 검증해줌)
controller파일에 @UserPipes(validationPipe)를 적어주면 자동으로 dto에 적어둔 @IsNotEmpty()를 확인해준다.
궁굼증: 그러면 dto에 무조건 관련한 데코레이터를 적어줘야 벨리데이션파이프가 작동하는 건가?
- 특정 게시물을 찾을 때 없는 경우 결과 값 처리하기
Sercive파일에서 해당 메서드를 정의한 곳에 예외 인스턴스를 생성해주면 된다.
에러가 나타났을 때 내가 원하는 문구를 적어주고 싶으면 메서드의 파라미터 자리에 내가 출력하고 싶은 문구를 적어준다.
- 없는 게시물을 지우려고 할 때 결과 값 처리하기
특정 게시물을 찾을 때 없은 경우 결과 값을 처리한 것과 비슷하게 진행을 할 수 있다.
1. 일단 내가 찾고자하는 게시물을 찾아줘야함.(const board = this.getBoardById(id);)
* 이미 아이디를 통해서 특정한 게시물을 찾아주는 메서드를 만들었기 때문에 그대로 사용해서 게시물을 찾아준다.
2. if (!post) {
throw new NotFoundException(`해당하는 게시물이 존재하지 않습니다`);
}
게시물이 없을 때 게시물을 찾을 수 없다고 띄워주는데 내가 원하는 문구를 써주고 싶었음.
- 커스텀 파이프를 이용한 유효성(validation)체크
커스텀 파이프 구현 방법
Pipe transform이란 인터페이스를 새롭게 만들 커스텀 파이프에 구현을 해줘야함.
Pipe transform 인터페이스는 모든 파이프에서 구현해줘야 하는 인터페이스임
그리고 이 인터페이스와 함께 모든 파이프는 transform() 메서드를 필요로한다.
transform() 메서드는 nest가 인자(Arg)를 처리하기 위해서 사용된다.
transform() 메서드는 두개의 파라미터를 갖는다.
transform(value, metadata)
1. 처리가 된 인자의 값(value)
2. 인자에 대한 메타 데이터를 포함한 객체
transform()메서드에서 Return된 값은 Route 핸들러로 전해진다.
만약 예외(Exception)가 발생하면 클라이언트에 바로 전해진다.
커스텀 파이프로 실제 구현할 기능: 상태(Status)는 PUBLIC과 PRIVATE만 올 수 있기 때문에 이외의 값이 들어오면 에러를 던져준다.
4-1. Postgres & TypeORM 연동
1. PostgeSQL 공식 홈페이지에서 최신 버전을 다운로드 받아줌
2. pgAdmin을 설치함
3. pgAdmin을 실행해서 사용자를 추가해줌
4. 서버를 새롭게 만든 후 데이터 베이스를 추가해줌
4-2. TypeORM이란?
- node.js에서 실행되고, TypeScript로 작성된 객체 관계형 매퍼 라이브러리
* 객체지향 프로그래밍: 클래스 사용, 관계형 데이터베이스: 테이블 사용
객체 모델과 관계형 모델 간의 불일치가 존재하게된다.
ORM이란?
- 객체와 관계형 데이터베이스의 데이터를 자동으로 변형, 연결하는 작업임.
ORM을 이용한 개발은 객체와 데이터베이스의 변형에 유연하게 사용할 수 있음
TypeORM의 특징과 이점
1. 모델 기반으로 DB 테이블 체계를 자동으로 생성한다.
2. DB에서 개체를 쉽게 삽입, 업데이트 및 삭제할 수 있다.
3. 테이블 간의 매핑(1:1, 1:N, N:N)을 만든다.
4. TypeORM은 간단한 코딩으로 ORM 프레임 워크를 사용하기 쉬움
5. TypeORM은 다른 모듈과 쉽게 통합된다.
4-3. TypeORM을 어플리케이션에서 이용하기
- @nestjs/typeorm: 네스트에서 TypeORM을 사용하기 위해 연동시켜주는 모듈
- typeorm: TypeORM 모듈
- pg: Postgres 모듈
어플리케이션에 TypeORM 연결하기
1. TypeORM 설정파일 생성하기
2. typeorm을 정의할 파일에 작성함
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
export const typeORMConfig: TypeOrmModuleOptions = {
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'root',
password: 'aaaa4321',
database: 'board-app',
entities: [__dirname + '/../**/*.entity.{js,ts}'],
synchronize: true,
};
3. 루트 모듈에 TypeORM 적용
import { Module } from '@nestjs/common';
import { BoardsModule } from './boards/boards.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeORMConfig } from './configs/typeorm.config';
@Module({
imports: [TypeOrmModule.forRoot(typeORMConfig), BoardsModule],
})
export class AppModule {}
이해가 될 것 같기도 하고....참 애매하다 너무 어렵다..... 수료까지 얼마 안남았는데 불타올라야하는데 아무것도 하기가 싫다 아무 것도 안하는 것 보다는 조금이라도 하는게 낫겠지