본문 바로가기
Research/Node.js

Express.js_싱글톤 패턴, 비즈니스 로직 분리

by RIEM 2023. 3. 24.
728x90

싱글톤이란? 객체의 인스턴스가 1개만 생성되기 하는 디자인 패턴이다. 클래스가 있고 를 활용하여 인스턴스 하나만 찍어낸다.

왜 사용하냐?
처음 만든 객체로 주구장창 쓸 수 있기에, 메모리를 아낄 수 있다. 그리고 전역으로 사용할 경우, 다른 클래스의 인스턴스들이 활용할 수도 있어 활용성이 높다.

싱글톤 패턴 적용

Express.js에 싱글톤 패턴을 적용하면 아래와 같다.

// app.ts

import * as express from 'express';
import catsRouter from './cats/cats.route';

class Server {

  // 인스턴스 하나 생성할 때 앱이 하나씩 생성된다
  public app: express.Application;

  constructor() {
    const app: express.Application = express();
    this.app = app;
  }

  // setRoute로 따로 분리. 모듈이 많아질 경우 따로 구분하는 것이 인생 편해짐.
  private setRoute() {
    this.app.use(catsRouter);
  }

  private setMiddleware() {
    //* logging middleware
    this.app.use((req, res, next) => {
      console.log(req.rawHeaders[1]);
      console.log('this is logging middleware');
      next();
    });

    //* json middleware
    this.app.use(express.json());

    this.setRoute();

    //* 404 middleware
    this.app.use((req, res, next) => {
      console.log('this is error middleware');
      res.send({ error: '404 not found error' });
    });
  }

  public listen() {
    this.setMiddleware();
    this.app.listen(8000, () => {
      console.log('server is on...');
    });
  }
}

function init() {
  const server = new Server();
  server.listen();
}

init();

서비스 로직 추가

// cats/cats.router.ts

// app 객채가 구분되는 것을 이어줄 필요가 있음
import { Router } from 'express';
import { readAllcat } from './cats.service';

// router 인스턴스 생성
const router = Router();

// READ 데이터 조회
router.get('/cats', readAllcat);

...

read 라우터에 readAllcat 서비스 주입

// ./cats/cats.service.ts
import { Request, Response } from 'express';

// READ 조회 서비스 생성
export const readAllcat = (req: Request, res: Response) => {
  try {
    const cats = { data: 'data example' };
    // throw new Error('db connect error');

    res.status(200).send({
      success: true,
      data: {
        cats,
      },
    });
  } catch (error) {
    res.send({
      succes: false,
      error: error.message,
    });
  }
};

...

service 레이어에 해당 함수를 추가한 뒤에 export해주면 된다. 이렇게 해줘야 router단에서 사용할 수 있다.

전체 코드

라우터 cats.route.ts

import { Router } from 'express';
import { NextFunction } from 'express-serve-static-core';
import {
  createCat,
  deleteCat,
  readAllcat,
  readCat,
  updateCat,
  updatePartialCat,
} from './cats.service';

const router = Router();

router.get('/cats', readAllcat);
router.get('/cats/:id', readCat);
router.post('/cats', createCat);
router.put('/cats/:id', updateCat);
router.patch('/cats/:id', updatePartialCat);
router.delete('/cats/:id', deleteCat);

export default router;

서비스 cats.service.ts

import { Request, Response } from 'express';
import { Cat, CatType } from './cats.model';

//* READ 고양이 전체 데이터 다 조회 -> GET
export const readAllcat = (req: Request, res: Response) => {
  try {
    const cats = Cat;
    // throw new Error('db connect error');
    res.status(200).send({
      success: true,
      data: {
        cats,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* READ 특정 고양이 데이터 조회 -> GET
export const readCat = (req: Request, res: Response) => {
  try {
    const params = req.params;
    console.log(params);
    const cat = Cat.find((cat) => {
      return cat.id === params.id;
    });
    res.status(200).send({
      success: true,
      data: {
        cat,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* CREATE 새로운 고양이 추가 api -> POST
export const createCat = (req: Request, res: Response) => {
  try {
    const data = req.body;
    Cat.push(data); // create
    res.status(200).send({
      success: true,
      data: { data },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* UPDATE 고양이 데이터 업데이트 -> PUT
export const updateCat = (req: Request, res: Response) => {
  try {
    const params = req.params;
    const body = req.body;
    let result;
    Cat.forEach((cat) => {
      if (cat.id === params.id) {
        cat = body;
        result = cat;
      }
    });
    res.status(200).send({
      success: true,
      data: {
        cat: result,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* UPDATE 고양이 데이터 부분적으로 업데이트 -> PATCH
export const updatePartialCat = (req: Request, res: Response) => {
  try {
    const params = req.params;
    const body = req.body;
    let result;
    Cat.forEach((cat) => {
      if (cat.id === params.id) {
        cat = { ...cat, ...body };
        result = cat;
      }
    });
    res.status(200).send({
      success: true,
      data: {
        cat: result,
      },
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

//* DELETE 고양이 데이터 삭제 -> DELETE
export const deleteCat = (req: Request, res: Response) => {
  try {
    const params = req.params;
    const newCat = Cat.filter((cat) => cat.id !== params.id);
    res.status(200).send({
      success: true,
      data: newCat,
    });
  } catch (error) {
    res.status(400).send({
      success: false,
      error: error.message,
    });
  }
};

레퍼런스

https://www.inflearn.com/course/%ED%83%84%ED%83%84%ED%95%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%EB%84%A4%EC%8A%A4%ED%8A%B8/dashboard
https://github.com/amamov/teaching-nestjs-a-to-z

728x90

'Research > Node.js' 카테고리의 다른 글

35.node.js Buffer?  (0) 2023.09.20
node.js_zip and unzip  (0) 2023.09.20
Express.js_router 분리하는 방법  (0) 2023.03.24
Express.js_CRUD API  (0) 2023.03.24
Express.js_미들웨어 사용 방법  (0) 2023.03.24

댓글