article 에 대해서 CRUD API 를 추가해보자.
이전 글에서 적어놓긴 했지만, article 에 대한 schema 는 아래와 같다.
// Article Schema
const articleSchema = new Schema({
title: { type: String, required: true },
contents: { type: Schema.Types.String, required: true },
created: { type: Date },
parent: { type: Schema.Types.ObjectId, required: true }
});
// Article Model
const ArticleModel = mongoose.model('article', articleSchema);
일단 아래 3가지 정도의 기능을 제공하면 될것 같다.
사실 옵션을 좀 더 디테일하게 설정해야 하는게 맞다.
정렬이라던지... created 라던지, 키워드 검색이라던지...
이 부분은 추후에 하는 걸로...
일단 _id 와 parent 에 대해서만 query 하자.
이제 실제 구현을 해보자.
다른 부분은 그냥 하면 되는데, target menu 와 그 자식 menu 들을 가져와야 하는 부분은 models/Menu.js
에 별도의 함수로 제공하는 것이 좋겠다.
models/Menu.js
내부에서도 이미 코드로서 존재하기도 하고, 각 data 에 관한 로직들은 각각의 js 에 존재하는 것이 코드 관리상으로도 그렇고 의미적으로도 더 맞다고 생각한다.
뭐 하는김에 models/Menu.js
코드 정리도 하고......
models/Menu.js
// target 메뉴들 + 자신의 모든 자식 메뉴들을 array 로 리턴
export const getMenusAndAllChildren = async query => {
let targets = [];
let children = [];
try {
// 타겟의 자식 메뉴들까지 다 지우기
targets = await MenuModel.find(query);
children = [...targets];
for (let i = 0; i < children.length; i++) {
if (children[i].children?.length > 0) {
const newChildren = await MenuModel.find({_id: children[i].children});
children = [...children, ...newChildren]
}
}
children = children.slice(targets.length);
} catch (e) {
console.error(e);
targets = [];
children = [];
}
return { targets, children };
}
이제 저 함수를 사용해서 GET /article 을 완성해보자.
router/article.js
import { Router } from 'express';
import { get } from '../models/Article.js';
// GET /article
router.get("/", async (req, res) => {
console.log('get article......');
const data = await get(req.query);
res.send({data});
});
models/Article.js
// query 는 _id 혹은 parent 만 허용
// parent 가 있을 경우에는 모든 자식 메뉴들도 다 대상임.
// 둘 다 없음 all
export const get = async query => {
let data = null;
try {
let lastQuery = {};
if (query?._id) {
lastQuery._id = query._id;
}
if (query?.parent) {
const { targets, children } = await getMenusAndAllChildren({ _id: query.parent });
lastQuery.parent = [...targets, ...children].map(p => p._id);
}
lastQuery = lastQuery._id || lastQuery.parent ? lastQuery : null;
data = await ArticleModel.find(lastQuery);
} catch (e) {
console.error(e);
}
return data;
};
article 을 생성하는 API 이며, 어드민 화면에서만 사용...
router/article.js
import { create } from '../models/Article.js';
// POST /article
router.post("/", async (req, res) => {
console.log('post article......');
const success = await create(req.body);
res.send({success});
});
models/Article.js
export const create = async data => {
let success = false;
const { parent } = data;
try {
// parent check
const parents = await getMenu({ _id: parent});
if (parents?.length !== 1) {
return false;
}
// set created
data.create = (new Date()).getTime();
const article = new ArticleModel(data);
await article.save();
success = true;
} catch (e) {
console.error(e);
}
return success;
};
article 을 삭제하는 API 이며 여러개의 article 을 삭제할 수 있도록 해봤다. (검증은 안함)
이것도 어드민 화면에서만 사용....
router/article.js
import { remove } from '../models/Article.js';
// DELETE /article
router.delete("/", async (req, res) => {
console.log('delete article......');
const success = await remove(req.body);
res.send({success});
});
models/Article.js
export const remove = async query => {
let success = false;
try {
const _id = query?._id;
if (!_id?.length !== 0) {
return false;
}
const targets = await ArticleModel.find({ _id });
await ArticleModel.deleteMany({_id: targets.map(t => t._id)});
success = true;
} catch (e) {
console.error(e);
}
return success;
};
메뉴 데이터를 수정하는 API 이며 검증 안했다.
이것도 어드민 화면에서만 사용....
router/menu.js
import { patch } from '../models/Article.js';
// PATCH /article
router.patch("/", async (req, res) => {
console.log('patch article......');
const success = await patch(req.body?.query, req.body?.data);
res.send({success});
});
models/Article.js
// 무조건 _id 로
export const patch = async (query, data) => {
let success = false;
try {
const _id = query?._id;
if (!_id?.length !== 0) {
return false;
}
await ArticleModel.findOneAndUpdate({ _id }, { $set: data });
success = true;
} catch (e) {
console.error(e);
}
return success;
};
뭐 DELETE 와 PATCH 를 제외하고는 잘 동작하는 것 확인했다.
모든 api 에 request data - query, body 에 대한 체크 로직을 전반적으로 손봐야 할듯.
나중에......