항상 프로젝트를 어떻게 구성하는지에 대한 고민과 가능한 한 체계적으로 만들려고 노력한다. 그 이유는 조금 더 알아보기 쉽고 이해하기 쉬운 코드를 만들기 위함이다. 인터넷에서 정리한 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