[코팩] NestJs REST API 사용법들

Seong Hyeon Kim·2024년 2월 6일
0

NestJs

목록 보기
5/14

이번에 사용하게될 REST API 에 관해서 간단하게 설명을 적어놓고 본격적으로 시작하겠습니다.

1) GET /posts

  • 모든 posts 를 가져온다.

2) GET /posts/:id

  • id에 해당하는 posts 를 가져온다.

3) POST /posts

  • post 를 생성한다.

4) PUT /posts/:id

  • id에 해당하는 post를 변경하거나 만약 없다면 생성한다 (patch 와 다른점은 그래서 생성에 대비해서 필요한 모든 데이터를 넘겨줘야하는 한다)

5) PATCH /posts/:id

  • id에 해당하는 posts 를 변경한다.

6) DELETE /posts/:id

  • id에 해당하는 posts 를 삭제한다.

사전세팅

let posts : PostModel[] = [
  {
    id:1,
    author : 'newjeans_official',
    title : '뉴진스 민지',
    content : '메이크업 고치고 있는 민지',
    likeCount : 10000,
    commentConut : 2000
  },

  {
    id:2,
    author : 'newjeans_official',
    title : '뉴진스 하니',
    content : '춤연습을 하는 하니',
    likeCount : 10000,
    commentConut : 2000
  },
  
  {
    id:3,
    author : 'aespa_official',
    title : '에스파 윈터',
    content : '노래 연습중인 윈터',
    likeCount : 10000,
    commentConut : 2000
  }
]

현재는 db 세팅을 하지 않았기 때문에 우선 임시데이터 저장소로 사용될 배열을 하나 만들어서 게시물들을 몇개 만들어줍니다.


그리고 인터페이스역시 조금 변경을 해줍니다.

interface PostModel{
  id :number;
  author : string;
  title : string;
  content : string;
  likeCount : number;
  commentConut : number;
}

1. Get (전체조회)

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

  @Get()
  getPosts(){
    return posts;
  }
  
  
}
  • get 요청으로 모든데이터를 가져올경우 지금은 임시 데이터저장소인 posts를 가져오게 해주면 간단하게 해결됩니다.

실제로도 데이터가 잘 들어오는 것을 확인할 수 있습니다.



2. Get (게시물 한개만 조회)

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

  @Get()
  getPosts(){
    return posts;
  }
  
  1️⃣
  @Get(':id')
  2️⃣ getPost(@Param('id') 3️⃣ id:string){
    return 4️⃣ posts.find((post)=>post.id === +id)
  }

  
  
}
  • 게시물 선택해서 보여주는 get 요청의 경우 파라미터 값으로 id를 받으면 됩니다. 각각의 포인터들의 추가설명을 드리자면 다음과 같습니다.

    1️⃣ : @Get(':id') ==> 엔드포인터로 추가할 부분을 선언하는 부분입니다.

    2️⃣ : getPost(@Param('id') ==> api 네이밍을 기존에 전제조회의 목적이였던 getPost 에서 한개만을 가져온다는 의미로 복수형을 의미하는 s를 없앴으며 파라미터값으로 가져와야 하기 때문에 @Param을 작성해주었습니다.

    괄호안에 'id' ==> 작성해준 이유는 가령 url 상에서 파라미터값을 여러개로 받아서 사용하는 경우도 있기때문에 이부분을 명시해주고자 작성한 부분입니다.
    ex) http://localhost:3000/:id/:age/:name

    3️⃣ : id:string ==> 그리고 이 파라미터 값으로 받은 id의 타입을 스트링으로 받겠다 라고 지정해주는 부분입니다. (id 값의 경우 특별한 목적이 없다면 스트링으로 받는게 더 좋습니다.)

    4️⃣ posts.find((post)=>post.id === +id) ==> 지금단계 에서는 db 나 orm 을 사용하지 않고 있어서 기본 메서드인 find를 사용해서 화살표함수를 사용한 반복문의 목적으로 작성된 부분입니다. id 에 +를 붙여준 이유는 타입문제를 해결하기 위해서 숫자형으로 변경하기 위해서 작성해주었습니다.

포스트맨 실행결과도 잘 나오는것을 확인할 수 있습니다.

예외처리

그런데 만약 아이디값이 없는 값을 조회하면 어떻게 될까요?

실행이 안되는것은 아니지만 response 값이 없는채로 나오는것을 볼수 있습니다.
이러한 이유는 find 함수를 잘 보면 알수 있는데요.

find 함수는 찾아보고 일치하는 값이 없다고 하면 undefind 를 반환하는것을 알수 있습니다.

이때 사용할 수 있는게 nestjs에서 기본으로 제공되는 에러메소드인 NotFoundException 입니다.

  @Get(':id')
  getPost(@Param('id') id:string){
    const post = posts.find((post)=>post.id === +id)

    if(!post){
      throw new NotFoundException
    }else{
      return post
    }
  }

코드를 다음과 같이 변경해주면 간단하게 에러핸들링을 할수가 있습니다.

실제로 포스트맨에서의 결과도 데이터가 없다라는 의미의 404 에러의 결과값이 나오는것을 확인할 수 있습니다.

이러한 익셉션들은 공식홈페이지에서도 자세하게 확인할 수 있습니다.

https://docs.nestjs.com/exception-filters#built-in-http-exceptions




3.Post (게시물 생성)

포스팅에 필요한 조건으로 바디값으로 작성자, 제목, 내용 이 3가지만을 받게 하고 완성 코드를 먼저 작성해보겠습니다.

  @Post()
  1️⃣ postPosts(
    2️⃣ @Body('author') author : string,
    @Body('title') title : string,
    @Body('content') content : string
  ){
    const post = {
     3️⃣ id : posts[posts.length -1].id +1,
      4️⃣ author,
      title,
      content,
      likeCount:0,
      commentConut:0
    }

    // 기존 포스트 리스트에 새롭게 만든 포스트들을 추가
    5️⃣ posts = [
      ...posts,
      post,
    ];

    // 결과값으로는 리소스를 최대한 줄이기 위해 생성된 포스트만 리턴값으로 제공
    return post

  }

각각의 역할들을 다음과 같습니다

1️⃣ ==> api 이름을 사용될 네이밍 입니다.
2️⃣ ==> 바디값으로 들어올 이름을 명시해준 부분이고, 그것들의 타입까지 지정합니다.
3️⃣ ==> db 세팅이 안되어있어 우선 id 값을 임시로 지정해주기 위해 사용된 부분입니다. 자동으로 기존의 id 값들중 가장 마지막 값에 +1 해주는 내용입니다.
4️⃣ ==> 바디에서 받은 값들을을 할당하는 내용입니다.
5️⃣ ==> orm 을 사용하지 않기때문에 우선 기존 리스트에 새롭게 작성된 내용을 추가하는 로직입니다.

  • 이제 작성된 post 요청이 잘 실행되는지 확인해 보았습니다.

  • 작성된 내용이 추가되었는지 get 요청으로도 한번더 확인하는 모습입니다.


4. Put (수정하기)

파라미터값으로 id를 받아서 해당아이디가 있는지 먼저 찾고,
찾은다음 바디값으로 받은 내용들로 다시 변경해주는 로직을 만들어보겠습니다.


  @Put(':id')
  putPost(
    @Param('id') id:string,
    @Body('author') 1️⃣ author? : string,
    @Body('title') title? : string,
    @Body('content') content? : string
  ){
    const post = posts.find((post)=>post.id === +id)

    if(!post){
      throw new NotFoundException()
    }

    2️⃣ if(author){
      post.author = author
    }

    if(title){
      post.title = title
    }

    if(content){
      post.content = content
    }

    // map 으로 id 체크 후 맞으면 변경
    3️⃣ posts = posts.map((prePost)=>prePost.id === +id ? post : prePost)

    return post;
  }

1️⃣ ==> author? : string, 여기서 ? 가 의미하는 것은 값이 있을수도 있고 없을수도 있을때에를 의미합니다. 바디값으로 받을 준비는 하되 없을수도 있을 경우를 위해 사용된 부분입니다

2️⃣ ==> 바디값으로 받은게 있다면 그 값으로 변경된 새로운 post 를 만드는 부분입니다.

3️⃣ ==> 변경된 포스트를 기존 배열로 변경하기 위해 map 함수를 사용해서 변경하는 모습입니다.

  • 포스트맨으로 실행되었을때에 잘 변경되는것을 확인할 수 있습니다

  • 크로스체크를 위해서 get 요청으로 한번더 확인해도 변경이 잘된것을 확인할 수 있습니다.

삭제하기 (게시물 삭제)

put 메소드와 마찬가지로 파라미터값으로 id를 받아서 해당아이디가 있는지 먼저 찾고, 있다면 삭제하는 형태로 구현을 해보겠습니다.

@Delete(':id')
  deltePost(
    @Param('id') id:string
  ){
    const post = posts.find((post)=>post.id === +id)
    posts = posts.filter((post)=> post.id !== +id)
    
    if(!post) {
      throw new NotFoundException()
    }else{
      return `선택하신 ${id}번 게시물이 삭제되었습니다`
    }

put 과 같은 형태로 코드가 구현이 되었기때문에 다른 설명은 따로 하지 않고 실제 결과만 확인해보겠습니다

마무리

orm 과 db 를 사용하지 nest.js 에서의 REST API 를 사용해보는 기초적인 내용이였습니다.

전체코드

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;
  commentConut : number;
}

let posts : PostModel[] = [
  {
    id:1,
    author : 'newjeans_official',
    title : '뉴진스 민지',
    content : '메이크업 고치고 있는 민지',
    likeCount : 10000,
    commentConut : 2000
  },

  {
    id:2,
    author : 'newjeans_official',
    title : '뉴진스 하니',
    content : '춤연습을 하는 하니',
    likeCount : 10000,
    commentConut : 2000
  },
  
  {
    id:3,
    author : 'aespa_official',
    title : '에스파 윈터',
    content : '노래 연습중인 윈터',
    likeCount : 10000,
    commentConut : 2000
  }
]


  // 1) GET /posts
  //    모든 posts 를 가져온다.
  
  // 2) GET /posts/:id
  //    id에 해당하는 posts 를 가져온다.

  // 3) POST /posts
  //    post 를 생성한다.

  // 4) PUT /posts/:id
  //    id에 해당하는 post를 변경하거나 없으면 생성한단 (patch 와 다른점)

  // 5) DELETE /posts/:id
  //    id에 해당하는 posts 를 삭제한다.

@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()
    }else{
      return post
    }
  }

  @Post()
  postPosts(
    @Body('author') author : string,
    @Body('title') title : string,
    @Body('content') content : string
  ){
    const post = {
      id : posts[posts.length -1].id +1,
      author,
      title,
      content,
      likeCount:0,
      commentConut: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
    }

    // map 으로 id 체크 후 맞으면 변경
    posts = posts.map((prePost)=>prePost.id === +id ? post : prePost)

    return post;
  }

  @Delete(':id')
  deltePost(
    @Param('id') id:string
  ){
    const post = posts.find((post)=>post.id === +id)
    posts = posts.filter((post)=> post.id !== +id)
    
    if(!post) {
      throw new NotFoundException()
    }else{
      return `선택하신 ${id}번 게시물이 삭제되었습니다`
    }
    

  }

}
profile
삽질도 100번 하면 요령이 생긴다. 부족한 건 경험으로 채우는 백엔드 개발자

0개의 댓글