안녕하세요 오늘은 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

+ Recent posts