Lsiron
Nest.js 에서 API 만들기 (get, post, patch, delete) 본문
Nest.js를 사용하여 간단한 CRUD API를 만드는 방법을 다뤄보겠다.
먼저 app.controller.ts 파일로 가보자.
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
AppController는 Node.js의 Router와 같은 역할을 한다.
즉, Get 데코레이터는 express의 get Router 를 의미하며, 메소드 데코레이터 형식으로 쓰인 것.
한번 임의로 데코레이터를 만들고 실행해보자.
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('/lsiron')
getLsiron(): string {
return "i'm lsiron";
}
}
lsiron 이라는 경로를 만들어주고, i'm lsiron 문자열을 반환하도록 만들어준 뒤, 실행 해 보았다.
주의할 점은 데코레이터는 꾸며주는 함수나 클래스 바로 위에 붙어있어야한다.
( 즉 데코레이터와 함수 사이에 빈칸을 두면 안된다. )
정말 express에서 get Router와 똑같은 역할을 하는 것을 볼 수 있었다.
당연히 @Post로 만들어주면 express에서 app.post를 만든 것 처럼 작동을 한다.
( 대신 @nestjs/common 에서 Post 데코레이터를 가져와주어야 한다. )
controller는 url을 가져오는 역할만 할 뿐이고, 비즈니스 로직은 service에서 담당한다.
nest.js에서 하는 방식으로 바꾸어 준다면 아래와 같다.
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('/lsiron')
getLsiron(): string {
return this.appService.getLsiron();
}
}
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
getLsiron(): string {
return "i'm lsiron"
}
}
이렇게 controller는 url을 가져오고 function을 반환만 해주며, 이 function의 내용은 service에 들어있다.
( 함수의 이름은 굳이 controller와 똑같이 할 필요는 없다. )
이제 nest.js를 설치했을 때, 기본으로 들어있는 내용을 지우고 CRUD API를 새로 만들어보자.
먼저 controller와 service 파일을 삭제 해 준 뒤 module파일에 import 해준 controller와 service를 지워준다.
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
위 처럼 src 폴더는 module과 main 파일만 남겨주고 module 파일 내부는 오로지 Module 만을 남겨놓자.
새로운 작업을 위해 첫 번째로 만들어 줄 것은 controller이다.
허나 우리는 nest.js를 설치하면서 cli를 사용할 수 있게 되었기 때문에 명령어 만으로 controller를 만들 수 있다.
아래의 명령어를 입력하여 설치해주자.
$ nest g co "movies"
위 명령어에서 g와 co는 각각 generate 와 controller의 약어이다. 그리고 " " 안에 만들고자 하는 controller의 이름을 적어주면 된다.
나는 movies controller를 만들것 이기 때문에 이름을 movies라고 적었다.
import { Module } from '@nestjs/common';
import { MoviesController } from './movies/movies.controller';
@Module({
imports: [],
controllers: [MoviesController],
providers: [],
})
export class AppModule {}
이러면 자동으로 movies controller를 담은 폴더가 생성됨과 동시에 module 파일에 moviesController가 기입된 것을 볼 수 있다.
spec 파일은 테스트파일인데 나중에 다시 생성 해 줄 것이기 때문에 일단은 지워주자.
이제 movies.controller,ts 파일로 가서 Get 요청을 날리는 API를 만들어보자.
import { Controller, Get } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
}
위와 같이 코드를 만들어준다. 참고로 @Controller('movies')의 movies는 Entry Point 이다.
즉, 이 controller는 무조건 /movies 를 거쳐야 한다는 것 이다.
예를들어, movies 를 Entry Point로 입력한 controller에 @get 데코레이터의 경로를 '/lsiron' 으로 설정한다면
lsiron 페이지로 접속하기 위해선 url을 localhost:3000/movies/lsiron으로 입력해야한다.
한번 실행한 뒤, /movie url로 들어가보자.
실행이 잘 되는 것을 볼 수 있다.
그러면 url 파라미터 방식으로 API를 하나 더 만들어보자.
import { Controller, Get } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
@Get('/:id')
getOne(){
return "This will return one movie"
}
}
url 파라미터 방식으로 만들어주었다.
이제 /movies 뒤에 / 를 넣고 아무 숫자를 입력해도 "This will return one movie" 를 보여줄 것이다.
실행이 잘 되는 것을 볼 수 있다.
프로젝트를 진행하다보면 본문에 params로 id값을 받아올때가 많은데 이 경우는 어떻게 해 주어야 할까?
express에서는 const id = req.params.id 이런 형식으로 받아왔었다. nest.js에서도 구성요소는 비슷하지만 구조가 아예 다르다.
import { Controller, Get, Param } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
@Get('/:id')
getOne(@Param('id') id: string){
return `This will return one movie with the id ${id}`;
}
}
req와 const문자가 없는 것 빼고는 구성요소가 똑같다.
@nestjs/common 에서 @Param 데코레이터를 가져오고 getOne 함수 인자에 모두 넣어준다.
@Param 데코레이터의 인자와 @Get 데코레이터의 인자는 이름이 같아야 하지만, 인자 우측에 있는 id는 const id의 id라고 생각하면 된다.
@Get('/:id')
getOne(@Param('id') movieId: string){
return `This will return one movie with the id ${movieId}`;
}
이렇게 'movidId' 로 이름을 바꿔줘도 상관없다. 그냥 변수로 보면 된다.
이제 한번 실행 해 보자.
실행이 잘 되며, url parameter 에서 데이터를 잘 받아오는 것 까지 확인 할 수 있었다.
이제까지 배운Get 요청과 Param을 바탕으로 Post요청과 Delete 요청을 날리는 API를 만들어보자.
import { Controller, Get, Post, Delete, Param } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
@Get('/:id')
getOne(@Param('id') movieId: string){
return `This will return one movie with the id ${movieId}`;
}
@Post()
create() {
return 'This will create a movie';
}
@Delete('/:id')
remove(@Param('id') movieId: string) {
return `This will delete a movie with the id: ${movieId}`;
}
}
Post API test
Delete API test
모두 정상적으로 실행 되는 것을 알 수 있다.
마지막으로 patch 요청을 날리는 API를 만들어보자.
express에서 Update API를 만들 때 모두 Put을 사용했지만, nest.js 에서는 조금 다르다.
바로 전체 업데이트와 부분 업데이트로 나뉘는데, 전체 업데이트는 Put을 사용하고 부분 업데이트는 Patch를 사용한다.
Put은 모든 리소스를 업데이트 하기 때문에 위 예시코드의 경우 전체 movie를 업데이트 할 때 사용한다.
허나 Patch는 일부 리소스를 업데이트 하기 때문에 위 예시코드의 경우 일부 movie를 업데이트 할 때 사용한다.
일단 나는 Patch로 만들어보겠다.
import { Controller, Get, Post, Delete, Patch, Param } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
@Get('/:id')
getOne(@Param('id') movieId: string){
return `This will return one movie with the id ${movieId}`;
}
@Post()
create() {
return 'This will create a movie';
}
@Delete('/:id')
remove(@Param('id') movieId: string) {
return `This will delete a movie with the id: ${movieId}`;
}
@Patch('/:id')
patch(@Param('id') movieId: string) {
return `This will patch a movie with the id: ${movieId}`;
}
}
Patch API Test
모두 정상적으로 실행 되는 것을 알 수 있다.
여기서 조금만 더 파고들어 보자.
만약 Post메서드로 request의 body 부분을 가져오고 싶다면 어떻게 해야할까?
위에서 @param으로 삽입했듯이 똑같이 @body로 삽입하면 된다.
@Post()
create(@Body() movieData) {
console.log(movieData);
return 'This will create a movie';
}
Param을 적용했을 때와 똑같이 const movieData = req.body 와 똑같다.
( Param을 적용했을땐, @Param의 인자로 id를 넣어줬었는데, Body는 req.body 밖에 없으니 인자를 넣어주지 않은 것 )
이제 postman으로 JSON 데이터를 API로 한번 보내보자.
send를 누르면 명령어 창에 console.log가 제대로 찍힌 것을 확인 할 수 있다.
movieData로 req.body 값 전체를 받아왔으니, movieData만 console 로 찍어도 데이터를 전부 다 가져오는 것 이다.
이제 movieData를 return 값으로 넣어보자.
@Post()
create(@Body() movieData) {
return movieData;
}
다시 Postman으로 send를 눌러보자.
movieData 값이 그대로 return 되는 것을 확인 할 수 있다.
Post 메서드를 통해 body를 생성했다면? 우리는 Patch 메서드 또한 손을 봐 주어야한다. => 생성한 값을 수정하는 로직
게시판으로 예를 들자면 글을 작성한 유저의 아이디를 Param으로 받아와서 Body 값을 수정 해 주는 것 이다.
@Patch('/:id')
patch(@Param('id') movieId: string, @Body() updateData) {
return {
updatedMovie: movieId,
...updateData,
};
}
즉, 업데이트 할 movie의 id랑 우리가 보낼 데이터의 object를 return 해 준 것이다.
똑같이 Postman으로 가서 JSON 형식으로 데이터를 보내보자.
위와 같이 return이 잘 되는것을 확인 할 수 있다.
여기서 nest.js의 장점이 있다. 본래 express.js에서 body값을 JSON 형식으로 파싱하고 JSON 데이터를 return 하려면 별도의 설정이 필요했었다.
app.use(express.json());
위 설정이 기억 날 것이다.
허나, nest.js에서는 별도의 설정을 안 해줘도 위와 같이 body값을 자동으로 JSON 형식으로 파싱하고 return까지 해준다.
추가로 Get 메서드를 사용하여 API를 하나 더 만들어보자.
import { Controller, Get, Post, Delete, Patch, Param, Body } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(){
return "This will return all movies";
}
@Get('/search')
search(){
return `We are searching for a movie made after: `
}
@Get('/:id')
getOne(@Param('id') movieId: string){
return `This will return one movie with the id ${movieId}`;
}
@Post()
create(@Body() movieData) {
return movieData;
}
@Delete('/:id')
remove(@Param('id') movieId: string) {
return `This will delete a movie with the id: ${movieId}`;
}
@Patch('/:id')
patch(@Param('id') movieId: string, @Body() updateData) {
return {
updatedMovie: movieId,
...updateData,
};
}
}
/search endpoint로 하나 만들어 주었다.
여기서 명심해야 할 점은, express.js와 같이, /search 같이 정적인 경로는 :/:id 와 같은 동적인 경로보다 먼저 정의해야 한다.
만약, /search 보다 /:id가 더 위에 있는 경우에는 /search 경로가 들어왔을 때도 /:id로 처리할 것 이다.
이제 Query로 받아오는 Query argument를 작성 해 보자.
@Get('/search')
search(@Query('year') searchingYear:string) {
return `We are searching for a movie made after: ${searchingYear}`
}
Param을 적용했을 때와 똑같이 const searchingYear = req.query.year 와 똑같다.
Postman으로 가서 한번 데이터를 보내보자.
return 값을 잘 반환 하는 것을 확인 할 수 있다.
이렇게 nest.js로 controller를 통해 get, post, patch, delete 요청을 날리는 API를 만들어 보았다.
express를 통해 만들때와 비교적 유사한 점이 많기 때문에 TypeScript만 숙지가 잘 되어 있다면 습득하는 데는 문제가 없어보인다.
참조 : 노마드코더
'백엔드 > Nest.js' 카테고리의 다른 글
Nest.js에서 모듈과 의존성 주입 이해하기 (0) | 2024.08.25 |
---|---|
Nest.js에서 DTO를 통해 유효성 검사 처리하기 (0) | 2024.08.23 |
Nest.js에서 Controller와 Service 다루기 (0) | 2024.08.22 |
Nest.js 시작하기 (0) | 2024.07.21 |
Nest.js 설치하기 (0) | 2024.07.15 |