[Dev log] 싱글톤 패턴, 서비스패턴 개선

이건우·2023년 4월 15일
0

개선 전 (app.ts)

import * as express from "express";
import catsRouter from "./cats/cats.routes"

// const app = express();
const app: express.Express = express();

// const data: Array<any> = [1,2,3,4];

const port: number = 8000;


// 미들웨어 접근
app.use((req:express.Request,res:express.Response,next:express.NextFunction)=>{
    console.log((req.rawHeaders[1]));
    console.log('this is middleware');
    next();
})

// json 미들웨어
app.use(express.json());

app.use(catsRouter);


// 404 middleware
app.use((req:express.Request,res:express.Response, next:express.NextFunction) => {
  console.log("this is error middleware");
  res.send({ error: "404 not found error" });
});


app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}/`);
});

개선 후

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

class Server {
  public app: express.Application;

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

  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(port, () => {
      console.log('server is on...');
    });
  }
}

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

init();

해설

기존에 내가 짜던 코드 느낌보다 더 확실히 깔끔하고 간결하다. server 클래스 선언을 통해 상태를 관리할수 있다는것.. 생각 조차 못했다. app을 단 한개 고유의 외부접근을 허용하는public 필드로 지정하고 constructor를 통해 해당 클래스의 인스턴스를 생성과 초기화. 그리고 미들웨어들을 외부에서 접근불가능한 priviate로 지정한뒤 하나의 함수를 통한 클래스 실행.. 기존에 따로 따로 동떨어져 있던것들을 하나의 클래스로 묶어버렸다.

말그대로 싱글톤 패턴화 되었다.

개선 전 (비즈니스 로직과 route 분리)

import { Cat, CatType } from "./cats.model";
import { Router } from "express";

const router = Router();

//  READ 고양이 데이터 전체 조회

router.get("/cats", (req, res) => {
  try {
    const cats = Cat;

    // throw new Error("db connect error")

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

// 특정 고양이 데이터 조회
router.get("/cats/:id", (req, res) => {
  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: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

// Creat 새로운 하나의 고양이 api 추가
router.post("/cats", (req, res) => {
  try {
    const data = req.body;
    console.log(data);
    Cat.push(data); // create

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

// Update => Put
router.put('/cats/:id',(req,res)=>{
    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: {
            result,
          },
        });
    } catch (error: any) {
        res.status(400).send({
          succes: false,
          error: error.message,
        });
      }
})
// 부분적인 Update => Patch
router.patch("/cats/:id", (req, res) => {
  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: {
        result,
      },
    });
  } catch (error: any) {
    res.status(400).send({
      succes: false,
      error: error.message,
    });
  }
});

// Delete 삭제 => Delete

router.delete("/cats/:id", (req, res) => {
  try {
    const params = req.params;
    const newCat =
    Cat.filter((cat) => 
        cat.id !== params.id
    );

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

export default router; 

개선 후 (cat.service.ts, cat.route.ts)

cat.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,
    });
  }
};

cat.routes.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;

비즈니스 로직과 라우트를 분리해 둠으로 써 보다 가독성이 좋아졌다.

profile
내가 느낌만알고 한줄도 설명할줄 모른다면 '모르는 것'이다.

0개의 댓글