NestJS
nest-js 구조
1
2
3
4
5
6
7
8
9
10
11
AppModule(root)
├──Module1
│ └──Controller
│ └──Service
│ └──..
│ └──..
├──Module2
│ └──Controller
│ └──Service
│ └──..
│ └──..
기본적인 명령어
프로젝트 생성
1
2
npm i -g @nestjs/cli
nest new project-name
모듈생성
1
nest g module module-name
컨트롤러 생성
컨트롤러는 들어오는 요청을 처리하고 클라이언트에 응답을 반환한다.
1
nest g controller module-name
서비스생성
서비스 안에는 데이터베이스 관련된 로직을 처리한다.
1
2
nest g service module-name --no-spec
# --no-spce : 테스트 코드 생성 안함
Type ORM
설치
1
2
3
npm install pg typeorm @nestjs/typeorm --save
# pg : postgres 모듈
# typeorm : typeorm 모듈
설정
src > configs > typeorm.config.ts
파일을 만든다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as config from 'config'; // 설정 파일
const dbConfig = config.get('db');
export const typeORMConfig: TypeOrmModuleOptions = {
type: dbConfig.type,
host: process.env.RDS_HOSTNAME || dbConfig.host,
port: process.env.RDS_PORT || dbConfig.port,
username: process.env.RDS_USERNAME || dbConfig.username,
password: process.env.RDS_PASSWORD || dbConfig.password,
database: process.env.RDS_DB_NAME || dbConfig.database,
entities: [__dirname + '/../**/*.entity.{js,ts}'], // entity가 정의된 위치
synchronize: dbConfig.synchronize, // true이면 entity가 변경시 해당 table 삭제 후, 다시 생성
};
Entity 작성
db table의 설계도 같은 느낌 (Django에서 Model과 비슷한 느낌) 각각의 모듈폴더 안에 xx.entity.ts에 작성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Entity('users')
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
pk: number;
@Column()
id: string;
@Column()
password: string;
//외레키 설정
// OneToMany이면 Django에서 역참조라고 생각하면 된다.(_set으로 접근)
// eager는 해당 모델을 가져올 때, userTires를 가져올지 설정하는 문구이다.
@OneToMany((type) => UserTire, (userTire) => userTire.user, { eager: false })
userTires: UserTire[];
}
근데, ts는 카멜케이스 이니깐 컬럼명을 카멜케이스로 하면 db에도 카멜케이스 형태로 들어간다.
이것을 DB에 들어갈때는 스네이크 케이스로 하고 싶으면 다음과 같이하면된다.
1
2
@Column({name:'created_at'})
createdAt: Date
하지만 이 방법은 번거럽고 실수 할 수 있다. 따라서 typeorm-naming-strategies를 사용해서 자동을 바뀔 수 있도록 한다.
1
2
3
export const typeORMConfig: TypeOrmModuleOptions = {
// typeORMConfig에 다음과 같이 추가
namingStrategy: new SnakeNamingStrategy(),
Repository
각 table의 CRUD를 하는 곳 Django에서 Manager(objects)랑 비슷한 느낌 각각의 모듈폴더 안에 xx.repository.ts에 작성한다. 기본적으로 Repository를 상속받은 형태로 작성하고, 추후 필요한 ORM을 메쏘드 형태로 만든다.
1
2
3
4
5
import { EntityRepository, Repository } from 'typeorm';
import { User } from './users.entity';
@EntityRepository(User)
export class UserRepository extends Repository<User> {}
만든 Repository를 Module에서 사용할 수 있도록 등록한다.
1
2
3
4
@Module({
imports: [TypeOrmModule.forFeature([UserRepository])],
...
})
service 부분에서 사용하므로 다음과 같이 선언해서 사용한다.
ts에서는 생성자의 private 인자로 들어가면 자동으로 맴버 property가 된다.
1
2
3
4
5
6
7
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UserRepository)
private userRepository: UserRepository,
) {}
}
DTO
계층간 데이터를 전송하기 위해서 필요한 객체이며, 해당 객체를 만들기 위해서는 아래와 같은 패키지가 필요함.
파이프 data transformation과data validation을 위해서 사용됨 transformation : 정수로 받았는데, 숫자로 변환 validation : 유효성 체크
1
npm install class-validator class-transformer --save
파이프는 핸들러, 파라미터, 글로벌 레벨 3가지로 나뉨 핸들러: 핸들러 하나의 작용(컨토롤러 함수 하나) 파라미터 : 파라미터 하나의 적용 글로벌 : 모든 요청에 적용
로그인/회원 가입
bcryptjs
bcryptjs 단방향 해쉬 알고리즘으로 회원가입시, 비밀번호를 암호화 하기위해 사용 다양한 언어로 되어 있고 사용방법도 거의 동일한 것 같다. 참고
1
npm install bcryptjs --save
1
import * as bcrypt from 'bcryptjs';
로그인/인증
- jwt: 로그인 시에 인증정보를 암호화한다.
- passport: 토큰이 유효한지 검사하고 user정보를 반환하는 기능을 수행한다. 참고
1
npm install @nestjs/jwt @nestjs/passport passport passport-jwt --save
Test
테스트 파일을 작성하면 에러가 날때가 있다. package.json
에서 jest
찾아서 설정을 바꿔주자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"jest": {
"moduleDirectories": [
"node_modules",
"src"
],
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"roots": [
"src"
],
"testRegex": ".spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node",
"moduleNameMapper": {
"src/(.*)": "<rootDir>/src/$1"
}
}