ë°ąěëě ë°ě´í° ě ěĽíë ë˛ (array database ě´ěŠ)
ě ë ę˛˝ëĄ / ěë ę˛˝ëĄ / GET method / POST method / res.redirect() / req.body
ě§ę¸ě ë°ě´í°ëĽź ë°ę¸°ë§ íęł  ěë¤. ë°ě´í°ëĽź ě ěĽí  ě¤ ěěěź íë¤.
MongoDB뼟 ë°°ě°ę¸° ě , ěźë¨ě ě¤ě  ë°ě´í°ë˛ ě´ě¤ę° ěëëź ë°°ě´ëĄ ë ë°ě´í°ë˛ ě´ě¤(ę°ě§ ë°ě´í°ë˛ ě´ě¤)뼟 ěŹěŠí  ę˛ě´ë¤.
ěźë¨, videos ë°°ě´ě ę° video ę°ě˛´ě id ěěąě 1, 2, 3ě´ëźęł  ěěëëĄ ëśě¸ë¤.
videos ë°°ě´ě trending 읨í¸ëĄ¤ëŹ ë°ěźëĄ ëšźë´, ëŞ¨ë  ěť¨í¸ëĄ¤ëŹěě ěŹěŠí  ě ěëëĄ íë¤.
// videoController.js
let videos = [
  {
    title: "First Video",
    rating: 5,
    comments: 2,
    createdAt: "2 months ago",
    views: 59,
    id: 1,
  },
  {
    title: "Second Video",
    rating: 5,
    comments: 2,
    createdAt: "2 months ago",
    views: 59,
    id: 2,
  },
  {
    title: "Third Video",
    rating: 5,
    comments: 2,
    createdAt: "2 months ago",
    views: 59,
    id: 3,
  },
];
Homeě ę°ě§ ë°ě´í°ë˛ ě´ě¤ě ěë 모ë ëšëě¤ë¤ě ëě´í´ěź íë¤.
ě´ě  ęłľëśěě ě´ëݏ ěëŁí ëśëśě´ë¤.
video mixině ě´ěŠíěŹ, video(info)ě id뼟, (Homeěě í´ëŚí  video íě´íě) urlě ëŁě´ě¤Źë¤.
//- home.pug
extends base
include mixins/video
block content
  h2 Welcome here you will see the trending videos
  each potato in videos
    +video(potato)
  else
    li Sorry nothing found.
//- video.pug
mixin video(info)
  div 
    h4
      a(href=`/videos/${info.id}`)=info.title
      //- íě´í í´ëŚ ě '/videos/id ëë˛'ëĄ ě´ë
    ul 
      li #{info.rating}/5.
      li #{info.comments} comments.
      li Posted #{info.createdAt}.
      li #{info.views} views.
íě´íě í´ëŚí늴, /videos/id ëë˛ëĄ ě´ëíę˛ë ë§ë ë¤.ě´ëĽź ěí´ě  video.pug íěźěě HTMLě ë§ë¤ęł  ěěźëŻëĄ ě´ íěźě ě´í´ěź íë¤.
video.pug íěźěě h4뼟 ěě íë¤.
//- video.pug
h4
  a(href=`/videos/${info.id}`)=info.title
đĄ pug íěź ěěą ęˇěš
- ëłě + í ě¤í¸ â #{ëłě}
 - ë¨, href, id, class ëą 'ěěą'ěěë ě´ë ę˛ í ě ěë¤. ěë°ě¤íŹëŚ˝í¸ě ęˇěšě ë°ëźěź íë¤.
 
( " " + or í í댿 돸ěě´)
/videos/id ëë˛ëĄ ě´ëíě ë, í´ëŚí íě´íě videoę° ëł´ě´ę˛ë ë§ë ë¤.videoController.js íěźěě see 읨í¸ëĄ¤ëŹëĽź ěě íë¤.
â  see 읨í¸ëĄ¤ëŹě req.params(íëźëݏí°)뼟 ěśë Ľí´ëł´ë ě˝ë뼟 ěśę°íë¤.
꡸ í ěí ěźě second video íě´íě í´ëŚí´ localhost:4000/videos/2ëĄ ë¤ě´ę°ë¤.
VS codeě ë´ěĽ í°ëݏëě ěëí ëëĄ { id: '2' }ę° ěśë Ľëë ę˛ě íě¸íë¤.
// videoRouter.js
videoRouter.get("/:id(\\d+)", see);
//- video.pug
h4
  a(href=`/videos/${info.id}`)=info.title
// videoController.js ěě 
export const see = (req, res) => {
  console.log(req.params); // { id: '2' }
}
⥠ě´ëĽź ě´ěŠí´ videoě id뼟 ę°ě ¸ě¨ë¤.
( videos ë°°ě´ě video(info)ě id === video íě´ě§ urlě íëźëŻ¸í° )
// videoController.js
export const see = (req, res) => {
  const { id } = req.params; // const id = req.params.id; ě ę°ë¤
}
⢠ę°ě ¸ě¨ video id뼟 ě´ěŠí´ videos ë°°ě´ ěěě ꡸ video뼟 ę°ě ¸ě¨ë¤.
ę°ě ¸ě¨ video뼟 ě´ěŠí´ ꡸ video íě´íě ěśë Ľíë¤.
// videoController.js
export const see = (req, res) => {
  const { id } = req.params; // ëšëě¤ ěě´ë뼟 ę°ě ¸ě´
  const video = videos[id - 1]; // ëšëě¤ëĽź ę°ě ¸ě´
  return res.render("see", { pageTitle: `Seeing ${video.title}` }); // ëšëě¤ íě´íě ëł´ěŹě¤
}
ě§ę¸ě ę°ě§ ë°ě´í°ë˛ ě´ě¤ëĽź ěŹěŠ ě¤ě´ëź ě¤ě ëĄ videoě íěí ěë ěë¤.
꡸ëŹë, ę°ëľíę˛ ëĄě§ě ě ě´ëł´ě늴đ video íě´ě§ě urlě ě´ë¤ id뼟 ę°ě§ë¤.
đ ꡸ id뼟 ěťě´ě ꡸ id뼟 ę°ě§ęł ěë video뼟 ě°žëë¤.
đ ꡸ videoě ě 보뼟 ë°íěźëĄ video íě´ě§ě ě´ę˛ě ę˛ě render íë¤.
⣠ę°ě ¸ě¨ video뼟 see í í댿ěźëĄ ëł´ë¸ë¤. see.pug íěźěě video (object)뼟 ë¤ëٰ ě ěę˛ ëěë¤.
// videoController.js
export const see = (req, res) => {
  const { id } = req.params;
  const video = videos[id - 1];
  return res.render("see", { pageTitle: `Seeing ${video.title}`, video }); // video: videoě ę°ë¤
}
⤠ę°ě ¸ě¨ video ě ëł´ëĽź ě´ěŠí´ see.pug íěźě ěě íë¤.
기쥴ě See Video í
ě¤í¸ ëě ě video.views뼟 ëł´ěŹěŁźë ¤ęł  íë¤.
ěźí 쥰깴 ě°ě°ě뼟 ě´ěŠí´ ë¨Âˇëłľěě 경ě°ëĽź ëëě´ view ëë views뼟 ëł´ěŹě¤ë¤.
//- see.pug
extends base.pug
block content
  h3 #{video.views} #{video.views === 1 ? "view" : "views"}
ěě ěě  íě´ě§ëĄ ě´ëíë ë§íŹëĽź ë§ë ë¤.â  ë§íŹë ě ë 경ëĄě ěë ę˛˝ëĄ ě¤ 'ěë 경ëĄ'뼟 ě´ěŠí´ěź íë¤.
íěŹ íě´ě§(/videos/id ëë˛)ěě, ě´ëí´ěź í기 ë돸ě´ë¤.
//- home.pug
extends base.pug
block content 
  h3 #{video.views} #{video.views === 1 ? "view" : "views"}
  a(href=`${video.id}/edit`) Edit Video → //- ěśę° â
đĄ ě ë 경ëĄě ěë 경ëĄ
ě ë 경ëĄhrefě ě머댏ě /edit ě ëśě´ëŠ´, íěŹ ě´ë¤ íě´ě§ě ěëě§ě ěę´ěě´,
root 경ëĄ+ /editěźëĄ ě´ëíë¤.localhost:4000/profile/edit-profile/password =====> a(href="/potato") localhost:4000/potato
ěë 경ëĄhrefě ě머댏ě ęˇ¸ëĽ edit ě ëśě´ëŠ´,
íěŹ íě´ě§ěě/eidtěźëĄ ě´ëíë¤. (âľ videoRouter.js)localhost:4000/profile/edit-profile/password =====> a(href="potato") localhost:4000/profile/edit-profile/potato
/videos/id ëë˛/editěźëĄ ě´ëíě ë, ěě íë ¤ë videoę° ëł´ě´ę˛ë ë§ë ë¤.â  ě´ë˛ěë ěě í  video뼟 ę°ě ¸ěěź íëŻëĄ, videoController.js íěźěě ěě see 읨í¸ëĄ¤ëŹëĽź ěě í ëëĄ, edit 읨í¸ëĄ¤ëŹë ëę°ě´ ěě íë¤. ===> (2)ě â  ~ ⣠ë°ëłľ
// videoController.js
export const edit = (req, res) => {
  const { id } = req.params;
  const video = videos[id - 1];
  return res.render("edit", { pageTitle: `Editing: ${video.title}`, video });
};
⥠ę°ě ¸ě¨ video ě ëł´ëĽź ě´ěŠí´ edit.pug íěźě ěě íë¤.
ě´ íě´ě§ěě userę° videoě titleě ěě í  ě ěę˛ë í려고 íë¤.
formęłź text input, submit input í꡸뼟 ë§ë ë¤.
//- edit.pug (ěě  ëŻ¸ě)
extends base.pug
block content
  h4 Change Title of Video
  form(action="")
    input(name="title", placeholder="Video Title", value=`${video.title}`, required)
    input(value="save", type="submit")
cf. form í꡸ě action ěěą â
íź ë°ě´í°(form data)뼟 ěë˛ëĄ ëł´ëź ë í´ëš ë°ě´í°ę° ëě°Ší url
ě´ ę˛˝ě°ěë ë°ëĄ action ěěąě ę°ě ě ě´ěŁźě§ ěëë¤ëŠ´
기본ě ěźëĄ localhost:4000/videos/id ëë˛/edit ě´ ëë¤.
꡸ëŹë, ě ě˝ëë ěě§ ěě ě´ íěí 미ěěą ě˝ëě´ë¤.
ě§ę¸ęšě§ í ę˛ě ë°ąěëěě ëšëě¤ëĽź ę°ě ¸ě¤ë ę˛ě´ěë¤.
ě´ě  ěě í ë´ěŠě ë¤ě ë°ąěëëĄ ëł´ëź ě°¨ëĄě´ë¤.
ěŚ, save ë˛íźě ë뼴늴 inputě ě
ë Ľí ëšëě¤ě ěëĄě´ titleě´ ë°ąěëě ě ěĽëëëĄ í´ěź íë¤.
ë°ě´í°ëĽź ë°ěěŹ ëë GET request ěŚ, videoRouter.get("url", 읨í¸ëĄ¤ëŹ)ě ěŹěŠíë¤.
ë°ě´í°ëĽź ëł´ëź ëë POST request ěŚ, videoRouter.post("url", 읨í¸ëĄ¤ëŹ)ě ěŹěŠí´ěź íë¤.
đĄ GET method VS POST method (with ěě )
method: formęłź ë°ą ěë ěŹě´ě ě ëł´ ě ěĄ ë°Šě
GET method
- 기본ě ěźëĄ method="GET"ě´ ě¤ě ëě´ ěë¤.
 - ë°ě´í°ëĽź ë°ë ę˛ ëŞŠě ěź ë ěŹěŠëë¤.
 - 꾏ę¸ě´ë ë¤ě´ë˛ ëąěě ę˛ěí ë ěŹěŠëë¤. (ę˛ěě´ę° url 죟ěě íŹí¨ëë¤.)
 //- see.pug form(action="/save-changes") input(name="title", placeholder="Video Title", value=`${video.title}`, required) input(value="save", type="submit")form í꡸ě action ěěąě ěśę°íë¤.
â save ë˛íźě í´ëŚ ělocalhost:4000/save-changes?title=Third+VideoëĄ ě´ëíë¤. formě ěë ě ëł´ę° urlě ë¤ě´ę° ę˛ě´ë¤.
â í늴ěëCannot GET /save-changesëźęł ëŹë¤. ěë˛ë (ë¤ëĽ¸ GETě ëí´ě ěë ë°ę° ěě§ë§) GET /save-changesě ëí´ě ěë ë°ę° ě기 ë돸ě´ë¤.
POST method
- 기본ę°ě´ GETě´ëŻëĄ POST request뼟 ěŹěŠí기 ěí´ěë method="POST"뼟 ěśę°í´ěź íë¤.
 - ë°ě´í°ëĽź ě ë°ě´í¸íë ę˛ ëŞŠě ěź ë ěŹěŠëë¤.
 - íěźě ëł´ë´ęą°ë ëĄęˇ¸ě¸ě íęą°ë ë°ě´í°ë˛ ě´ě¤ě ěë ę°ě ë°ęż ë ěŹěŠëë¤.
 //- see.pug form(action="/save-changes", method="POST") input(name="title", placeholder="Video Title", value=`${video.title}`, required) input(value="save", type="submit")form í꡸ě method ěěąě ěśę°íë¤.
â save ë˛íź í´ëŚ ělocalhost:4000/save-changesëĄ ě´ëíë¤. (?title=...ě íěëě§ ěëë¤.)
â í늴ěëCannot POST /save-changesëźęł ëŹë¤. ěë˛ë POSTě ëí´ě ěë ë°ę° ě기 ë돸ě´ë¤.
ě ë´ěŠě ě°¸ęł í´ě edit.pug íěźě ë¤ě ěëě ę°ě´ ěě íë¤.
//- edit.pug
form(method="POST")
  input(name="title", placeholder="Video Title", value=`${video.title}`, required)
  input(value="save", type="submit")
ěë˛ë ěě§ POSTě ëí´ě ěë ë°ę° ěë ěíě´ë¤.
save ë˛íź(submit input)ě í´ëŚí  ë formě íëě íľě íęł ě íë¤.â  ěë˛ě í´ëš POSTě ëí´ ě려죟기 ěí´ videoRouter.js íěźěě ëę°ě urlëĄ post request뼟 ëł´ë´ë ě˝ë뼟 ěěąíë¤.
getęłź post뼟 꾏ëśí  ě ěëëĄ ę¸°ěĄ´ě edit 읨í¸ëĄ¤ëŹě ě´ëŚě getEditěźëĄ ëłę˛˝íë¤. (videoController.js ěěë)
// videoRouter.js
// videoRouter.get("/:id(\\d+)/edit", getEdit);
// videoRouter.post("/:id(\\d+)/edit", postEdit);
// ě ë ě¤ě ě˝ëë, ěë í ě¤ě ě˝ëëĄ ë°ężě¸ ě ěë¤.
videoRouter.route("/:id(\\d+)/edit").get(getEdit).post(postEdit);
⥠videoController.js íěźě postEdit 읨í¸ëĄ¤ëŹëĽź ěśę°íë¤.
ěźë¨ě ě돴ę˛ë ë°ííě§ ěęł , íěë§ ěěąí´ě¤Źë¤.
â getEdit 읨í¸ëĄ¤ëŹë formě render í´ě¤ë¤.
â postEdit 읨í¸ëĄ¤ëŹë video뼟 ěě í´ě¤ë¤. (ěě§ ě˝ë ěěą x)
// videoController.js
export const getEdit = (req, res) => {
  const { id } = req.params;
  const video = videos[id - 1];
  return res.render("edit", { pageTitle: `Editing: ${video.title}`, video });
};
export const postEdit = (req, res) => {}; // ěśę°
ě´ě  localhost:4000/videos/3/edit ěźëĄ ë¤ě´ę°ëŠ´, Cannot POST ę° ëě¤ě§ ěęł  ë¸ëźě°ě ë 돴í ëĄëŠě íë¤.
ěë˛ě postę° ëě§ë ě려줏ě§ë§, post request뼟 ë°ěě ë ë í´ěź íëě§ë ě í´ěŁźě§ ěěěźëŻëĄ ěë˛ë ě´ë¤ ě˛ëŚŹë íě§ ěě ěą ë¸ëźě°ě ě ěëľíě§ ěě ë¸ëźě°ě ę° 돴í ë기 ěíě¸ ę˛ě´ë¤.
ë°ëźě, ěë˛ę° post request뼟 ě˛ëŚŹ ë° ěëľí  ě ěëëĄ postEdit 읨í¸ëĄ¤ëŹëĽź ë§ě  ěěąí´ě¤ěź íë¤.
postEdit 읨í¸ëĄ¤ëŹě ěí ě video뼟 ěě íë ę˛ě¸ë° ěŹę¸°ěë videoě titleë§ě ë°ężëł´ě.
input ę°ě ě´ěŠí´ videoě titleě ě
ë°ě´í¸íëëĄ íë¤.â  postEdit 읨í¸ëĄ¤ëŹě res.redirect()뼟 ěśę°íë¤.
res.redirect()ë 'ě§ě í urlëĄ ë¸ëźě°ě ę° ěëěźëĄ ě´ë'íëëĄ íë¤.
ěŹę¸°ěë save ë˛íźě ë뼴늴 see íě´ě§(ěŚ, /videos/id ëë˛)ëĄ ëěę°ëëĄ í  ę˛ě´ë¤.
// videoController.js
export const postEdit = (req, res) => {
  const { id } = req.params;
  return res.redirect(`/videos/${id}`);
};
⥠postEdit 읨í¸ëĄ¤ëŹě req.body뼟 ěśę°íë¤.
ěě req.params뼟 íľí´ urlě íëźëŻ¸í° ę°(=video(info)ě id)뼟 ë°ěěë ę˛ě˛ëź
req.body뼟 íľí´ 'formě value뼟 ë°ěěŹ ě ěë¤.'
꡸ ě ě 먟ě , expressę° formě ë¤ëٰ ě ěëëĄ, server.jsě middleware뼟 ěśę°í´ěź íë¤.
(ěěšę° ě¤ěíë¤. videoRouterëł´ë¤ ě ě ěśę°í´ěź íë¤. ꡸ëěźë§ ě´ë¤ requestę° videoRouter.postě ě´ëĽ´ë ě ë ě´ëݏ req.bodyę° ě¤ëšëě´ ěě ě ěë¤.)
express.urlencoded()ë expressę° formě value뼟 ě´í´í í ěë°ě¤íŹëŚ˝í¸ object íěěźëĄ ëłííëëĄ íë¤.
extended ěľě
ě formě bodyě ěë ě ëł´ë¤ě´ 보기 ě˘ě íěě ę°ěśëëĄ íë¤.
// server.js
app.use(express.urlencoded({ extended: true }))
// videoController.js
export const postEdit = (req, res) => {
  const { id } = req.params;
  const { title } = req.body;
  videos[id - 1].title = title; // ę°ě§ ë°ě´í°ë˛ ě´ě¤ ěŹěŠ ě¤ě´ëź ě´ë ę˛ ě
ë°ě´í¸í´ě¤ ę˛. ě¤ě ëĄë ě´ë ę˛ ěí¨
  return res.redirect(`/videos/${id}`);
};
ëĄě§ ě 댏
đ íě´ě§ëĽź get í´ě ë¤ě´ę°ë¤.
đ (ë¤ě 돴ěě¸ę°ëĽź í´ëŚí´ ë¤ě´ę°ě) formě ëę°ëĽź ě ë Ľí í submit ë˛íźě ë뼸ë¤.
đ submit ë˛íźě ëëŹě post request뼟 ëł´ë´ëŠ´, post 읨í¸ëĄ¤ëŹę° ě¤íëë¤.
đ post 읨í¸ëĄ¤ëŹë req.bodyëĄëśí° formě ě ë Ľí ę°ě ěťě´, ě´ëĽź ë°íěźëĄ ě´ę˛ě ę˛ě íë¤.
(3) ëłľěľěŠ parcticeě´ë¤
ěŹę¸°ě ëšëě¤ëĽź ě
ëĄëíë¤ë ę˛ě
ę°ě§ ë°ě´í°ë˛ ě´ě¤(array database)ě video ę°ě˛´ëĽź íë ë ěśę°íë¤ë ëťě´ë¤.
//- base.pug
doctype html
html(lang="ko")
  head
    title #{pageTitle} | Wetube
    link(rel="stylesheet" href="https://unpkg.com/mvp.css")
  body
    header
      h1=pageTitle
      nav
        ul 
          li 
            a(href=`/videos/upload`) Upload Video →
    main
      block content
    include partials/footer.pug
//- upload.pug
extends base.pug
block content
  form(method="POST")
    input(name="title", placeholder="Video Title", required)
    input(value="upload", type="submit")
// videoRouter.js
import express from "express";
import {
  see,
  getEdit,
  postEdit,
  getUpload,
  postUpload,
} from "../controllers/videoController";
const videoRouter = express.Router();
videoRouter.get("/:id(\\d+)", see);
videoRouter.route("/:id(\\d+)/edit").get(getEdit).post(postEdit);
videoRouter.route("/upload").get(getUpload).post(postUpload); // ěśę°
export default videoRouter;
// videoController.js
const videos = [
  {
    title: "First Video",
    rating: 5,
    comments: 2,
    createdAt: "2 months ago",
    views: 1,
    id: 1,
  },
  // ě´í ěëľ
];
export const trending = (req, res) => {
  return res.render("home", { pageTitle: "Home", videos });
};
export const getUpload = (req, res) => {
  return res.render("upload", { pageTitle: "Upload Video" });
};
export const postUpload = (req, res) => {
  const { title } = req.body;
  const newVideo = { // ę°ě§ ë°ě´í°ë˛ ě´ě¤ ěŹěŠ ě¤ě´ëź ě´ë ę˛ ě¨ě¤ ę˛. ě¤ě ëĄë ě´ë ę˛ ěí¨
    title,
    rating: 0,
    comments: 0,
    createdAt: "just now",
    views: 0,
    id: videos.length + 1,
  };
  videos.push(newVideo); // ă
  return res.redirect("/");
};
+ë§ě§ë§ěźëĄ 모ë pug íěź ěěě .pug ěě íęł , see video뼟 watch videoëĄ ë°ęż
ę°ě ęłě ëŁę¸°
wsl2 ěŹě¤ěš, MongoDB ě¤ěš