본문 바로가기
Back-end/기초부터 따라하는 nest.js

시즌 2 #8. 기초부터 따라하는 Nest.js 2 : Request 객체와 Query, Param, Body 사용법 (feat. Response)

by hsloth 2024. 6. 17.

 

지난 포스팅에서는 간단하게 API를 구현해봤습니다. 그리고 7-1를 보셨다면, 비동기란 무엇인지 아주 간략하게 봤습니다.

https://suloth.tistory.com/202

 

시즌 2 #7. 기초부터 따라하는 Nest.js 2 : 간단한 API 구현하기

https://suloth.tistory.com/201 시즌 2 #6. 기초부터 따라하는 Nest.js 2 : Nest.js 프로젝트 생성 & 구조 설명지난 포스팅에서는 간단하게 DB 구조를 짜고, 해당 DB 구조에 대한 설명을 들었습니다.https://suloth.ti

suloth.tistory.com

 

https://suloth.tistory.com/203

 

시즌 2 #7-1. 기초부터 따라하는 Nest.js 2 : 동기와 비동기 그리고 Promise

해당 포스팅은 node.js의 기본적인 개념인 비동기와 Promise에 대해서 간단하게 설명하고 넘어가기 위한 포스팅입니다. 굳이 필요가 없으신 분들은 넘어가셔도 됩니다. 나중에 어느정도 기초적인 cs

suloth.tistory.com

 

 

이번 시간에는 Query와 Param, Body 사용법을 알려드리려고 합니다.

Query와 Param, Body가 무엇인지 헷갈리신다면 아래 포스팅의 HTTP Method 부분을 한 번 다시 보시는 것을 추천드립니다.

https://suloth.tistory.com/196

 

시즌 2 #1. 기초부터 따라하는 Nest.js 2 : HTTP 메소드

이전 시간에는 간단하게 서버와 클라이언트에 대해서 다뤄봤습니다.https://suloth.tistory.com/191 시즌 2 #0. 기초부터 따라하는 Nest.js 2 : Orientation조금 더 디테일하게 따라할 수 있는 Nest.js 튜토리얼

suloth.tistory.com

 


과제 정답


우선 지난 시간의 과제 정답을 보도록 하겠습니다.

둘 다 그렇게 어렵지 않습니다.

 

과제 1.

이번에는 /post 경로로 POST 요청을 보내면 Post Main Page라는 문자열을 보내도록 API를 작성해보도록 합시다.

 

// post.controller.ts
import { Controller, Post } from '@nestjs/common';
import { PostService } from './post.service';

@Controller('post')
export class PostController {
  constructor(private readonly postService: PostService) {}

  @Post()
  async getPostMainPage(): Promise<string> {
    const res = await this.postService.getPostMainPage();

    return res;
  }
}

// post.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class PostService {
  async getPostMainPage(): Promise<string> {
    return 'Post Main Page';
  }
}

 

과제 1에서는 #7에서 진행했던 부분 중에서 @Get()@Post() 로만 바뀌고 나머진 거의 같습니다.

 

 

 

과제 2.

/comment/main 경로로 GET 요청을 보내면 Comment Main Page라는 문자열을 보내도록 API를 작성해봅시다.

 

// comment.controller.ts
import { Controller, Get } from '@nestjs/common';
import { CommentService } from './comment.service';

@Controller('comment')
export class CommentController {
  constructor(private readonly commentService: CommentService) {}

  @Get('/main')
  async getCommentMainPage(): Promise<string> {
    const res = await this.commentService.getCommentMainPage();

    return res;
  }
}

// comment.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class CommentService {
  async getCommentMainPage(): Promise<string> {
    return 'Comment Main Page';
  }
}

 

과제 2는 #7에서 진행했던 부분 중에서 @Get() 함수의 인자로 '/main' 이 들어갔습니다.

이렇게 되면 /comment에 이어서 /main 경로로 GET요청을 보내면 해당 함수가 실행되게 됩니다.

따라서 /comment/main 경로로 GET 요청을 보내면 CommentController의 getCommentMainPage 함수가 실행됩니다.

 

끝입니다. 어렵지 않죠?

 


Query


쿼리는 간단하게 말하면, url에서 ?뒤에 붙는 녀석들을 말합니다. 그리고 구분은 &로 합니다.

https://127.0.0.1:3000/user/info?name=hsloth&age=20

에서 name과 age를 말하죠.

이런식으로 서버에게 요청을 보낼 때, 추가적으로 데이터를 보내서 더 자세한 정보를 얻거나, 추가적인 데이터 생성을 가능하게 합니다.

 

Nest.js에서 Query를 사용하는 방법은 간단합니다! 그냥 Query 데코레이터를 사용하면 끝입니다.

먼저, UserController로 가봅시다.

// user.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  // ...

  // /user/info 경로로 Get 요청시 함수가 실행된다.
  @Get('/info')
  async queryTest(
    // name을 key로 가지는 query의 value를 가져온다. 즉, hsloth
    @Query('name') name: string,
    // age를 key로 가지는 query의 value를 가져온다. 즉, 20
    @Query('age') age: string,
  ): Promise<any> {
    return { name, age };
  }
}

 

이렇게 @Query(key) 변수명(아무거나가능): 타입 으로 설정해주면 설정한 변수 안에 query의 value가 담기게 됩니다.

 

nest start 명령어로 서버를 키고, 브라우저에서 http://127.0.0.1:3000/user/info?name=hsloth&age=20 를 입력해주면 다음과 같은 화면을 볼 수 있습니다.

 


Param


파람은 Path라고도 합니다. Nest.js에서는 Param이라고 하니까 저는 Param이라고 하겠습니다.

Param은 /를 구분자로 데이터를 전달하는 녀석들을 말합니다.

https://127.0.0.1:3000/user/name/:name/age/:age

위에서 :name:age가 param이죠.

실제로 사용자가 url 주소창에 입력할 때는

https://127.0.0.1:3000/user/name/hsloth/age/20

이런 식으로 요청을 보냅니다.

 

사실상 Query로 ?name=hsloth&age=20 이렇게 보내는 것과 /name/hsloth/age/20 으로 요청을 보내는 것은 동일한 셈입니다.

자신(혹은 팀)만의 규칙을 정하고 어떤 경우에는 Query를 사용하고, 또 어떤 경우에는 Param을 사용할 지 정해서 자유롭게 사용하면 됩니다.

 

Param 사용법도 간단합니다. Param데코레이터를 사용해주면 돼요. 아래 코드를 UserController에 추가해줍시다.

  // user.controller.ts
  // ...
  @Get('/name/:name/age/:age')
  async paramTest(
    @Param('name') name: string,
    @Param('age') age: string,
  ): Promise<string> {
    return `지금은 Param을 테스트 중이고, name: ${name}, age: ${age} 입니다.`;
  }

:name:age가 Param 데코레이터의 인자로 들어갑니다. (:는 빼고 적어주세요)

 

@Param(:가 붙은 param key) 변수명: 타입 으로 변수명에 값을 넣어서 사용할 수 있습니다.

 

 

 

서버를 열고 브라우저에서 https://127.0.0.1:3000/user/name/hsloth/age/20 를 입력하면 다음과 같은 화면을 볼 수 있습니다.

:name 자리에 hsloth가 들어가고, :age자리에 20 이 들어간 것을 볼 수 있습니다.

 


Body


Query와 Param은 거의 모든 HTTP Method에서 사용할 수 있습니다.

하지만, Body는 Post, Patch, Put과 같은 메소드에서만 사용할 수 있습니다.

 

어떤 리소스에 대해서 생성, 수정 요청을 보낼 때, 리소스에 대한 데이터가 크기 때문에 Request Body를 통해 데이터를 전달해주기 위함입니다. query나 param으로는 많은 데이터를 전달하기에 무리가 있습니다. (url 길이도 길어지고... url 길이 제한도 있구요)

그래서 서버로 요청을 보낼 때 함께 보내는 데이터양이 많아지는 HTTP메소드의 경우 Body에 데이터를 담아서 보냅니다.

 

Nest.js에서는 이렇게 Request Body에 담긴 데이터를 편리하게 받을 수 있도록 만들어둔 데코레이터가 있습니다.

name이 "hsloth"고 age가 20인 user를 생성하는 함수를 만들어봅시다.

//...
  @Post()
  async bodyTest(@Body() body: any): Promise<any> {
    // 원래 이 자리에는 DB에 유저를 생성하는 Service 로직이 들어가 있어야 합니다. (즉, UserService 함수)

    return {
      name: body.name,
      age: body.age,
    };
  }
//...

 

@Body() 변수: 타입 을 컨트롤러의 함수의 인자로 등록해주면 끝입니다. 그러면 body에 알아서 Request body의 데이터가 담깁니다!

 

일단은 이런식으로 작성해주면 됩니다.

그리고 터미널에 nest start 명령어를 입력해서 서버를 열어준 다음, postman에서 요청을 보내봅시다.

 

POST http://127.0.0.1:3000/user 로 Body에 name, age를 담아서 보내니 응답이 제대로 왔습니다.

여기서 주의할 점은 Body -> raw -> JSON 형식을 선택하고 데이터를 넣어주어야 한다는 점입니다.

 


과제


이번에도 역시 과제가 있습니다. 조금 어려울 수도 있을텐데, 한 번 차근차근 해보시길 바랍니다.

 

Query와 Param Body를 이용해서 아래와 같은 API를 구현해봅시다.

 

1. Query를 이용해서 Post Controller에서 Pagination이라는 것을 구현해볼 겁니다. Pagination이란 게시글 목록을 가져올 때, 전부 가져오지 않고 "페이지당 일정한 개수의 게시글만 가져오도록 하는 기법"입니다. 페이지네이션을 위해서는 기본적으로 "현재 페이지"와 "가져올 게시글 개수"가 필요합니다. 이 두 가지를 query로 받아서 그대로 출력하는 API를 만들어주세요. 경로는 /post/list 로 설정하면 좋을 것 같네요.

ex) query를 a=1&b=2&c=3 으로 두었다면, 사용자는 

{ a : 1, b : 2, c : 3 }을 응답받게 됩니다.

 

2. Param을 이용해서 N번째(id가 N인) 게시글을 가져오려고 합니다. 이것을 구현해주세요. 사용자는 게시글의 title과 content를 응답으로 받아야합니다. (Post Controller에서 작업해주세요)

 

3. Body를 이용해서 게시글을 작성하는 API를 만들어주세요. Body에 title과 content를 입력하면, 응답으로 title과 content를 그대로 리턴하도록 만들어주세요. (Post Controller에서 작업해주세요. 그리고 이때, 예전에 만들어두었던 getPostMainPage함수를 제거한 후에 만들어주세요. 해당 함수를 PostController에서 제거하지 않으면, Post데코레이터의 경로가 겹쳐서 제대로 동작하지 않을 수 있습니다.)

 

위의 과제들을 진행하면서, 문제가 발생하는 부분이 하나 있을 겁니다. 그 부분을 파악하고 해결하는 법까지 찾아보세요.

힌트를 드리자면, Pipe라는 녀석을 사용하면 해결할 수 있는 문제가 분명 있을 겁니다.

 

 

 

이상으로 Query, Param, Body에 대한 포스팅을 마치겠습니다. 감사합니다.