포시코딩

[Nest.js] 8. TypeORM Repository 적용 (끝) 본문

Node.js

[Nest.js] 8. TypeORM Repository 적용 (끝)

포시 2023. 2. 16. 14:49
728x90

service 수정

board.service.ts

import _ from 'lodash';
import {
  Injectable,
  NotFoundException,
  UnauthorizedException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Article } from './article.entity';
import { Repository } from 'typeorm';

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

  async getArticles() {
    return await this.articleRepository.find({
      where: { deletedAt: null },
      select: ['id', 'title', 'author', 'createdAt'],
    });
  }

  async getArticleById(id) {
    return await this.articleRepository.findOne({
      where: { id, deletedAt: null },
      select: ['title', 'content', 'author', 'createdAt', 'updatedAt'],
    });
  }

  createArticle(title: string, content: string, password: number) {
    this.articleRepository.insert({
      author: 'test',
      title,
      content,
      password: password.toString(),
    });
  }

  async updateArticle(
    id: number,
    title: string,
    content: string,
    password: number,
  ) {

    // const article = await this.getArticleById(id);
    // 해당 메소드에는 password를 포함하고 있지 않기 때문에 사용 불가

    // const article = await this.articleRepository.findOne({
    //   where: { id, deletedAt: null },
    //   select: ['password'],
    // });
    // if (_.isNil(article)) {
    //   throw new NotFoundException('Article not found. id: ' + id);
    // }
    // if (article.password !== password.toString()) {
    //   throw new UnauthorizedException(`Password is not corrected. id: ${id}`);
    // }

    // 위 함수는 deleteArticle 에서도 쓰이기 때문에 따로 메소드화
    await this.verifyPassword(id, password);

    this.articleRepository.update(id, { title, content });
  }

  async deleteArticle(id: number, password: number) {
    await this.verifyPassword(id, password);

    this.articleRepository.softDelete(id);
  }

  private async verifyPassword(id: number, password: number) {
    // 굳이 노출될 필요 없는 메소드는 private하게
    const article = await this.articleRepository.findOne({
      where: { id, deletedAt: null },
      select: ['password'],
    });
    if (_.isNil(article)) {
      throw new NotFoundException('Article not found. id: ' + id);
    }
    if (article.password !== password.toString()) {
      throw new UnauthorizedException(`Password is not corrected. id: ${id}`);
    }
  }
}

 

createArticle() 에는 async/await 안 쓴 이유

getArticles(), getArticleById()는 find나 findOne을 해서 꼭 목록을 받아오는걸 보장해줘야 한다.

동기식으로 갖고 와야 하는데

 

createArticle()은 article을 생성하고나서

article을 생성했다는 응답을 받지 않아도 되기 때문에 굳이 async/await을 하지 않았다.

 

Controller 수정

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
} from '@nestjs/common';
import { BoardService } from './board.service';
import { CreateArticleDto } from './create-article.dto';
import { DeleteArticleDto } from './delete-article.dto';
import { UpdateArticleDto } from './update-article.dto';

@Controller('board')
export class BoardController {
  // 서비스 주입
  constructor(private readonly boardService: BoardService) {}

  // 게시물 목록을 가져오는 API
  @Get('/articles')
  async getArticles() {
    return await this.boardService.getArticles();
  }

  // 게시물 상세보기 -> 게시물 ID로 확인
  @Get('/articles/:id')
  async getArticleById(@Param('id') articleId: number) {
    return await this.boardService.getArticleById(articleId);
  }

  // 게시물 작성
  @Post('/articles')
  createArticle(@Body() data: CreateArticleDto) {
    return this.boardService.createArticle(
      data.title,
      data.content,
      data.password,
    );
  }

  // 게시물 수정
  @Put('/articles/:id')
  async updateArticle(
    @Param('id') articleId: number,
    @Body() data: UpdateArticleDto,
  ) {
    return await this.boardService.updateArticle(
      articleId,
      data.title,
      data.content,
      data.password,
    );
  }

  // 게시물 삭제
  @Delete('/articles/:id')
  async deleteArticle(
    @Param('id') articleId: number,
    @Body() data: DeleteArticleDto,
  ) {
    return await this.boardService.deleteArticle(articleId, data.password);
  }
}

service가 변경되었으니 그에 맞춰 controller도 수정

 

결과 확인

npm run start

이렇게 서버가 잘 실행되면 끝!

 

Insomnia에서 테스트해보면 데이터가 잘 들어가는 모습을 볼 수 있다.

 

DB 못찾는 에러

서버 실행 시 위와 같은 로그가 뜨면서

Unknown database 'nest_prac'

즉, 우리가 .env에 세팅해둔 DATABASE_NAME 상의 DB를 찾지 못해 발생하는건데

TypeORM이 Table은 만들어줘도 DB 까지 생성해주진 않는다. 

 

직접 만든 후 다시 시도하면 잘 될거임

 

마치며

여기까지 기본적인 Nest.js와 TypeORM을 사용해 간단한 게시판을 만들어보았다.

 

지금까지 작성한 코드는

https://github.com/cchoseonghun/nest_prac/tree/main/nbcamp/sparta_nest

 

GitHub - cchoseonghun/nest_prac

Contribute to cchoseonghun/nest_prac development by creating an account on GitHub.

github.com

여기서 직접 확인 가능하다.

 

그 외 따로 연습중인 repo

https://github.com/cchoseonghun/nestjs_sample

 

GitHub - cchoseonghun/nestjs_sample: Sample Back-End project using Nest.js. with Front-end using ejs or React.js

Sample Back-End project using Nest.js. with Front-end using ejs or React.js - GitHub - cchoseonghun/nestjs_sample: Sample Back-End project using Nest.js. with Front-end using ejs or React.js

github.com

728x90