개발일기장

expressJS 를 class형식으로 실행 본문

node.js

expressJS 를 class형식으로 실행

게슬 2022. 7. 28. 21:57
728x90

Spring boot같은 프레임워크로 웹서버를 만드는 경우에는 이미 틀은 다 만들어져 있어서 기능을 집어넣는다? 라는 표현을 쓰는게 맞는것 같음.

 

Node.js에서는 웹서버 개발을 위한 프레임워크가 많은데 기본적으로 다들 express.js로 시작하는것 같다.

Spring boot와는 다르게 express를 사용하면 레고를 하나씩 쌓고 이어붙이는것 처럼 원하는 기능을 하나씩 더하고, 미들웨어를 추가하는 방식으로 개발을 했던것 같다.

그런데 이거는 어디를 돌아다녀봐도 정해진 틀이 없고 개개인의 스타일이 다 달라서 좀 답답했음.

 

물론 NestJS같은 프레임워크가 Spring boot처럼 깔끔하고 규격이 있다고 느낄수 있었고, 이거 사용하는 회사들도 점점 늘어나는것 같은 느낌?? (사실은 잘 모름, 뭔가 후원하는게 여러개가 있고 당근?도 이거 썼었다고 들었..)

 


1. 일반적인 코드

const express = require('express');
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use('/api/record', require('./Record/record.controller'));
app.use('/api/user',require('./User/user.controller'));

app.use((req, res, next) => {
    //no url
    res.status(404).json({
        success: false,
        message: 'No URL',
    });
});

app.use((err, req, res, next) => {
    res.status(500).json({
        success: false,
        message: err.message,
    });
});

module.exports = app;

일반적으로 찾을 수 있는 express로 작성한 코드는 대부분의 예시들은 이런 스크립트 느낌으로 작성되어서 main함수에서 listen을 호출했던것 같다.


2. Class로 변환

Spring boot처럼 필요한 component를 주입하는데 자동으로는 아니고 수동으로 직접 하나씩 넣었음.

Class : controller, service, repository,ExpressApp,

Function : main으로 나누었다.

 

Controller부분에서 Router를 어떻게 작성하느냐에 따라서 사람들마다 스타일이 다른것 같음.

 

  • repository : 일단 Map방식으로 작성했고 이것을 주입받으면 된다.
class HelloRepository {
    private _database: Map<Number, String>; //나중에 DB pool이나 connection을 받아오면 될것.

    constructor(database: Map<Number, String>) {
        this._database = database;
    }
    
	//...생략
}

export default HelloRepository;
  • service : repository를 주입받는다.
import HelloRepository from "./hello.repository";

class HelloService {
    private _helloRepository: HelloRepository;
    constructor(repository: any) {
        this._helloRepository = repository;
    }

	//...생략
}

export default HelloService;
  • controller : 이부분이 가장 난해했다.

Router설정에 필요한 url path와 비즈니스로직 service를 주입받는다.

constructor에서 본인의Router를 하나 생성하고, addListener 메서드를 통해서 각각의 CRUD작업을 등록했다.

그리고 밖의 App에서 사용할 수 있도록 Router를 반환한다.

import { Router } from "express";
import HelloService from "./hello.service";

class HelloController {
    private _helloService: HelloService;
    private _router: Router;
    private _path : any;
    constructor(helloService: HelloService, path : String) {
        this._helloService = helloService;
        this._router = Router();
        this._path = path;
        this.addListener();
    }

    initRouter(): Router {
        return this._router;
    }
    
    
    addListener(): void {
        const router = Router();
        router
            .get('/:id', (req, res, next) => {
				//... 생략
                res.json(result);
            }).post('/', (req, res, next) => {
				//... 생략
                res.json(result);
            }).put('/:id', (req, res, next) => {
				//... 생략
                res.json(result);

            }).delete('/:id', (req, res, next) => {
				//... 생략
                res.json(result);
            })
            
        this._router.use(this._path, router);
    }
}

export default HelloController;
  • ExpressApp : Controller들을 등록하고, 설정을 하는 곳

Express.Application과 Controller들을 주입받는다.

서버를 시작하고, 필요한 옵션들(나중엔 세션이나 그런것)을 등록하고, Controller에서 받은 Router들을 등록한다.

import express,{ Application, Request, Response, NextFunction, Router } from 'express';

class ExpressApp {
    private _app: Application;
    private _controllers: Array<any>;

    constructor(app: Application, controllers: Array<any>) {
        this._app = app;
        this._controllers = controllers;
        this.initOptions();
        this.registRouter();
    }
    initOptions() : void{
        this._app.use(express.json());
        this._app.use(express.urlencoded());
    }

    registRouter(): void {
        this._controllers.forEach((controller) => {
            this._app.use(controller.initRouter());
        });
    }

    startServer(port: Number): void {
        this._app.listen(port, () => {
            console.log(` #####  Server listening on port: ${port}  #####`);
        });
    }

}

export { ExpressApp }
  • Main function : Component에 필요한 것들을 주입해주는 곳.
import express, { Application } from "express";
import { ExpressApp } from './app';
import HelloController from "./hello.controller";
import HelloRepository from "./hello.repository";
import HelloService from "./hello.service";

function main(): void {
    const app: Application = express();
    const routerList = new Array();

    //이게 뭐야 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
    routerList.push(new HelloController(new HelloService(new HelloRepository(new Map<Number, String>)), "/user"));
    
    const expressApp: ExpressApp = new ExpressApp(app, routerList);
    expressApp.startServer(8080);
}

main();

그런대 각각의 필요한 부분에 수동으로 주입하는 코드가 너무 복잡하다.

routerList.push(new HelloController(new HelloService(new HelloRepository(new Map<Number, String>)), "/user"));

Spring에서는 Component를 자동으로 등록하고 주입해주지만 Express에는 그런기능이 없어서 Class를 사용하고, 데이터 주입을 받는다면 이렇게 복잡해진다.

그리고 DB와 Redis같은 설정까지 더 하면 엄청 복잡해질것..

 

그래서 NodeJS에서는 이런 문제를 해결해주는 inversify라는 library가 있는데

https://www.npmjs.com/package/inversify

 

inversify

A powerful and lightweight inversion of control container for JavaScript and Node.js apps powered by TypeScript.. Latest version: 6.0.1, last published: 9 months ago. Start using inversify in your project by running `npm i inversify`. There are 2328 other

www.npmjs.com

이것을 사용해서 조금의 설정만 해준다면 저런 이상한 코드를 간단히 만들고, 유지보수에 편리하게 해줄것이다.

그건 다음에..


https://tlqckd0.tistory.com/57

 

ExpressJS에 inversify적용하기

https://tlqckd0.tistory.com/56 express.js 를 class형식으로 실행 Spring boot같은 프레임워크로 웹서버를 만드는 경우에는 이미 틀은 다 만들어져 있어서 기능을 집어넣는다? 라는 표현을 쓰는게 맞는것 같음.

tlqckd0.tistory.com

했음

728x90
Comments