Node.js와 Express를 이용해 게시판 만들기 ④ - Controller - 콜백 함수 따로 관리하기

32081 단어 nodejsexpressexpress

들어가며

몇가지 변경사항과 추가된 것이 있어서 정리했다.


1. Post Model 변경

작성자 필드 추가, description -> contents 변경

📁models/📃Post.js

const postSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      required: true,
      trim: true,
    },
    // description에서 contents로 변경
    contents: {
      type: String,
      required: true,
    },
    // 작성자 필드 추가
    writer: {
      type: String,
      required: true,
      trim: true,
    },
  },
  {
    timestamps: true,
  }
);

2. Request의 Body를 읽기 위해 express.json 사용하기

Express 4.16.0 이상 버전부터 Body-Parser의 일부 기능을 포함한다.
그래서 body-parser를 따로 install 해주지 않아도 아래와 같이 사용이 가능하다.

/📃app.js

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


/*
{ extended: true/false } -> bodyParser 옵션 중 하나

false -> node.js에 기본으로 내장된 queryString 사용
true -> npm qs 라이브러리를 사용
*/

3. 로그 다루기

path 접근 시 로그를 확인하기 위해서 morgan 모듈을 설치하자

$ npm install morgan
/📃app.js

…
const morgan = require('morgan');
…

app.use(morgan('dev'));

4. nodemon 사용하기

코드의 변경이 있을 때마다 서버를 재시작 하는 것이 너무 불편하기 때문에
nodemon을 사용해서 코드 변경이 있을 시 자동으로 서버를 재시작하게 하자

$ npm install nodemon
/📃package.json

"scripts": {
    "dev": "nodemon app.js"
  },

앞으로 js, mjs, json 파일의 변경이 있을 때마다 (파일을 저장할 때마다)
자동으로 서버를 재시작해준다.

  • 정상 동작 화면


Controller

코드를 작성하기 전에

지난 포스트에서 정리, 작성했던대로 Controller에 콜백 함수의 동작을 구현해보자

먼저 Router 에 작성했던 콜백함수명을 가져왔다.

모든 게시글 조회
  - getAllPost

게시글 작성 GET / POST
  - getWrite
  - postWrite

게시글 전체 DELETE - 임시
  - deleteAllPost

특정 게시글 GET / DELETE
  - getOnePost
  - deleteOnePost

게시글 수정 GET / POST
  - getEditPost
  - postEditPost
  

코드 작성

행위에 대한 메소드와 경로, 접근 시 실행될 함수의 이름까지 작성을 완료했다면
Controller 파일을 만들어 실행 함수를 관리해보자

Controller 에서는 Post 모델에 대한 작업이 필요하기 때문에
Post Model 을 불러오고 시작한다.

const Post = require('../model/Post');

① 먼저 모든 게시글 조회에 대한 함수를 만들어보자

GET /

📁controllers/📃postController.js

// 모든 게시글 조회
const getAllPost = async (req, res) => {
  try {
    const posts = await Post.find({});
    res.status(200).render('board', { posts });
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

💡 앞으로 반복될 내용 ⤵

try..catch 문법을 사용해 스크립트가 오류로 인해 중단되는 것을 방지한다.


응답에 대한 상태 코드를 설정하고
클라이언트에게 파일(board)과 변수 데이터(posts)를 전송한다.


오류 발생 시 상태 코드를 설정하고 에러 메시지를 응답한다.


② 게시글 작성 페이지와 작성 후 데이터 전송

GET /post
POST /post

📁controllers/📃postController.js

…

// 게시글 작성 GET / POST
const getWrite = (req, res) => {
  try {
    res.status(200).render('write');
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

const postWrite = async (req, res) => {
  try {
    const {
      body: { title, contents, writer },
    } = req;
    const post = await Post.create({
      title,
      contents,
      writer,
    });
    res.redirect(`/board/post/${post._id}`);
    // 게시글을 작성한 뒤, 해당 게시글의 상세 페이지로 이동
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

③ 게시글 전체 삭제 - 개발용

없어도 되는 함수,
테스트할 때 쌓인 데이터가 너무 많아 정리가 필요해서 만들게 되었다.

DELETE /post/all

📁controllers/📃postController.js

…

// 게시글 전체 DELETE - 임시
const deleteAllPost = async (req, res) => {
  try {
    await Post.deleteMany({});
    res.sendStatus(204);
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

④ 특정 게시물의 상세 페이지 접근과 삭제

GET /post/:postId
DELETE /post/:postId

📁controllers/📃postController.js

…

const getOnePost = async (req, res) => {
  try {
    const {
      params: { postId },
    } = req;
    const post = await Post.findOne({ _id: postId });
    res.status(200).render('post', { post });
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

const deleteOnePost = async (req, res) => {
  try {
    const {
      params: { postId },
    } = req;
    await Post.findOneAndDelete({ _id: postId });
    res.sendStatus(204);
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

⑤ 특정 게시물 수정과 수정한 데이터 전송

GET /post/edit/:postId
POST /post/edit/:postId

📁controllers/📃postController.js

…

// 게시글 수정 GET / POST
const getEditPost = async (req, res) => {
  try {
    const {
      params: { postId },
    } = req;
    const post = await Post.findOne({ _id: postId });
    res.status(200).render('editPost', { post });
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

const postEditPost = async (req, res) => {
  try {
    const {
      params: { postId },
      body: { title, contents },
    } = req;
    await Post.findOneAndUpdate({ _id: postId }, { title, contents });
    res.redirect(`/board/post/${postId}`);
  } catch (error) {
    res.status(400).send({ error: error.message });
  }
};

마지막으로 작성한 함수를 router 에서 쓰기 위해 export 해주고
postRouter.js 에서 불러온다.

📁controllers/📃postController.js

…

module.exports = {
  deleteAllPost,
  getAllPost,
  getWrite,
  postWrite,
  getOnePost,
  getEditPost,
  postEditPost,
  deleteOnePost,
};
📁routers/📃postRouter.js

…

const {
  getAllPost,
  getWrite,
  postWrite,
  getOnePost,
  getEditPost,
  postEditPost,
  deleteOnePost,
  deleteAllPost,
} = require('../controllers/postController');

다음 포스트에서는 클라이언트에게 전송할 view 파일들을 작성해보자



전체 코드 보기
📃 Node.js 와 Express로 게시판 만들기 - Github

좋은 웹페이지 즐겨찾기