BackEnd Skils

백엔드 입문 (5) - Express 아키텍처 구조

JellyApple 2024. 12. 8. 23:53

1. 마이크로 프레임워크 vs 풀스택 프레임워크

: 익스프레스는 마이크로프레임워크 즉, 미니멀리스트 웹 프레임워크다. 최소 기능을 가지면서 필요한 기능을 플러그인으로 확장하는 프레임워크이다. 장고, 스프링 같은 풀스택 프레임워크들은 디렉터리 구조를 강제하지만 마이크로 프레임워크는 폴더 구조를 강제하지 않는다.

 

2. 3계층 구조 아키텍처
: 서버 개발에서 가장 보편적으로 사용하는 3계층 구조 아키텍처를 적용하고자 한다. MVC 패턴을 적용하기도 좋기 때문이다.

: 컨트롤러, 서비스 , 데이터 액세스 계층을 가짐.

: 컨트롤러 계층에서는 뷰에서 넘어온 요청을 받아 권한 체크, 유효성 검증 등을 한 후 서비스 계층으로 넘김.

: 서비스 계층에서는 비즈니스 로직을 처리한다. 이렇게 비즈니스 로직을 분리하면 각각 다른 컨트롤러에서 같은 서비스를 재사용할 수 있다.

: 서비스에서 DB에 데이터를 저장할 때에는 데이터 액세스 계층과 데이터를 주고 받는데. 이 경우 정의해둔 모델을 넘기는 것이 일반적이다.

 

3. 익스프레스에서 3계층 구조 아키텍처

: 익스프레스에서 컨트롤러 역할은 라우터가 한다.

: 서비스 계층은 비즈니스 로직을 구현하는 부분이기 때문에 각 프로젝트에서 해당 역할을 하는 클래스 또는 함수를 작성해야 한다.

: 데이터 액세스 계층을 따로 작성하는 경우도 있지만 SQL, 몽고디비 등이 있으면 모듈을 갖고 그대로 사용하는 편도 많다.

 

4. 익스프레스 프로젝트의 데이터 흐름

1) 뷰 - 웹 페이지

2) 컨트롤러 - express-router

3) 서비스 - 서비스 함수 혹은 클래스

4) 데이터 액세스 계층 - 몽고디비 같은 모델

5) 모델 - 데이터 모델

 

5. 플로우 

1) 뷰 역할하는 웹 페이지에서 서버로 요청을 보냄

2) 컨트롤러에서 요청에 대한 인증, 유효성 검증 등 하고 문제 없으면 서비스 계층에 있는 함수 호출함

3) 서비스에서는 받은 데이터로 비즈니스 로직 처리하거나, 데이터 액세스로 넘기는 모델 객체를 생성함

4) 데이터 액세스에서는 서비스 계층에서 받은 데이터를 CRUD 등을 수행함.

5) 다시 데이터 처리 결과를 서비스 계층으로 넘김

6) 서비스 계층은 컨트롤러 계층으로 넘김

7) 컨트롤러에서는 실행 결과가 담긴 데이터를 웹 페이지에 응답으로 보냄

 

6. 템플릿 엔진

: 컨트롤러에서 넘기는 데이터를 웹페이지에서 표현할 때 사용할 템플릿 엔진이 필요하다.

: API만 만들면 필요 없으나. 뷰로 웹페이지 혹은 SQL 파일을 만들어 넘기려면 템플릿 엔진을 설정해야 제대로 표현할 수 있다. ex) pug ,EJS , 머스태시 , Nunjucks 등이 있다.

 

7. 익스프레스 예시 코드

const express = require("express");
const handlebars = require("express-handlebars");
const app = express();

app.engine("handlebars", handlebars.engine()); // 템플릿 엔진으로 핸들바 등록
app.set("view engine", "handlebars"); // 웹페이지 로드 시 사용할 템플릿 엔진 설정
app.set("views", __dirname + "/views"); // 뷰 디렉토리를 views로 설정

app.get("/", (req, res) => {
  res.render("home", { title: "홈페이지", message: "안녕하세요!" });
});

app.listen(3000, () => {
  console.log("서버가 시작되었습니다.");
});

 

* handlebars : 파일의 확장자로 사용할 이름 

.* app.set("views" , __dirname + "/views"); : 뷰로 사용할 파일등의 디렉터리를 설정하는 단계 , __dirname을 사용해 절대 경로로 지정한다. 

* __dirname : node를 실행하는 디렉터리 경 

 

* views/layouts/main.handlebars

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>node.js backend practice</title>
  </head>
  <body>
    {{{body}}}
  </body>
</html>

 

=> {{{ body }}}에 다른 핸들바 템플릿의 코드가 그대로 들어가게 된다.

 

8. MongoDB 연결 코드

const express = require("express");
const handlebars = require("express-handlebars");
const app = express();

const mongodbConnection = require("./configs/mongodb-connection");

app.engine("handlebars", handlebars.engine()); // 템플릿 엔진으로 핸들바 등록
app.set("view engine", "handlebars"); // 웹페이지 로드 시 사용할 템플릿 엔진 설정
app.set("views", __dirname + "/views"); // 뷰 디렉토리를 views로 설정

app.get("/", (req, res) => {
  res.render("home", { title: "테스특 게시판", message: "안녕하세요!" });
});

app.get("/write", (req, res) => {
  res.render("write", { title: "테스트 게시판" });
});

app.get("/detail/:id", async (req, res) => {
  res.render("detail", { title: "테스트 게시판" });
});

let collection;
app.listen(3000, async () => {
  console.log("server is running on port : 3000");
  const mongoClient = await mongodbConnection();
  collection = mongoClient.db().collection("post");
  console.log("MongoDB Connected");
});
// mongodb-config.js
const { MongoClient } = require("mongodb");
const url = "mongodb://localhost:5000"; // 실제 본인 계정에 맞게 수정

module.exports = function (callback) {
  return MongoClient.connect(url, callback);
};

 

 

9. nodemon 설정

: 서버를 제작할 때 서버를 재시작하는 경우가 많은데 매번 끄고 키는 과정을 번거로울 수 있는데 nodemon으로 코드 저장 시 서버를 재시작시켜주는 도구이다. vite에 HMR 기능과 유사하다.

: npm i nodemon