본문 바로가기
Back-end/디지몬 프로젝트

Digimon project : 백엔드 프로젝트 - 초기 설정

by hsloth 2023. 6. 23.

본격적으로 프로젝트를 시작해보자!

 

일단은 프로젝트를 위해 nest.js 초기 설정부터 해주자.

 

우선, Nest.js 프로젝트를 생성한다. (nest설치가 안되어있는 분들은 공식문서가서 nest cli를 설치하고 따라하시면 됩니다)

nest new <project명>

 

그리고 nestia 적용을 위해서 다음 명령어를 입력해주자.

참고로, project폴더로 이동(cd)한 후 입력해줘야한다... (기본적으로 이런 건 다 알 거라고 생각하고 진행을 하겠습니다)

npm install --save-dev nestia
npx nestia setup

 

그리고 nestia.config.ts 파일을 설정해주자. 최상위 폴더에 생성해주어야 한다.

// nestia.config.ts
// nestia configuration file
import type sdk from '@nestia/sdk';

const NESTIA_CONFIG: sdk.INestiaConfig = {
  /**
   * List of files or directories containing the NestJS controller classes.
   */
  input: 'src/domain/**/*.controller.ts',
  /**
   * Output directory that SDK would be placed in.
   *
   * If not configured, you can't build the SDK library.
   */
  output: 'src/api',

  /**
   * Building `swagger.json` is also possible.
   *
   * If not specified, you can't build the `swagger.json`.
   */
  swagger: {
    /**
     * Output path of the `swagger.json`.
     *
     * If you've configured only directory, the file name would be the `swagger.json`.
     * Otherwise you've configured the full path with file name and extension, the
     * `swagger.json` file would be renamed to it.
     */
    output: 'dist/swagger.json',
    /**
     * List of server addresses.
     */
    servers: [
      {
        url: 'http://localhost:3000',
        description: 'Local Server',
      },
    ],
    /**
     * Security schemes.
     */
    security: {},
  },
  /**
   * Whether to wrap DTO by primitive type.
   *
   * If you don't configure this property as `false`, all of DTOs in the
   * SDK library would be automatically wrapped by {@link Primitive} type.
   *
   * For refenrece, if a DTO type be capsuled by the {@link Primitive} type,
   * all of methods in the DTO type would be automatically erased. Also, if
   * the DTO has a `toJSON()` method, the DTO type would be automatically
   * converted to return type of the `toJSON()` method.
   *
   * @default true
   */
  primitive: false,
};
export default NESTIA_CONFIG;

 

 

다음과 같이 설정을 해주자. 자세한 설명은 주석이 있으니 주석을 읽어보길 바란다.

 

nestia.config.ts 파일을 만들었다면, 이를 바탕으로 swagger를 생성할 수 있다.

다음 명령을 입력하자.

npx nestia swagger

 

 

그러면, 이제부터 Nestia관련 기능들을 사용할 수 있다.

nestia에 대한 것은 아래 사이트에서 찾아보자. 굳이 찾아보자 않아도, 내가 쓴 글들을 따라오면 알게 될 것이다.

http://nestia.io/

 

Nestia Guide Documents - Index

NestJS Helper Libraries

nestia.io

 

 

 

Prisma

 

나는 원래 nest.js 에서 ORM은 TypeORM을 사용했었다. 하지만 TypeORM은 타입추론이 잘 안된다는 점이 매우 불편했다.

그래서 이번 프로젝트에는 Prisma를 사용하기로 했다.

npm install prisma --save-dev
npx prisma init --datasource-provider mysql

위의 명령어로 prisma를 설치할 수 있다.

 

그러면 .env 파일이 생성되는데 여기서 아래와 같이 설정을 해주자.

DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE_NAME"

혹은 이렇게도 사용 가능하다. (안해봤지만 해보고 안되면 댓글로 알려주세요...!)

DB_USER=db유저명
DB_PASSWORD=db비밀번호
DB_HOST=db호스트
DB_PORT=db포트

DATABASE_URL="mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/DATABASE_NAME"

 

DB연결을 설정했으니 모델을 작성해보자. schema.prisma 파일에서 모델을 작성할 수 있다.

나는 아래와 같이 작성했다.

model Admin {
  id Int @id @default(autoincrement())
  email String @unique
  password String
  firstName String
  middle_name String?
  last_name String
  nickname String @unique
  introduction String? @db.Text
  birth DateTime @db.Date
  
  emailReception Boolean

  createdAt DateTime? @default(now())
  updatedAt DateTime? @updatedAt
  deletedAt DateTime?

  genderId Int 
  gradeId Int

  Gender Gender @relation(fields: [genderId], references: [id])
  AdminGrade AdminGrade @relation(fields: [gradeId], references: [id])

  MainPosting MainPosting[]
}

model Gender {
  id Int @id @default(autoincrement())
  name String @unique
  Admin Admin[]
}

model AdminGrade {
  id Int @id @default(autoincrement())
  name String @unique
  Admin Admin[]
}

model MainPosting {
  id BigInt @id @default(autoincrement())
  title String
  content String @db.Text
  
  createdAt DateTime? @default(now())
  updatedAt DateTime? @updatedAt
  deletedAt DateTime?

  categoryId Int
  adminId Int

  MainPostingCategory MainPostingCategory @relation(fields: [categoryId], references: [id])
  Admin Admin @relation(fields: [adminId], references: [id])

  MainPostingReport MainPostingReport[]
}

model MainPostingCategory {
  id Int @id @default(autoincrement())
  name String @unique
  orderId Int? // 해당 카테고리의 분류번호를 나타냄. 분류번호가 낮을 수록 맨 위에 해당 카테고리가 위치함.

  parentId Int?

  MainPosting MainPosting[]
}

model MainPostingReport {
  id BigInt @id @default(autoincrement())
  title String 
  content String @db.Text

  mainPostingId BigInt

  MainPosting MainPosting @relation(fields: [mainPostingId], references: [id])
}

프리즈마 모델 작성 방법은 구글링과 공식문서를 애용하도록하자. 정~말 쉽다.

 

작성한 모델을 DB에 반영하기 위해서 다음 명령어를 입력하자.

npx prisma db push

해당 명령어를 입력하면 Prisma로 작성한 모델들이 DB에 적용이 된다.

 

그리고 prisma를 이용하기 위해서는 prisma client를 설치해야한다.

npm install @prisma/client

 

설치 후, PrismaService를 만들어서 사용하면 된다.

// prisma/prisma.service.ts
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

// prisma/prisma.module.ts
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

// main.ts
// enableShutdownHooks를 위해서 main.ts에 설정해주어야한다.
async function bootstrap() {
	...
	const prismaService = app.get(PrismaService);
  await prismaService.enableShutdownHooks(app)
  ...
}
bootstrap()


// prismaService를 사용할 때는 이렇게 사용하자.
// cat.module.ts
@Module({
	imports: [PrismaModule],
    ...
})
export class CatModule {}

// cat.service.ts
export class CatService {
	constructor(
    	private readonly prisma: PrismaService
    ) {}
    ...
}