이번에 사용하게될 REST API 에 관해서 간단하게 설명을 적어놓고 본격적으로 시작하겠습니다.
1) GET /posts
2) GET /posts/:id
3) POST /posts
4) PUT /posts/:id
5) PATCH /posts/:id
6) DELETE /posts/:id
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;
}
@Controller('posts')
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@Get()
getPosts(){
return posts;
}
}
실제로도 데이터가 잘 들어오는 것을 확인할 수 있습니다.
@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()
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 을 사용하지 않기때문에 우선 기존 리스트에 새롭게 작성된 내용을 추가하는 로직입니다.
파라미터값으로 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 함수를 사용해서 변경하는 모습입니다.
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}번 게시물이 삭제되었습니다`
}
}
}