Edit Video # 01

0_CyberLover_0·2022년 4월 13일
0

Node.JS # 03

목록 보기
14/19

Documentation을 다시 보면 exec(execute)라는 걸 볼수 있다.

https://mongoosejs.com/docs/api.html#model_Model.findById

await Adventure.findById(id).exec();

이게 뭘 하는 거냐면 이 부분이 query를 실행(execute)시키는 거다.

그런데 문제가 뭐냐면

videoController.js에서 보면

  const video = await Video.findById(id);

이 부분은 이미 실행이 된거다. 그래서 이 부분에 exec를 입력하면

  const video = await Video.findById(id).exec();

딱히 뭐가 달라지는건 없다. 새로고침을 해도 똑같은 video페이지가 보인다.

무슨 일이 벌어지고 있는 거냐면 쉽게 말해 Mongoose내부적으로

만약 execute를 호출하면 promisereturn될 거다.

하지만 promise에 대해선 전혀 신경 안 써도 된다. 그래서 그냥 삭제해 주도록 한다.

이렇게 해도 상관없는 이유는 지금 asyncawait을 쓰고 있기 때문이다.

그래서 똑같이 보이고 코드도 달라질게 없는 거다. 하지만 제대로 처리해야 할 것은

누군가가 존재하지 않는 video페이지를 방문 했을때 어떻게 해야 하느냐 이다.

확인해 보기 위해서 videoconsole.log로 출력하고

export const watch = async (req, res) => {
  const { id } = req.params;
  const video = await Video.findById(id);
  console.log(video);
  return res.render("watch", { pageTitle: video.title, video });
};

이게 굉장히 중요하다. 만약 누군가 존재하지 않는 video페이지로 접근 할수도 있기 때문이다.

새로고침하고 터미널로 가보면 예상대로 video object가 출력이 된다.

http://localhost:4000/videos/625528ea216ff9baacd03f1a

하지만 만약 여기 url중에 숫자 0을 6으로 바꾸면 어떻게 될까?

어떤 일이 일어나냐면 무한 로딩중이다. (현재는 바로 페이지가 오류가 난다.

사이트에 연결을 할수 없다고 뜬다.)

터미널로 가서 확인해 보면

null

null이 출력이 되고 있다. 단순히 말해서 video를 찾을 수 없단 소리이다.

하지만 아직 에러가 있다. 이 에러는 MongoDB에서 부터 나온 에러가 아니다.

이 경우에는 null로 부터 title이라는 property를 찾을 수 없다는 게 문제이다.

TypeError: Cannot read properties of null (reading 'title')

무슨 말이냐면 영상 검색에 실패 했기 때문에 videonull인 상태고

  return res.render("watch", { pageTitle: video.title, video });

여기 pageTitle을 보면 videotitle을 요구하는데 하지만 그 영상을 찾을 수 없었기 때문에

videonull인 거다.

URL을 바꿔준 해당 id를 가진 영상은 존재하지 않기 때문이다.

굉장히 흥미로운 문제이다. 왜냐하면 뭔가를 코딩 할때는 계획한 조건에서는 잘 작동하게 되어 있다.

하지만 다른 조건들도 항상 체크해야 한다. 검색한 비디오가 존재하지 않을 때 어떻게 대처 할지

보다시피 현재 error가 발생 하고 있다.

title을 요청했지만 그 video가 존재하지 않아서 null이 되는 error이다.

nulltitle이 없다. 이 에러 메세지는 완전 별로 이다.

TypeError: Cannot read properties of null (reading 'title')

에러메세지가 videonull이고 nulltitle을 갖고 있지 않습니다.

이런 식으로만 나와도 조금 나은 메세지 일텐데 말이다.

이제 할수 있는건 미리 확인 하는거다.

videoController.js에서

export const watch = async (req, res) => {
  const { id } = req.params;
  const video = await Video.findById(id);
  if (video) {
    return res.render("watch", { pageTitle: video.title, video });
  }
  return res.render("404", { pageTitle: "Video not found." });

만약 video가 존재 한다면 render watch 부분을 리턴하고 존재하지 않는다면

아직 만들지는 않았지만 404를 렌더한다.

404도 만들어 준다.

views폴더 안에 404.pug파일을 만들어 준다.

extends base

watch.pug와 같이 extends base라고 만들어 준다.

그리고 baseheaderpageTitle이 필요하니 만들어 줬다.

이제 video가 존재하지 않는 경우도 대처 한거다. 새로고침 해서 확인해 보면

"Video not found."라고 잘 뜬다. 이제 not found도 제대로 처리하게 되었다.

이제는 base.pug로 돌아가서 모든 링크에 재대로 접근 할수 있게 고쳐 보도록 한다.

    body 
        header
            h1=pageTitle
            nav 
                ul 
                    li 
                        a(href="/videos/upload") Upload Video
                    li  
                        a(href="/") Home

링크를 이렇게 하나 생성하면 Home으로 바로 가는 링크가 생긴 거다.

이제 query들을 실행 할 뿐만 아니라 결과도 체크해서 404 not found도 제대로 리턴한다.

이제 영상을 편집 할수 있게 해본다.

현재는 edit page를 보면 에러가 있다. 보다 먼저 손 봐 줄건 edit video control을 완성 하는 거다.

getEditpostEdit이 있는데 getEdit부터 작업 할거다.

IDreq.params로 부터 받는다. watch function한 것과 비슷하게 할 거다.

일단은 비디오를 찾아야 하니

export const watch = async (req, res) => {
  const { id } = req.params;
  const video = await Video.findById(id);
  if (!video) {
    return res.render("404", { pageTitle: "Video not found." });
  }
  return res.render("watch", { pageTitle: video.title, video });
};

export const getEdit = async (req, res) => {
  const { id } = req.params;
  const video = await Video.findById(id);
  if (!video) {
    return res.render("404", { pageTitle: "Video not found." });
  }
  return res.render("edit", { pageTitle: `Editing`, video });
};

만약 await를 쓸거라면 async를 입력해야 한다는걸 잊지 말자.

그리고 만약 영상이 존재하지 않는다면 렌더해야 할것도 있다. 그리고 주로 사용하는 패턴이데

보통 에러를 먼저 처리하는게 좋다. 정리하자면 에러를 먼저 확인하고 처리하면

나머지 코드들은 다 정상적인 케이스에 작동 할 코드가 될거다.

만약 videonull이면 errorreturn 하고 아닌 경우엔 정상적으로 리턴

(!video) 

(비디오가 없을때)

(video === null)

이둘은 같은 개념이다.

보통 에러가 날 경우를 if를 써서 처리하고 if 바깥에 있는 코드들은 정상적인 경우

실행 될것들로 코딩한다.

그래서 getEdit에 이렇게 정리 하게 된거다.

왜냐하면 이번에도 편집할 영상이 존재 하는지 먼저 확인을 할 필요가 있기 때문이다.

그러니 영상을 먼저 검색하고 만약 존재하지 않는 영상이면 "Video not found."를 출력한다.

다시 강조 하자면 에러체크를 먼저 한다. 그러면 나머지 코드는 에러 걱정 할 필요가 없다.

하지만 여기서 return하는게 굉장히 중요하다.

  if (!video) {
 res.render("404", { pageTitle: "Video not found." });
  }
  return res.render("watch", { pageTitle: video.title, video });
};

만약 이런식으로 return을 안하면 영상이 존재하지 않을때 javascript

 res.render("404", { pageTitle: "Video not found." });

이 부분을 실행하고 계속해서 그 밑에 코드도 실행 할거다.

  return res.render("watch", { pageTitle: video.title, video });

그러니까 function을 바로 끝내야하니 if안에 return을 집어 넣어야 한다.

if안에 return이 없으면 javascript는 영상이 없을때 if 안의 코드를 실행하고

그 밑에 코드들도 실행 할텐데 그런 원하지 않는 결과이니까 꼭 return을 해주도록 한다.

getEdit에서는 먼저 영상을 검색하고 만약 영상이 없을 경우엔 404를 리턴할거다.

정상적인 처리 방법이고 여기에서 edit페이지를 출력할거다.

  return res.render("watch", { pageTitle: video.title, video });

edit.pug를 확인해 보면

      input(name="title", placeholder="Video Title",value=video.title,required)

edit페이지는 video object를 필요로 한다. 그래서 Editing이라고 하고

video object를 보내준 결과이다.

  return res.render("edit", { pageTitle: `Editing`, video });

이제 새로 고침을 하면 input에 이미 제목이 preload되어 있다.

  return res.render("edit", { pageTitle: `Edit ${video.title}`, video });

그리고 Edit하고 video.title을 넣어 줬다. 새로 고침 해주면 잘 작동 한다.

아직 edit해야 할것 들이 많다. 그러기 위해선 pug 파일을 수정 해야 한다.

제목도 필요 하지만, 영상 설명과 해시태그도 필요 하다.

upload.pug에서

input(placeholder="Description", requried, type="text", name="description", minlength=20)
      input(placeholder="Hashtags, separated by comma.", requried, type="text", name="hashtags")

이 두줄을 복사해서

edit.pug에다가 넣어 준다.

block content 
   h4 Change Title of Video
   form(method="POST")
      input(name="title", placeholder="Video Title",value=video.title,required)
      input(placeholder="Description", requried, type="text", name="description", minlength=20)
      input(placeholder="Hashtags, separated by comma.", requried, type="text", name="hashtags")
      input(value="Save",type="submit")

이제 제목뿐만 아니라 설명, 해시태그도 편집 할수 있다. 그리고 input들은 upload form에서 가져와서 내용이 없다.

하지만 지금 edit template이기 때문에 미리 form에 내용을 채워 줘야한다.

block content 
   h4 Change Title of Video
   form(method="POST")
      input(name="title", placeholder="Video Title",value=video.title,required)
      input(placeholder="Description", requried, type="text", name="description", minlength=20, value=video.description)
      input(placeholder="Hashtags, separated by comma.", requried, type="text", name="hashtags", value=video.hashtags)
      input(value="Save",type="submit")

이런식으로 value를 추가해 준다. 그러면 빈 input이 아닌 가지고 있는 정보의

input이 나오게 된다.

하지만 이제는 hashtags에 문제가 생겼다. 뭐가 문제냐면 hashtagsarray이다 보니

있는 그대로 array로 보여지고 있다. hashtagsarray되도록 정했기 때문이다.

그래서 지금부터 hashtagsformat해 줄 거다.

array같이 보이지 않고 string처럼 보여야 자연스럽기 때문이다.

이제 어떻게 주어진 arraystring으로 format할지 알아 본다.

array를 복사해서 inspect를 통해 console로 가서 복사한 array에 다가

.join()만 붙여 주면 끝난다.

이제 edit.pug로 돌아가서

      input(placeholder="Hashtags, separated by comma.", requried, type="text", name="hashtags", value=video.hashtags.join())

.join()를 붙여 준다. 이제 새로고침하면 array가 아닌 string으로 나온다.

profile
꿈꾸는 개발자

0개의 댓글