on1ystar 머릿속을 정리, 기록하는 곳

Node.js/Express body-parser/POST request 처리



의문점이나 지적 등의 관심 및 조언을 위한 댓글이나 메일은 언제나 환영이고 감사합니다.


views에서 POST 메소드로 요청한 form 데이터를 controllers에서 받아오는 방법을 알아보자.

DB는 사용하지 않고 간단하게 전역 객체 배열을 이용


시나리오

  • views

비디오 수정 페이지에 form 작성 → video title 수정 → POST request

  • controllers

request.body 객체에서 form 데이터 파싱 → videos 객체 배열에서 해당 video의 title 수정 → 비디오 시청 페이지로 redirect

  • views

비디오 시청 페이지에서 수정 사항 확인


디렉토리 구조(이전 포스팅 참고)

┌──node_modules
├─┬src
 ├─┬controllers
  ├──userController.js
  └──videoController.js
 ├─┬routers
  ├──globalRouter.js
  ├──userRouter.js
  └──videoRouter.js
 └─┬views
   ├─┬partial
    └──footer.pug
   ├──base.pug
   ├──home.pug
	├──videoEdit.pug<-----추가
   └──watch.pug
├──server.js
└──pakage.json


☄ views


// views/watch.pug
extends base.pug

block content
    h1=video.title
    h3 #{video.views} #{video.views <= 1 ? "view" : "views"}
    a(href=`${video.id}/edit`) edit video &rarr;

#{}을 이용해 JavaScript의 삼항 조건 연산자를 사용할 수 있다.

그리고 .pug에서 속성 값에 string과 함께 JS 객체 변수를 사용하고 싶을 때는 ${} 문법을 사용하면 된다.

// views/videoEdit.pug
extends base

block content
    form(method="post")
        input(name="title", placeholder="Video Title", value=`${video.title}`, required)
        input(value="save", type="submit")

name 속성의 값이 전달될 input 데이터의 변수 명이 됨(없으면 파싱 불가)


☄ routers


// routers/videoRouter.js
import { getEdit, postEdit } from "../controllers/videoController";

const videoRouter = express.Router();

videoRouter.get("/:id", watch);
videoRouter.route("/:id/edit").get(getEdit).post(postEdit);

export default videoRouter;

app.route()는 하나의 route에 여러 개의 http method를 체인 형식으로 라우팅할 수 있다.

이렇게 설정하면 하나의 view에 라우팅한 하나의 url에서 http request method 별로 사용자의 다양한 처리 및 응답할 수 있다.

/videos/:id/edit으로

  • GET request → getEdit controller 호출
  • POST request → postEdit controller 호출


☄ controllers


// controllers/videoController.js
let videos = [
  {
    title: "First video",
    rating: 5,
    comments: 4,
    createdAt: "2 minutes ago",
    views: 100,
    id: 1,
  },
  {
    title: "Second video",
    rating: 5,
    comments: 4,
    createdAt: "2 minutes ago",
    views: 100,
    id: 2,
  },
  {
    title: "Third video",
    rating: 5,
    comments: 4,
    createdAt: "2 minutes ago",
    views: 100,
    id: 3,
  },
];

export const watch = (req, res) => {
  const { id } = req.params;
  const video = videos[id - 1];
  return res.render("watch", { pageTitle: `Whatching ${video.title}`, video });
};
export const getEdit = (req, res) => {
  const { id } = req.params;
  const video = videos[id - 1];
  return res.render("videoEdit", { pageTitle: `Edit ${video.title}`, video });
};
export const postEdit = (req, res) => {
  const { id } = req.params;
  const { title } = req.body;
  videos[id - 1].title = title;
  return res.redirect(`/videos/${id}`);
};

getEdit은 라우팅 된 url로 GET 요청이 오면, videoEdit.pug을 렌더링 해 사용자에게 비디오 수정 페이지를 보여주는 처리를 하는 컨트롤러다. 때문에 마지막에 videoEdit.pug 페이지를 렌더링하는 res.render 함수를 반환한다.

postEdit은 마찬가지로 POST 요청을 처리하는 컨트롤러다. getEdit는 다르게 /videos/${id}(watch.pug 페이지)로 redirect 응답을 반환한다.

본래 POST 요청 시 사용자가 작성한 데이터들은 request 객체에 담겨 전달된다. 하지만 express에서 바로 request.body에 접근하면 undefined 에러가 발생한다.

// controllers/videoController.js
// ...
export const postEdit = (req, res) => {
  const { id } = req.params;
  console.log(req.body);
  return res.end();
  // videos[id - 1].title = title;
  // return res.redirect(`/videos/${id}`);
};

때문에 body-parser라는 미들웨어의 도움을 받아야 한다.


☄ body-parser middleware


request body에 있는 데이터를 분석해 JavaScript가 해석할 수 있도록 req.body 형태의 객체로 만들어 주는 미들웨어다.

설치

  • npm install body-parser

사실 Express v4.16.0부터 body-parser가 빌트 인 되어 따로 설치하지 않아도 됨.

https://expressjs.com/en/4x/api.html#express.urlencoded

// server.js

//...
app.set("views", process.cwd() + "/src/views");
app.set("view engine", "pug");
app.use(logger);
app.use(express.urlencoded({ extended: true })); // <-----추가
app.use("/", globalRouter);
app.use("/users", userRouter);
app.use("/videos", videoRouter);
//...

urlencoded({ extended: true }) 속성은 주소 형식으로 전달된 데이터를 해석하겠다는 의미로 주로 form 요청 데이터 해석 시 사용된다.

req.body 객체에 input 태그의 name 속성으로 지정한 title이 속성 이름, 입력한 body-parser test가 값으로 들어가 있다.

/videos/${id}(watch.pug 페이지)로 redirec까지 잘 된다.


Reference

https://nomadcoders.co/wetube

Node.js 교과서(2판) - 조현영

https://expressjs.com/en/4x/api.html#express.urlencoded