코딩 정보/NestJs

[NestJs] 기본적인 restful api 만들어 보기

꽁이꽁설꽁돌 2025. 1. 6. 21:31
728x90
반응형
     

목차

     

     

    초기 세팅 설정

    초기 세팅은 다음과 같다.

     

    1. nest js 설치

    npm install -g @nestjs/cli

     

    2.nest로 세팅하기

    nest new 프로젝트명

     

    -> pnpm, yarn, pnpm 중 원하는 패키지 매니저를 선택해 주자

     

    다음과 같이 세팅이 완료 된다.

     

    이후 빨간색 에러가 뜰 수도 있는데 자신이 설치한 패키지 매니저로 init 해주자

    npm init
    yarn init
    pnpm init

     

     

    처음생성되는 src 파일을 살펴보면 다음과 같다.

     

     

    app.module.ts

    애플리케이션 루트 모듈로 다른 모든 모듈을 포함한다.

    import { Module } from '@nestjs/common';
    import { PostsService } from './posts.service';
    import { PostsController } from './posts.controller';
    
    // @Module 데코레이터는 NestJS에서 모듈을 정의하는 데 사용됩니다.
    // 이 데코레이터는 해당 모듈에 속한 컨트롤러, 서비스, 그리고 다른 의존성을 관리합니다.
    // 즉, 이 모듈이 애플리케이션에서 어떤 기능(컴포넌트)들을 포함하고 있는지 설정하는 역할을 합니다.
    
    @Module({
      // controllers는 이 모듈에 포함된 컨트롤러들을 정의합니다.
      // 컨트롤러는 들어오는 요청(Request)을 처리하고, 
      // 적절한 서비스를 호출한 뒤, 응답(Response)을 반환하는 역할을 합니다.
      // 여기서는 PostsController가 이 역할을 담당합니다.
      controllers: [PostsController],  // PostsController는 클라이언트 요청을 처리하는 진입점입니다.
    
      // providers는 이 모듈에 의존성 주입(Dependency Injection)으로 제공할 클래스들을 정의합니다.
      // 주로 서비스(Services), 리포지토리(Repositories), 팩토리(Factories) 등이 포함됩니다.
      // 여기서는 PostsService를 정의하여, 이 모듈에서 사용할 수 있도록 설정합니다.
      providers: [PostsService], // PostsService는 비즈니스 로직과 데이터 처리를 담당합니다.
    })
    export class PostsModule {
      // PostsModule은 게시물(Posts) 기능과 관련된 모든 의존성을 그룹화한 모듈입니다.
      // 이 모듈은 다른 모듈에서 PostsController와 PostsService를 사용할 수 있도록 설정합니다.
    }

     

    위에서 자세히 주석이 써져있는 것은 ioc의 개념이 중요하기 때문이다.

    궁금하면 아래를 참고하자

    https://ilikezzi.tistory.com/13#hELLO

     

    [Nest.JS] IoC , DI란? 그리고 NestJS의 꽃 Provider

    미루고 미루다가 오늘 드디어 NestJS의 꽃인 Provider와 필수로 알고 가야되는 Ioc, DI에 대해 포스팅 해보려고한다. 처음 공식문서를 접했을 때엔 이게 무슨소린가 싶었지만 너무나 중요한개념이라

    ilikezzi.tistory.com

     

    app.controller.ts

    http 요청을 처리하는 컨트롤러이다.

     

    app.service.ts

    app.controller.ts의 비지니스 로직을 처리하는 서비스이다.

    import { Injectable } from '@nestjs/common';
    
    @Injectable()  //주입을 해주기 위해서 필요 -> 그후 모듈에서 주입 시켜주어야 함
    export class AppService {
      getHello(): string {
        return 'Hello World!'; // 비즈니스 로직 처리
      }
    }

     

    main.ts

    애플리케이션의 시작점이다.

     

    기본적으로 이러한 구성으로 확장하기 용이하게 설계되어

    같은 구조로 추가하면 된다.

     

     

    우리는 post부분을 만들 것이기 때문에 다음의 명령어를 입력하자

    nest g resource

     

    posts라고 입력해주면 다음과 같이 생기게 된다.

     

    로직 분리 전 파일 controller.ts

    import {
      Body,
      Controller,
      Delete,
      Get,
      NotFoundException,
      Param,
      Post,
      Put,
    } from '@nestjs/common';
    import { PostsService } from './posts.service';
    
    interface PostModel {
      id: number;
      author: string;
      title: string;
      content: string;
      likeCount: number;
      commentCount: number;
    }
    
    //초기 더미 데이터
    let posts: PostModel[] = [
      {
        id: 1,
        author: 'suji',
        title: '민지',
        content: '하이',
        likeCount: 999,
        commentCount: 101,
      },
      {
        id: 2,
        author: 'ggg',
        title: '수지',
        content: '안녕',
        likeCount: 96,
        commentCount: 1,
      },
      {
        id: 3,
        author: 'sins',
        title: '규진',
        content: '감사',
        likeCount: 999,
        commentCount: 1001,
      },
    ];
    
    
    // GET / post
    // 모든 post를 다 가져온다.
    
    // GET / posts/:id
    // id에 해당되는 post를 가져온다.
    
    // POST / posts
    // POST를 생성한다
    
    // PUT / post/:id
    // id에 해당되는 POST를 변경한다
    
    // DELETE / posts/:id
    // id에 해당되는 POST를 삭제한다.
    
    
    
    //요청을 받고 정확하게 함수로 라우팅해주는 역할
    @Controller('posts')
    export class PostsController {
      constructor(private readonly postsService: PostsService) {}
      @Get()
      getPosts() {
        return posts;
      }
    
      @Get('/:id')
      getPost(@Param('id') id: string) {
        const post = posts.find((post) => post.id === +id);
        if (!post) {
          throw new NotFoundException();
        }
        return post;
      }
    
      @Post()
      postPosts(
        @Body('author') author: string,
        @Body('title') title: string,
        @Body('content') content: string,
      ) {
        const post: PostModel = {
          id: posts[posts.length - 1].id + 1,
          author,
          content,
          title,
          likeCount: 0,
          commentCount: 0,
        };
    
        posts = [...posts, post];
        return post;
      }
    
      @Put(':id')
      putPost(
        @Param('id') id: string,
        @Body('author') author?: string,
        @Body('title') title?: string,
        @Body('content') content?: string,
      ) {
        const post = posts.find((post) => post.id === +id);
        if (!post) {
          throw new NotFoundException();
        }
        if (author) {
          post.author = author;
        }
        if (title) {
          post.title = title;
        }
        if (content) {
          post.content = content;
        }
        posts = posts.map((prevPost) => (prevPost.id === +id ? post : prevPost));
        return posts;
      }
    
      @Delete(':id')
      deletePost(@Param('id') id: string) {
        const post = posts.find((post) => post.id === +id);
        if (!post) {
          throw new NotFoundException();
        }
        posts = posts.filter((post) => post.id !== +id);
        return id;
      }
    }
    
    //주로 사용되는 exception
    // BadRequestException
    // UnauthorizedException
    // NotFoundException
    // ForbiddenException

     

    기본적인 작동은 잘 이루어지지만 비지니스 로직을 분리해 주어야 한다.

    한쪽은 라우팅, 한쪽은 비지니스 로직에 집중해서 보기 쉽게 해야 하기 때문이다.

     

    분리된 파일의 모습

    import {
      Body,
      Controller,
      Delete,
      Get,
      Param,
      Post,
      Put,
    } from '@nestjs/common';
    import { PostsService } from './posts.service';
    
    // GET / post
    // 모든 post를 다 가져온다.
    
    // GET / posts/:id
    // id에 해당되는 post를 가져온다.
    
    // POST / posts
    // POST를 생성한다
    
    // PUT / post/:id
    // id에 해당되는 POST를 변경한다
    
    // DELETE / posts/:id
    // id에 해당되는 POST를 삭제한다.
    
    //요청을 받고 정확하게 함수로 라우팅해주는 역할
    @Controller('posts')
    export class PostsController {
      constructor(private readonly postsService: PostsService) {}
      @Get()
      getPosts() {
        return this.postsService.getAllPosts();
      }
    
      @Get('/:id')
      getPost(@Param('id') id: string) {
        return this.postsService.getPostById(+id);
      }
    
      @Post()
      postPosts(
        @Body('author') author: string,
        @Body('title') title: string,
        @Body('content') content: string,
      ) {
        return this.postsService.createPost(author, title, content);
      }
    
      @Put(':id')
      putPost(
        @Param('id') id: string,
        @Body('author') author?: string,
        @Body('title') title?: string,
        @Body('content') content?: string,
      ) {
        return this.postsService.updatePost(+id, author, title, content);
      }
    
      @Delete(':id')
      deletePost(@Param('id') id: string) {
        return this.postsService.deletePost(+id);
      }
    }
    
    //주로 사용되는 exception
    // BadRequestException
    // UnauthorizedException
    // NotFoundException
    // ForbiddenException

     

    import { Injectable, NotFoundException } from '@nestjs/common';
    
    export interface PostModel {
      id: number;
      author: string;
      title: string;
      content: string;
      likeCount: number;
      commentCount: number;
    }
    
    let posts: PostModel[] = [
      {
        id: 1,
        author: 'suji',
        title: '민지',
        content: '하이',
        likeCount: 999,
        commentCount: 101,
      },
      {
        id: 2,
        author: 'ggg',
        title: '수지',
        content: '안녕',
        likeCount: 96,
        commentCount: 1,
      },
      {
        id: 3,
        author: 'sins',
        title: '규진',
        content: '감사',
        likeCount: 999,
        commentCount: 1001,
      },
    ];
    
    @Injectable()
    export class PostsService {
      getAllPosts() {
        return posts;
      }
    
      getPostById(id: number) {
        const post = posts.find((post) => post.id === +id);
        if (!post) {
          throw new NotFoundException();
        }
        return post;
      }
    
      createPost(author: string, title: string, content: string) {
        const post: PostModel = {
          id: posts[posts.length - 1].id + 1,
          author,
          content,
          title,
          likeCount: 0,
          commentCount: 0,
        };
    
        posts = [...posts, post];
        return post;
      }
    
      updatePost(postId: number, author?: string, title?:string, content?: string){
          const post = posts.find((post) => post.id === postId);
            if (!post) {
              throw new NotFoundException();
            }
            if (author) {
              post.author = author;
            }
            if (title) {
              post.title = title;
            }
            if (content) {
              post.content = content;
            }
            posts = posts.map((prevPost) => (prevPost.id === postId ? post : prevPost));
            return posts;
      }
    
      deletePost(postId: number){
        const post = posts.find((post) => post.id === postId);
        if (!post) {
          throw new NotFoundException();
        }
        posts = posts.filter((post) => post.id !== postId);
        return postId;
      }
      
    }

     

    강의출처

     

    [코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core 강의 | 코드팩토리 -

    코드팩토리 | 자바스크립트, 타입스크립트 다음은 백엔드 개발! NestJS를 이용한 REST API 백엔드 개발, Socket IO 개발 및 배포를 할 수 있게 됩니다., 백엔드가 처음이어도 누구나 OK! 트렌디한 NestJS로

    www.inflearn.com

     

     

    반응형