본문 바로가기
Archive

TypeORM 과 API

by livemehere 2022. 7. 31.

그동안 express로 서버개발을 꽤많이 해왔고, 다른 커뮤니티를 찾아보지 않아도 느꼈던, express의 자유도는 오히려 장기적으로, 엔터프라이즈 용으로는 분리한 점이 느껴졌다.

중간중간 Nest의 핵심 개념과 기능들을 정리해 보고자 한다.

 

공식문서

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

 

공식문서는 아니지만, 검색시 노출이 많이되는 꽤 괜찬은 문서

 

README_ko - typeorm

이 예시에서는 MySQL을 사용하고 있지만 지원되는 다른 데이터베이스를 사용할 수도 있다. 다른 데이터 베이스를 사용하려면 옵션의 type을 사용 중인 데이터베이스 타입으로 변경하기만 하면 된

orkhan.gitbook.io

 

DB연결하기

서버에서 가장중요한것이 DB와 연결된 API를 제공하는 것이라 생각한다.

인증, dto 이런것들 이 이후라고 생각한다.

 

mysql + typeorm 설치

npm install --save @nestjs/typeorm typeorm mysql2

 

docker db 설치

설치후 스키마도 하나 생성해준다.

docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=1234 -d -p 3306:3306 mysql:latest

 

app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from './posts/posts.module';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '1234',
      database: 'kong',
      synchronize: true,
      keepConnectionAlive: true,
      logging: 'all',
      charset: 'utf8mb4',
      autoLoadEntities: true,
    }),
    PostsModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
  • type: db 종류
  • host: db 주소
  • port: db포트(mysql은 보통 3306)
  • username: db 사용자이름
  • password: db 사용자 비번
  • database: db 데이터베이스 이름
  • entities: 만든 엔티티들 여기에 넣기
  • autoLoadEntities: true면 TypeOrmModule.forFeature에 넣은 엔티티들은 자동 연결됨
  • synchronize: true면 entity에 따라 실제 db 테이블 재생성(기존 테이블 다 날라가니 주의)
  • logging: true면 typeorm이 만들어주는 쿼리가 콘솔에 표시(개발 시에는 켜두는 게 매우 유용)
  • keepConnectionAlive: true여야 핫 리로딩시에도 db 연결이 끊어지지 않음
  • charset: db의 언어 설정(utf8mb4로 할것)

엔티티 생성(테이블 생성)

Repository pattern

TypeORM을 사용하는 패턴은 여러개가 있다. 그중에서 개인적으로 repository 패턴을 선호한다.(이유는 처음이걸로 접했으니까..)

각 Entity는 각각의 Repository(저장공간)이 있다.

 

Entity(테이블)정의

import {
  Column,
  CreateDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class Article {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ type: 'text' })
  content: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}

(밑에서 forFeature([Arficle])) DI시 -> 자동으로 디비에 테이블이 생성됨

모듈, 컨트롤러, 서비스 생성하기

nest에서는 큰 기능 범주로 모듈을 나누고, 모듈 내에서 요청과 응답을 처리하는 controller, 비지니스로직이 들어가는 service 3가지로 구성된다.

 

nest g mo posts // 모듈 생성
nest g co posts // 컨트롤러 생성
nest g s posts // 서비스 생성

테스트 파일을 제거하면 3개의 파일이 핵심이다.

API 생성하기

provider는 단순히 @Injectable() 데코레이터 주석이 달린 클래스를 말한다. provider 객체는 런타임에 NestJS에 의해 다른 모듈로 주입될 수 있다.
provider는 service를 포함해 repository, factory, helper 등이 될 수 있다.

@Injectable() 데코레이터가 붙어있는 클래스는 constructor를 통해서 의존성을 주입할 수 있다. 이렇게 하면 클래스 내부에서 this를 통해서 해당 서비스에 접근할 수 있게 된다.

import { Controller, Get, Post } from '@nestjs/common';
import { PostsService } from './posts.service';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  findAll() {
    return this.postsService.findAll();
  }

  @Post()
  create() {
    return this.postsService.createOne();
  }
}
import { Injectable } from '@nestjs/common';

@Injectable()
export class PostsService {
  findAll() {
    return 'findAll';
  }

  createOne() {
    return 'create';
  }
}

TypeORM Dependency Injection

Post데코레이터와 겹쳐서 Entity의 이름을 Article로 변경하였습니다
@Module({
  imports: [TypeOrmModule.forFeature([Article])],
  controllers: [PostsController],
  providers: [PostsService],
})
import { Body, Controller, Get, Post } from '@nestjs/common';
import { PostsService } from './posts.service';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  findAll() {
    return this.postsService.findAll();
  }

  @Post()
  create(@Body() body: any) {
    return this.postsService.createOne(body);
  }
}

 

조회, 생성

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Article } from '../entity/article.entity';
import { Repository } from 'typeorm';

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Article)
    private articleRepository: Repository<Article>,
  ) {}

  findAll() {
    return this.articleRepository.find();
  }

  async createOne(body) {
    const { title, content } = body;
    const newArticle = this.articleRepository.create({ title, content });
    return this.articleRepository.save(newArticle);
  }
}

 

수정,삭제

@Patch(':id')
update(@Param('id') id: string, @Body() body: any) {
return this.postsService.updateById(+id, body);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.postsService.removeById(+id);
}
updateById(id: number, body: any) {
return this.articleRepository.update(id, body);
}

removeById(id: number) {
return this.articleRepository.delete(id);
}

 

반응형

'Archive' 카테고리의 다른 글

CORS 와 Cookie  (0) 2022.07.31
static 파일제공 & View Engine & React  (0) 2022.07.31
Cookie 와 session 으로 인증관리하기  (0) 2022.07.31
TS 냐금냐금 - 6  (0) 2022.07.30
TS 냐금냐금 - 4  (0) 2022.07.30