[MOONDEUK 6일차 -3] 포스트 CRUD
💡 서론
일단 대략적인 포스트를 쓸 준비를 마쳤다!
참 신기한게, 맨처음에는 "기존 것과 다르게, 더 좋게" 만드려 노력했는데,
정말 돌고 돌다 공식문서들을 확인해보면, 모르는 것들을 알아가는 기쁨과,
동시에 기존 것과 겹치는 것들은 다르게 바꾸면서 만들어야 할지에 대한 고민도 든다.
아무래도 '포트폴리오'의 목적성이 있는 프로젝트다 보니, 그럴 수 있다.
(예를 들자면 mongoose의 findByIdAndUpdate라는 것을 기존에 배울 때 쓰다보니,
난 좀 다르게 find로 구현하고 싶어지는 반항심 등... 근데 코드가 길어지잖아)
여튼, 중요한 건 어차피 면접에서 증명하면 되고, 나는 내가 공부한 만큼 구현해왔으니. 당당하게 그냥 개발이나 하자 이거야~
💡 본론
일단 CRUD에 맞게 하나씩 접근한다.
route/post/write
const post = express.Router();
/* create - write */
post.post('/write', postValidationCheck, writeController);
이제는 이정도의 난이도는 괜찮다.
여기서 고민이었던 것은, [String]과 같은 배열의 형태에서 어떻게 유효성을 검사할 지였는데,
express-validator 공식 문서에서는 친절하게 custom
이라는 사용자 지정 방식이 있었다.
map
으로 먼저 다 판별후, 조건을 어긋나는 게 있는지 필터링하는 식으로 했다.
import { check, validationResult } from 'express-validator';
import Post from '../../models/post.js';
export const postValidationCheck = async (req, res, next) => {
await check('title')
.exists()
.withMessage("제목을 입력해주세요.")
.run(req);
await check('body')
.exists()
.withMessage("내용을 입력해주세요.")
.run(req);
await check('tags')
.custom(tag => {
return (tag.map(t => typeof(t) !== 'string')).includes(true) ? false : true;
})
.withMessage("태그는 문자로 이루어져야 합니다.")
.bail()
.custom(tag => {
if ((tag.map(t => t.trim().length === 0)).includes(true)) {
return false
}
return true;
})
.withMessage("최소 1자 이상의 문자 태그를 입력해주세요.")
.run(req)
const result = validationResult(req);
if (!result.isEmpty()) return res.status(400).json({ errors: result.array() });
return next();
}
const writeController = async (req, res) => {
const { title, body, tags } = req.body;
// const { author } = req.user;
const post = new Post({
title,
body,
tags,
// author,
});
try {
await post.save();
res.send(post);
} catch(e) {
res.status(500).send(e);
}
}
export default writeController;
route/post/list
/* read (all) - list */
post.get('/list', listController);
전체를 조회하는 컨트롤러. 그냥 전체 조회하면 뚝딱이다.
주의는 exec
. 쿼리를 조회할 때 쓰는데, 안 쓸시 오류가 발생하니 참고하자.
import Post from '../../models/post.js';
const listController = async (req, res) => {
try {
const posts = await Post.find().exec();
res.send(posts);
} catch(e) {
res.status(500).send(e);
}
};
export default listController;
routesMiddleware/checkValidId
여기서부터는 특정 아이디를 조회한다.
따라서 먼저 ObjectId
가 유효한 것인지부터 검사해야 한다.
따라서, routes 하위 디렉토리 쪽에서 적용할 middleware
를 하나 추가하자.
import mongoose from 'mongoose';
// check invalid ObjectId type.
const checkValidId = (req, res, next) => {
const { id } = req.params;
const { ObjectId } = mongoose.Types;
if (!ObjectId.isValid(id)) {
return res.status(400).send('NOT INVALID REQUEST (id)');
} else {
return next();
}
}
export default checkValidId;
route/post/read
/* read (id) - read */
post.get('/:id',checkValidId, readController);
이것도 위의 것에서 id만 추가한 느낌.
다만, 여기서는 callback
함수가 개인적으로 더 깔끔해보여서 썼다.
(여기서 이렇게 에러가 처리됐다!는 게 좀 더 직관적이라 판단)
import Post from '../../models/post.js';
const readController = async (req, res) => {
const { id } = req.params;
try {
await Post.findById(id).exec((err, result) => {
// not exists post.
if (err) return res.status(404).send('NOT FOUND POST DATA');
return res.send(result);
});
} catch(e) {
res.status(500).send(e);
}
}
export default readController;
route/post/update
/* update (PATCH /:id) - update */
post.patch('/update/:id', checkValidId, updateController);
findByIdAndUpdate
를 통해 처리했다.
find
로 하려 했는데 코드가 비교적 길어지는 느낌이 싫어서
역시 구관이 명관이다, 싶어서 사용했다.
그래도 꽤나 이득도 많았다. 더 나은 소스를 찾기 위해 mongoose 공식문서 역시 많이 볼 수 있었던 좋은 기회였다 :) 정말 유용한 메서드가 많다!
import Post from '../../models/post.js';
const updateController = async (req, res) => {
const { id } = req.params;
try {
console.log(req.body);
await Post.findByIdAndUpdate(id, req.body, { new: true }, (err, result) => {
if (err) res.status(404).send('NOT FOUND');
return res.send(result);
}).exec();
} catch(e) {
res.status(500).send(e);
}
}
export default updateController;
route/post/delete/:id
/* delete (DELETE /:id) - delete */
post.delete('/delete/:id', checkValidId, deleteController);
그냥 지워버린다. 여기서 어차피 보낼 건 없으니 204상태를 띄운다.
import Post from '../../models/post.js';
const deleteController = async (req, res) => {
const { id } = req.params;
await Post.findByIdAndDelete(id, (err, result) => {
if (err) return res.status(404).send('NOT FOUND');
return res.status(204).send();
})
}
export default deleteController;
💡 후기
이제 초간단 CRUD는 끝냈다.
한 번 컴포넌트 디자인을 나중에 하고, 먼저 기능 구현에 초점을 맞춰보자!
내일 목표는 라우트 + 상태관리를 서버에 정상적으로 연동시키는 것.
처음 배우는 express
에 쩔쩔매던 게 엊그제인데
일주일 만에 꽤나 많은 것을 해냈다. awesome⭐👏
Author And Source
이 문제에 관하여([MOONDEUK 6일차 -3] 포스트 CRUD), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jengyoung/MOONDEUK-6일차-3-포스트-CRUD저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)