현재 오류가 있고
console
에서 해당 에러가 뭔지 정확히 알수 있다.
또 다른 오류는 뭐가 있는지 찾아 본다.
예를 들어
ValidationError: Video validation failed: createdAt: Cast to date failed for value "lalalallalalal" (type string) at path "createdAt"
이 에러는 validation
에러이다.
createdAt
에 잘못된 타입의 데이터를 전송했기에 그렇다.
Date
타입이 아니라 에러가 발생 하였다. string
을 전송해서 에러가 발생 한거다.
다른 오류는 뭐가 있을지 더 본다.
예를 들어 데이터를 아예 안 보낼수도 있다.
videoController.js
에서
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
await Video.create({
title: title,
description: description,
hashtags: hashtags.split(",").map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
});
return res.redirect("/");
};
createdAt
을 지워서 date
를 아예 안 보내면 어떻게 될지 한번 보도록 한다.
새로고침 한다음 upload
해 보면 아무 에러 없이 video
가 형성 되었다.
왜 에러 없이 만들어 질수 있을까? createdAt
이 date
여야 한다고 설정했었다.
이유는 required
를 적지 않아서 그렇다. 그래서 에러가 나지 않았다.
video
를 생성하는데 date
를 전송 안 했지만 database
에게 괜찮다고
date
는 필수가 아니라고 전달해서 그렇다.
required
라고 설정하지 않았기에 이런 결과가 나온거다.
현재 mongo console
을 보면 db.videos.find()
쳐보면
video
중에 한video
는 createdAt
가 없다.
그래서 reuired
를 추가해 주도록 한다.
video.js
에서
createdAt: { type: Date, required: true },
이렇게 해주면 이제 에러가 생길거다. 왜냐하면 createdAt
은 이제 required
이기 때문이다.
사실 다른 모든 부분도 다 required
여야 한다.
새로고침 해주고 upload
해주면 어떻게 되냐면 에러가 발생 한 걸 확인 할수 있다.
browser
자체에는 문제가 없지만 response
가 없다.
return res.redirect("/");
그 이유는 javascript
가 에러로 인해 이곳에서 멈춘거다.
에러가 있으면 catch
를 해야한다. try
와 catch
를 사용 하면 되지만 좀 있다 해주도록 한다.
현재 이 에러에 집중한다. validation
에러라고 적혀 있다.
ValidationError: Video validation failed: createdAt: Path `createdAt` is required.
createdAt
이 required
라 적혀 있다.
보다시피 mongoose
에게 데이터 타입을 구체적으로 작성 할수록 편하다.
예를 들어
createdAt: { type: Date, required: true },
hashtags: [{ type: String }],
이렇게 저 부분은 required
이다. 여긴 string
이어야 한다.
이렇게 해주면 mongoose
와 mongoDB
가 우리를 위해서 validation
해준다.
지금 mongoDB
가 date
가 없기 때문에 video
생성을 거부 하고 있는 거다.
실수 할수 있는 부분들을 체크해주고 있는거다.
계속 다른 오류들을 만들어(?) 보도록 한다.
그 전에 먼저 에러만 손 보도록 한다.
페이지는 계속 무한 로딩 중인데 아래 코드가 실행 되지 않아서 그러는 거다.
return res.redirect("/");
await
에서 에러가 생기면 그냥 다 날아가 버리는 거다.
await Video.create({
바로 이부분 !! 아무것도 실행 되지 않는다. 넘어가기 위해서는 에러를 catch
해줘야 한다.
좀 전에 말했던 try
와 catch
를 사용해 준다.
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
try{
await Video.create({
title: title,
description: description,
hashtags: hashtags.split(",").map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
});
return res.redirect("/");
} catch (error) {
console.log(error);
return res.render("upload", { pageTitle: "Upload Video" });
}
};
이렇게 try
를 해줄거고 에러가 있으면 catch
해줄거다.
그리고 에러도 위치 해 줄거고 에러를 console.log
해준다.
에러를 잡아내도 무언가를 return
해야한다. 그래서 upload
를 다시 render
할거다.
그래서 이렇게 결과가 나왔다.
video
생성에 문제가 없다면 home
으로 보내질거다.
하지만 에러가 있다면 javascript
는 실행 시키지 않고 upload
를 다시 render
할거다.
다시 한번 새로고침을 해주고 video
를 만들어 보면 보다시피 에러가 있고
upload
가 다시 render
되었다. 그리고 에러는 바로 터미널에서 볼수 있다.
Error: Video validation failed: createdAt: Path `createdAt` is required.
createdAt
이 required
라고 알려 주고 있다.
이제 에러가 catch
되고 있고 사용자는 response
를 받게 되었다.
하지만 아직 사용자는 에러 메세지를 직접 볼수 없는 상태이다.
사용자에게 오류 메세지를 바로 띄울수 있는게 훨씬 좋을 거다.
한 가지 방법은 에러 메세지를 보내주는 건데 그 메세지를 upload template
으로 보내는 거다.
그럼 바로 보내주도록 한다.
videoController.js
에서
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
try {
await Video.create({
title: title,
description: description,
hashtags: hashtags.split(",").map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
});
return res.redirect("/");
} catch (error) {
console.log(error);
return res.render("upload", {
pageTitle: "Upload Video",
errorMessage: error._message,
});
}
};
이렇게 바꿔 준다. 터미널을 통해 보면 오류 코드는 정말 길다. 하지만 메세지는 짧다.
그 메세지를 활용해 보도록 한다.
errorMessage: error._message,
그래서 이렇게 작성 하게 되었다. 이제 upload
를 render
할때 에러 메세지도 함께 render
된다.
그리고 이제 upload.pug
로 가서
extends base.pug
block content
if errorMessage
span=errorMessage
form(method="POST")
input(placeholder="Title", requried, type="text", name="title")
input(placeholder="Description", requried, type="text", name="description")
input(placeholder="Hashtags, separated by comma.", requried, type="text", name="hashtags")
input(type="submit", value="Upload Video")
form
맨위에 이렇게 작성해준다. 보다시피 template
를 render
하고 있다.
에러 메세지는 template variable
의 행태로 보내고 있다.
그리고 다시 video
를 만들어 본다. 메세지가 표시된다~!!
에러 메세지가 포함된 template
을 render
하고 있다.
이 프로젝트에서는 이 정도에서 만족 할수도 있다.
다시 한번, 지금 에러를 다루는 걸 하고 있다.
await Video.create({
여기에 오류가 생기면 javascript
가
console.log(error);
return res.render("upload", {
pageTitle: "Upload Video",
errorMessage: error._message,
});
여기로 이동해서 에러 메세지를 출력해 주는 거다. 이제 console.log
는 필요 없으니 지워준다.
에러가 생기면 upload template
는 다시 render
되서 사용자는 form
을 다시 보게 된다.
하지만 전과는 달리 에러 메세지와 함계 표시 될거다.
에러 메세지는 mongoose
가 만들어준 에러 메세지와 동일하다.
그리고 그 메세지는 실수를 했을 때만 표시가 된다.
하지만 그 상태에서 upload
를 다시 해보면 에러가 없는 template
을 render
하고 있다.
왜냐하면 template
을 render
하는 controller
가 postUpload
가 아닌 getUpload
이기 때문이다.
일단 거기까지는 에러가 없다. 그럼 여기를 좀 정리하고 새로운 에러를 또(?) 만들어 본다.
video.js
에서 보면
createdAt: { type: Date, required: true },
createdAt
는 required
여야 하지만 매번 이렇게 하고 싶지 않다고 해보자.
수 많은 model
에 각각 이렇게 해줘야 한다면 너무 고통 스러울 거다.
그래서 createdAt
에 default
값을 설정해 주는 거다.
createdAt: { type: Date, required: true, default: Date.now },
이렇게 작성 하지 않는것이 중요한 포인트이다.
createdAt: { type: Date, required: true, default: Date.now() },
이렇게 적으면 function
을 즉각 실행 시킬건데 그걸 원하지 않는다.
그래서 위에 처럼 function
을 빼 준다.
그리고 Mongoose
와 mongoDB
가 똑똑해서 video
를 만들면 mongoose
가 알아서 처리해 준다.
createdAt: Date.now(),
이 코드와 동일 한 것이다. 그러나 매번 이렇게 작성 해서 실행 시키고 싶지 않다.
그래서 default
값을 정해 주는 거다. 그리고 다시 말하지만 ()
를 빼는 이유는
바로 실행 시키고 싶지 않기 때문이다.
mongoose
는 새로운 video
를 생성했을 때만 실행 시킬거다.
이제 에러를 정확히 찾고 처리하는지 또는 video
가 제대로 생성 되는지 확인해 보도록 한다.
아무 문제 없이 생성 된걸 확인 할수 있다.
mongo
로 가서 db.videos.find()
를 쳐보면 많은 종류의 video
를 확인 할수 있다.
그리고 videoController.js
에서 보면
meta: {
views: 0,
rating: 0,
},
이렇게 되어 있는 부분이 보일 텐데 이 부분도 마음에 안 든다.
지워 준 다음 video.js
로 가서
meta: {
views: { type: Number, default: 0, required: true },
rating: { type: Number, default: 0, required: true },
},
required
는 default
값이 있으면 약간 쓸모가 없지만 그래도 써준다.
이걸로 인해 이 부분도 중복해서 쓰지 않아도 된다.
이제 또(?) 에러를 만들어 보자.
보다시피 새로운 걸 적용 할수록 코드가 짧아지고 있어서 좋은 코드가 되어 간다.
title
과 description
에도 required
를 부여 할수 있다.
title: { type: String, required: true },
description: { type: String, required: true },
이 두 항목은 string
이라 다른 코드를 추가 해줄수 있는데
예를 들어 title
의 최대 길이를 100자로 설정 할수 있다.
또는 최소 열 단어 또는 스무자 이상이어야 한다고 설정 할수 있다.
내 마음에 드는 대로 다 바꿔 줄수도 있다.
이번 파트에서 한걸 되짚어 보면 먼저 에러를 일부러 만들었다.
원래 createdAt
코드가 마음에 안 들었다. 하지만 해당 코드가 required
이고 default
가 없어서
catch
에 대해 배울 수 있었다. 그 덕에 에러 메세지를 template
을 render
해서 보낼 수 있게 되었다.
template
는 정상일때 getUpload
가 render
하고 에러가 있는 경우에는 에러 메세지와 함께 render
된다.
try
와 catch
도 배웠다.
기억할게 있다. await
되는 코드에 오류가 있다면 javascript
는 더 이상 코드를 실행 시키지 않는다.
그렇기에 try
를 넣었고 그 덕에 javascript
는 try
한 뒤 catch
할 거다.
catch
가 없다면 서버는 그냥 아무것도 안하게 될거다.
그러니 try
와 catch
는 꼭 같이 붙여줘야 한다.