안녕하세요 오늘은 Nodejs CRUD API 를 만들어 볼 것 입니다.
일단 스키마먼저 보여드리겠습니다. 제일 기본적인 todolist의 CRUD를 구현할 것 입니다.
export class TodoModel {
date: Date;
list: [];
constructor(id: string = "") {
this.date = new Date();
this.list = [];
}
}
전체코드입니다.
import express, { NextFunction } from "express";
import * as _ from "lodash";
import uniqid from 'uniqid';
// 공통 모듈
import Common, {
CommunicationCode,
CommunicationResult,
LogType
} from "../../common/common";
// MongoDB 모듈
import { TodoModel } from "../../database/models/todo"
import mongoDB from "../../database/mongodb";
// 서비스 모듈
// import { APIHelper } from "../helper";
import moment from 'moment';
/**
* @class
* @name TodoAPI
* @description Todo 관련 API
*/
export default class TodoAPI {
private readonly db: mongoDB;
private readonly TODO_DB_ID = "todo";
constructor() {
this.db = mongoDB.root();
}
/**
* @function throw
* @description #1 /api/auth API에서 발생가능한 예외를 처리하는 메서드
* @description #2 API_BASE에 상속
*/
public throw = (
err: Error,
req: express.Request,
res: express.Response,
next: NextFunction
) => {
Common.log(LogType.sev_error, `exception Error : ${err}`);
};
public todoAdd = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
let query: any = req.body.query;
if(query.date == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "date 파라미터를 검출하지 못했습니다.";
throw result;
}
const date: Date = new Date(query.date);
if(isNaN(date.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "date 파라미터가 유효하지 않습니다.";
throw result;
}
let list: any = {};
list["uid"] = uniqid();
console.log("uid : ", list["uid"]);
list["checked"] = (query.checked == undefined) ? false : query.checked;
list["label"] = (query.label == undefined) ? "" : query.label;
list["start"] = (query.start == undefined) ? new Date() :new Date( query.start ) ;
list["end"] = (query.end == undefined) ? new Date() :new Date( query.end );
let insertQuery: any = {};
insertQuery["id"] = uniqid();
insertQuery["date"] = date;
insertQuery["list"] = [];
insertQuery["list"].push(list);
// todo update
await this.db.insertOne(this.TODO_DB_ID, insertQuery);
res.send({ _COM: result });
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/add], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/add], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
};
public todolist = async (req: express.Request, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
const param_date: any = req.query.date;
let query: any = {};
if(param_date != null) {
const start: Date = new Date(param_date + " 00:00:00");
const end: Date = new Date(param_date + " 23:59:59");
query["date"] = {
$gte: start,
$lte: end
};
}
else {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
console.log("query : ", query);
// SQL의 Select로 본다.
// find : query로 검색된 결과를 보여준다. (return array)
const todo: TodoModel = await this.db.findOne(this.TODO_DB_ID, query);
if(todo == undefined) {
result.set(CommunicationCode.DB_FAIL_NO_DATA);
result.msg = "데이터가 없음.";
throw result;
}
let searchQuery: any = {};
searchQuery["date"] = {
$gte: ( req.query.start != undefined) ? moment(req.query.start).toDate() : moment("1970-01-01").toDate(),
$lte: (req.query.end != undefined) ? moment(req.query.end).toDate() : moment("2999-12-31").toDate()
};
res.send({ _COM: result, data: {
date: todo.date,
todo: todo,
}});
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/todolist], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/todolist], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
}
public todolistAll = async (req: express.Request, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
console.log("Date:",new Date());
let query: any = {};
// SQL의 Select로 본다.
// find : query로 검색된 결과를 보여준다. (return array)
const todo: TodoModel = await this.db.find(this.TODO_DB_ID, query);
res.send({ _COM: result, data: todo});
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/todolist], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/todolist], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
}
/**
* @function delete
* @access DELETE
* @description # todo 삭제.
*/
public todoDel = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
let query: any = {};
// let todo: TodoModel = new TodoModel();
// todo 삭제
await this.db.delete(this.TODO_DB_ID, query);
res.send({ _COM: result });
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/delete], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/delete], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
};
public todoUpdate = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
const id = req.body.query.id;
if(id == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const list = req.body.query.list;
if(list == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const uid = list.uid;
if(uid == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const start: Date = new Date(list.start);
if(isNaN(start.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "start 파라미터가 유효하지 않습니다.";
throw result;
}
const end: Date = new Date(list.end);
if(isNaN(end.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "end 파라미터가 유효하지 않습니다.";
throw result;
}
let query: any = {
id: id,
list: {
$elemMatch: {
uid: uid
}
}
};
const data = await this.db.findOne(this.TODO_DB_ID, query);
if(data == undefined) {
result.set(CommunicationCode.DB_FAIL_NO_DATA);
result.msg = "검출된 데이터가 없습니다.";
throw result;
}
console.log("data.list : ", data.list);
let update: any = {
$set: {
"list.$.label": list.label == undefined ? data.list[0].label : list.label,
"list.$.checked": list.checked == undefined ? data.list[0].checked : list.checked,
"list.$.start": list.start == undefined ? data.list[0].start : new Date(list.start),
"list.$.end": list.end == undefined ? data.list[0].end : new Date(list.end),
}
};
//todo update
await this.db.update(this.TODO_DB_ID, query, update);
res.send({ _COM: result });
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/update], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/update], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
};
}
이제 하나하나 분석해보겠습니다.
제일 첫번째로 Add 먼저 보겠습니다.
public todoAdd = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
let query: any = req.body.query;
if(query.date == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "date 파라미터를 검출하지 못했습니다.";
throw result;
}
// DATE 값 예외처리 (검출)
//CommunicationCode은 예외처리를 위한 컴포넌트
const date: Date = new Date(query.date);
if(isNaN(date.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "date 파라미터가 유효하지 않습니다.";
throw result;
}
//DATE 예외 처리 (유효)
let list: any = {};
list["uid"] = uniqid();
console.log("uid : ", list["uid"]);
list["checked"] = (query.checked == undefined) ? false : query.checked;
list["label"] = (query.label == undefined) ? "" : query.label;
list["start"] = (query.start == undefined) ? new Date() :new Date( query.start ) ;
list["end"] = (query.end == undefined) ? new Date() :new Date( query.end );
//uid 값은 중복 방지, uid로 검색을 하기위해 uniqid라는 라이브러리를 사용했습니다.
// https://www.npmjs.com/package/uniqid
let insertQuery: any = {};
insertQuery["id"] = uniqid();
insertQuery["date"] = date;
insertQuery["list"] = [];
insertQuery["list"].push(list);
//list에 push를 해주는 부분입니다.
await this.db.insertOne(this.TODO_DB_ID, insertQuery);
res.send({ _COM: result });
// insertOne이라는 함수를 만들어서 인자값을 넣어줍니다 insertOne은 아래에서 설명하겠습니다.
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/add], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/add], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
// 예외 처리
};
insertOne이라는 함수를 보여드리겠습니다.
mongoose 라이브러리를 사용하여 실질적으로 mongoDB에 값을 저장하는 코드입니다.
public insertOne = (sID: string, query: any, options?: any, index?: any): Promise<any> => {
// Common.log(LogType.prompt, `${sID}: query: ${query}, Insert DB Data`);
return new Promise((resolve: any, reject: any) => {
try {
const collection: mongoose.Collection = this.mongooseDB.collection(sID);
collection.insertOne(query, options, (error: MongoError, result: InsertOneWriteOpResult) => {
if (error) { reject(error); }
else {
resolve(result);
}
});
} catch (e) { reject(e); }
});
}
Add의 결과값입니다.
그럼 이제 SelectOne 을 보겠습니다.
Data 하나만 검색하는 함수
public todolist = async (req: express.Request, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
const param_date: any = req.query.date;
let query: any = {};
if(param_date != null) {
const start: Date = new Date(param_date + " 00:00:00");
const end: Date = new Date(param_date + " 23:59:59");
query["date"] = {
$gte: start,
$lte: end
};
}
else {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
console.log("query : ", query);
// SQL의 Select로 본다.
// find : query로 검색된 결과를 보여준다. (return array)
const todo: TodoModel = await this.db.findOne(this.TODO_DB_ID, query);
if(todo == undefined) {
result.set(CommunicationCode.DB_FAIL_NO_DATA);
result.msg = "데이터가 없음.";
throw result;
}
let searchQuery: any = {};
searchQuery["date"] = {
$gte: ( req.query.start != undefined) ? moment(req.query.start).toDate() : moment("1970-01-01").toDate(),
$lte: (req.query.end != undefined) ? moment(req.query.end).toDate() : moment("2999-12-31").toDate()
};
res.send({ _COM: result, data: {
date: todo.date,
todo: todo,
}});
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/todolist], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/todolist], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
}
findOne 이라는 함수로 한개의 데이터 값을 찾습니다.
/**
* @function findOne
* @returns Promise<any>
* @description DB에서 한 개의 데이터 값을 찾는다.
* @tutorial OnlyKeyValue 주로 1개가 확실한 데이터를 찾는데 쓴다.
* @param sID schema ID
* @param query 찾을 검색문
*/
public findOne = (sID: string, query: any, options: FindOneOptions = {}): Promise<any> => {
return new Promise((resolve: any, reject: any) => {
try {
let collection: mongoose.Collection = this.mongooseDB.collection(sID);
collection.findOne(query, options).then(value => { resolve(value); }).catch(e => { reject(e); });
} catch (e) {
reject(e);
}
});
}
Data 전체를 검색하는 함수
public todolistAll = async (req: express.Request, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
console.log("Date:",new Date());
let query: any = {};
// SQL의 Select로 본다.
// find : query로 검색된 결과를 보여준다. (return array)
const todo: TodoModel = await this.db.find(this.TODO_DB_ID, query);
res.send({ _COM: result, data: todo});
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/todolist], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/todolist], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
}
find함수
/**
* @function find
* @returns Promise<any>
* @description 찾는다. DB에서, 목적지를
* @param sID schema ID
* @param qKey Find Key, undefined의 경우 해당 collection의 전체 DOC을 검색한다.
* @param qValue qKey에서 검색한 멤버의 찾을 조건. 정규식도 가능하다.
*/
public find = (sID: string, query: any, options: any = {}, _sort: any = {}, _skip: number = -1, _limit: number = -1): Promise<any> => {
return new Promise(async(resolve: any, reject: any) => {
try {
let collection: mongoose.Collection = this.mongooseDB.collection(sID, { _prettyShell: true });
let cursor: Cursor<any> = collection.find(query, options);
if(cursor == undefined) {
resolve([]);
}
else {
if(_skip != -1 && _limit != -1) {
cursor = collection.find(query, options).sort(_sort).skip(_skip).limit(_limit);
}
else if(_skip != -1) {
cursor = collection.find(query, options).sort(_sort).skip(_skip);
}
else if(_limit != -1) {
cursor = collection.find(query, options).sort(_sort).limit(_limit);
}
else {
cursor = collection.find(query, options).sort(_sort);
}
}
let docs: Array<any> = await cursor.toArray();
resolve(docs);
// resolve(cursor);
// cursor.forEach((doc: any) => { docs.push(doc); })
// .then(value => { resolve(docs); })
// .catch(e => { reject(e); });
} catch (e) {
reject(e);
}
});
}
Delete 함수
/**
* @function delete
* @access DELETE
* @description # todo 삭제.
*/
public todoDel = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
let query: any = {};
// let todo: TodoModel = new TodoModel();
// todo 삭제
await this.db.delete(this.TODO_DB_ID, query);
res.send({ _COM: result });
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/delete], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/delete], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
};
delete 함수
/**
* @function delete
* @returns Promise<any>
* @description: 해당 스키마의 데이터를 수정한다.
* @param sID : schema ID
* @param query : 삭제할 조건
* @param many(default false) : true로 바꿀 경우 관계된 모든 데이터를 삭제한다.
* @param all(default false) : ※주의! true로 바꿀 경우 어떤 조건이든지 해당 스키마의 모든 데이터를 삭제한다.
*/
public delete = (sID: string, query: any, options: any = {}, many: boolean = false): Promise<any> => {
return new Promise<any>((resolve: any, reject: any) => {
let collection: mongoose.Collection = this.mongooseDB.collection(sID);
if (query == undefined) {
reject("Query Empty");
} else if (!many) {
collection.deleteOne(query, options, (error: MongoError, result: DeleteWriteOpResultObject) => {
if (error) { reject(error); }
else { resolve(result); }
});
} else {
collection.deleteMany(query, options, (error: MongoError, result: DeleteWriteOpResultObject) => {
if (error) { reject(error); }
else { resolve(result); }
});
}
});
}
Update 함수
public todoUpdate = async (req: any, res: express.Response) => {
let result: CommunicationResult = new CommunicationResult();
try {
const id = req.body.query.id;
if(id == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const list = req.body.query.list;
if(list == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const uid = list.uid;
if(uid == undefined) {
result.set(CommunicationCode.FAIL_EMPTY_PARAMETER);
result.msg = "파라미터를 검출하지 못했습니다.";
throw result;
}
const start: Date = new Date(list.start);
if(isNaN(start.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "start 파라미터가 유효하지 않습니다.";
throw result;
}
const end: Date = new Date(list.end);
if(isNaN(end.getTime())) {
result.set(CommunicationCode.FAIL_INVALID_DATA);
result.msg = "end 파라미터가 유효하지 않습니다.";
throw result;
}
let query: any = {
id: id,
list: {
$elemMatch: {
uid: uid
}
}
};
const data = await this.db.findOne(this.TODO_DB_ID, query);
if(data == undefined) {
result.set(CommunicationCode.DB_FAIL_NO_DATA);
result.msg = "검출된 데이터가 없습니다.";
throw result;
}
console.log("data.list : ", data.list);
let update: any = {
$set: {
"list.$.label": list.label == undefined ? data.list[0].label : list.label,
"list.$.checked": list.checked == undefined ? data.list[0].checked : list.checked,
"list.$.start": list.start == undefined ? data.list[0].start : new Date(list.start),
"list.$.end": list.end == undefined ? data.list[0].end : new Date(list.end),
}
};
//todo update
await this.db.update(this.TODO_DB_ID, query, update);
res.send({ _COM: result });
} catch (e) {
if (e instanceof CommunicationResult) {
result = e;
Common.log(LogType.error, `[/api/todo/update], try ~ catch : ${e.msg}`);
} else {
result.set(CommunicationCode.FAIL_UNKNOWN);
result.msg = e.message;
Common.log(LogType.sev_error, `[/api/todo/update], try ~ catch : ${e}`);
}
res.send({ _COM: result });
}
};
update함수
/**
* @function update
* @returns Promise<any>
* @description: 해당 스키마의 데이터를 수정한다.
* @param sID schema ID
* @param query : 수정할 조건
* @param update : 수정할 조건
* @param options : 수정할 조건
* @param isMany : 수정을 여러개 할 지 여부
*/
public update = (sID: string, query: any, update: any, options: any = {}, isMany: boolean = false): Promise<any> => {
return new Promise<any>((resolve: any, reject: any) => {
try {
if (!isMany) {
let collection: mongoose.Collection = this.mongooseDB.collection(sID);
collection.updateOne(query, update, options, (error: any, res: any) => {
if (error) { reject(error); }
else { resolve(res); }
});
} else {
let collection: mongoose.Collection = this.mongooseDB.collection(sID);
collection.updateMany(query, update, options, (error: any, res: any) => {
if (error) { reject(error); }
else { resolve(res); }
});
}
} catch (e) {
resolve(e);
}
});
}
index.ts
import express from "express";
import { Router } from "express-serve-static-core";
import TodoAPI from "./todo";
const todo = new TodoAPI();
const router: Router = express.Router();
router.use(todo.throw);
router.post("/todoAdd",todo.todoAdd);
router.get("/todolist", todo.todolist);
router.get("/todolistAll", todo.todolistAll);
router.delete("/todoDel",todo.todoDel);
router.post("/todoUpdate",todo.todoUpdate);
export = router;
감사합니다:)
'Node.js' 카테고리의 다른 글
보안 취약점을 잡자 ~! (0) | 2019.09.04 |
---|---|
Express ? (0) | 2019.09.03 |
REST – PUT vs POST (0) | 2019.08.28 |
간단한 Todolist Select API를 만들어보았다! (0) | 2019.08.26 |
Node.js로 hello world 출력해보기 (0) | 2019.08.07 |