본문 바로가기

카테고리 없음

[NodeJS] Express 프로젝트 아키텍쳐 (project architecture) 설계방법

항상 프로젝트를 어떻게 구성하는지에 대한 고민과 가능한 한 체계적으로 만들려고 노력한다. 그 이유는 조금 더 알아보기 쉽고 이해하기 쉬운 코드를 만들기 위함이다. 인터넷에서 정리한 express 프로젝트 설계의 기본 틀을 살펴보자.

 

설계의 대략적인 모양은 이러하다.

│   app.js          # 시작점
└───routes          # 라우터
└───config          # db 연결과 같은 환경변수와 구성요소
└───controllers     # APIs
└───models          # Database 모델
└───middlewares     # 모든 미들웨어
└───utils           # 공통 기능 함수들

 

하나씩 살펴보자.


app.js (필수)

  • Express 어플리케이션의 시작점이다.
  • 가능한 최소한으로 구현하는게 좋다. 
  • express settings와 DB연결 코드, global project 가 포함된다.

코드 예시

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

 


routes (필수)

express router를 사용하여 생성한 모든 경로들과 controller 파일에서 export한 경로들이 포함된다.

파일 네이밍 : index.routes.js

  

폴더

 

코드 예시

const express = require('express');
const checkAuth = require('../middleware/checkAuth.middleware');
const userControllers = require('../controllers/users.controllers');
const router = express.Router(); 

router.post('/signup',userControllers.userRegister);
router.post('/login',userControllers.userLogin);
router.get('/me', checkAuth, userControllers.getMe); 

module.exports = router

 


config (선택)

제 3자의 API들과 서비스가 포함된다(예 passport, S3..)

네이밍 : index.js

 


 

controllers (필수)

모든 API 함수를 포함한다. 

routes의 내부의 기능들을 정의한다. 

네이밍 : index.conroller.js

 

폴더

코드 예시

const bcrypt = require('bcrypt');
require('dotenv').config()
const jwt = require('jsonwebtoken');
const User = require('../models/user');

const getMe = async (req, res) => {  
    const userId = req.user.userId  
    const user = await User.findById(userId)  
    if(user){    
           res.status(200).json({      
                           message:"Found",      
                           user,    
                           })  
            }  
            else{    
                 res.status(400).json({       
                                message:"Bad request"    
                               })  
}}

module.exports = {
    getMe,
}

 


models (필수)

데이터베이스와 관련된 함수들이 포함된다. 

request나 response가 있으면 안되고 오류를던지면 안된다.

이렇게 하면 생성된 스키마와 생서된 에러가 분리되고 일반 api와도 분리할 수 있다.

 

폴더

 

코드 예시

 

const mongoose = require(“mongoose”);

const userSchema = new mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  name: String,
  email: {
    type: String,
    lowercase: true,
    match: /[a-z0–9!#$%&’*+/=?^_`{|}~-]+(?:\.[a-z0–9!#$%&’*+/=?^_`{
    		|}~-]+)*@(?:[a-z0–9](?:[a-z0–9-]*[a-z0–9])?\.)+[a-z0–9](?:[a-z0–  9-]*[a-z0–9])?/,
  },
  password: String, 
  phone_number: Number,
});

module.exports = mongoose.model(“User”, userSchema);

 


utils (선택)

공통되어 중복되는 함수들로 구성된다.

네이밍 : index,js

 

 

 

Reference

https://medium.com/codechef-vit/a-better-project-structure-with-express-and-node-js-c23abc2d736f

https://dev.to/nermineslimane/how-to-structure-your-express-and-nodejs-project-3bl