그저 내가 되었고
항해99) 3주차:: 주특기 입문; 개인과제 전체 코드(JS) 본문
Directory Structure
.
├── app.js
├── routes
│ ├── index.js
│ ├── comments.js
│ └── posts.js
└── schemas
├── index.js
├── comment.js
└── post.js
app.js
//express 프레임웤 구동. express는 노드로 서버를 빠르고 간편하게 만들 수 있게 도와주는 웹 프레임웤!!
const express = require('express'); // express 프레임웤을 express란 변수에 담고
const app = express(); //app이란 변수에!!!! 그 express 프레임웤을 할당!!! 그러면 일반적 서버 사용 위한 app 객체 생성됨~!
//서버 구동은 전부 객체를 참조한다.
const connect = require("./schemas/index"); //connect라는 변수로 schemas의 모듈 갖고 올 것(저기에 원래 저렇게 /index라고 적어줘서 index만 갖고오려고 하는 것1!!! 근데 걍 schemas까지만 적어줘도.. 폴더 이름까지만 적어주면 자동적으로 갖고오니까 안의 index 알아서 찾아서 보여줌. connect 이름은 그냥 알아보기 쉽게 하는거고.. 뭐 네가 aaa하든 bbb하든 밑에 aaa();만 잘 맞춰주면 알아서 잘 돌아감ㅋ
connect(); //위에서 require( )모라는 함수를 connect에 할당해줬고, connect변수는 함수를 품고 있으니까 저렇게만 적어줘도 함수 실행 가능~!
// const abc = (a, b) => { return a + b}
// console.log(abc(1, 2));
//함수...???????
app.use(express.json()); //왜 굳이 데이터가 제이슨 형식이어야 하는지?...ㅜㅜ req~res 중간에 middleware가 들어감. 모듈이 미들웨어가 될 수 있다. req.body를 파싱하려 사용함. 그래서 주석해도 get은 잘 돌아감. app.use는 미들웨어를 거쳐가도록!!!!!! 하는 app객체의 use함수.
const postsRouter = require("./routes/posts"); //라우츠 파일에서 내보낸 라우터를 할당함
const commentsRouter = require("./routes/comments");
app.use("/api", [postsRouter, commentsRouter]); //반환받은 각각의 라우터를 익스프레스에다가 적용시키기. 익스프레스라는건 프레임워크? 지금 만들고있는 서버에 적용시킨다는 뜻인건가? ㅇㅇ 도구에다가 잘 적용해주는겨ㅎ... 그 도구가 알아서 서버가 잘 만들어주고있좌나,,,, 그릉까
//app.use라는 문법 통해서 적용시킬건데(API를 등록시킬건데), app.use는 app이라는 익스프레스 객체에다가 전역으로 쓸거란 뜻??? app.use는 미들웨어를 거쳐가도록!!!!!! 하는 app 객체의 use 함수.
//기본 url 접속시 respond. 이것도 라우터를 통해 기본url에 대한 라우팅을 한 것이라고 볼 수 있음. 지금까지는 app.get과 같이 http method로 만들었다고 한다면, 나머지는 router로!!
app.get('/', (req, res) => { ////기본 url(/)에 req와 res를 받아서 실행하는 api를 만드는 것
res.send('반가워용✨😎!');
});
//포트 열어줌
const port = 3002;
app.listen(port, () => {
console.log(port, '포트로 서버가 열렸어요!');
});
routes/posts.js
const express = require('express'); //express 프레임웤 설치 후 express라는 변수에 담고
const router = express.Router(); //express안의 라우터 함수를 실행해서 그 결괏값을 라우터라는 변수에 할당. 실제로 api를 만들거나 라우터를 생성할 때는 이렇게 router라는 변수를 통해 사용한당!
const Posts = require("../schemas/post.js"); //post.js라는 스키마 파일을 Posts로 갖고온다~!
//두 가지 역할을 하는 것? 데이터 모델링 & 이미 db에 저장된것 다 불러오는?
//1. 전체 게시글 목록 조회 API
router.get("/posts", async (req, res) => { //위에서 반환 받은 라우터라는 변수로 라우터 만들기. 기본 url 말고 추가적인 경로로 실행하는 API &&& req(API에 받은 데이터)랑 res 객체 받아서 실행할게~!
//function 앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환. 자바스크립트는 await 키워드를 만나면 프라미스가 처리될 때까지 기다림. 결과는 그 이후 반환됨.
const item = await Posts.find().sort({updatedAt: -1}) //await에서 데이터가 올때까지 기다리게 함. find하고 sort하는 데이터가.. await나 async가 안걸려있으면? 먼저 나온 데이터는 먼저 쭉쭉 가버림. 여럿이 밥먹고 한명씩 나가는거 아니고 한명씩 다 가게,,, 데이터가 점점 더 많아진다는 가정 하에 필요한 것. 사용자가 많아지게되면 서버 부하가 되고 data양도 늘어서 볼륨이 커지니까 처리시간 길어지고ㅇㅇ
//동기는 요청을 보낸 후 해당하는 응답을 받아야만 다음으로 넘어갈 수 있는 실행방식이고
// 반대로 비동기는 요청을 보낸 후에 응답과 관계없이 다음 동작을 실행할 수 있는 방식입니다.
//JS는 원래 동기!!! 그래서 async, await 사용해서 비동기처럼 작동하게끔 해 주는 것.
const mapItem = item.map((item) => {
return {
postId : item._id,
writer : item.writerName,
title : item.title,
content : item.contents,
createdAt : item.createdAt
}
})
res.json({item: mapItem}); //mapItem으로 받은 get메소드 리턴값을 반환할 res 객체
});
//params 안의 goodsId는 오브젝트라서 객체 구조 분해 할당을 해서 간단하게 처리하면 됨! 위의 주석 처리한 const goodsId랑 얘랑은 똑같지만, 이번엔 객체 구조 분해 할당을 사용하는 것~! 이렇게 URL 파라미터에 들어온 데이터를 {goodsId}라는 변수에 할당했드아
//2. 게시글 상세 조회 API
router.get("/posts/:_postId", async (req, res) => {
const {_postId} = req.params; //위의.. url 뒷편의 :(콜론) 뒷부분의 것 받아옴(이름 똑같이 적어줘야됨!!(_postID 그대로!!) 특정 url 뒤의 모든 데이터는 매개변수로 보며, 그 매개변수를 단지 받아올 뿐)
//아니 이 앞뒤 {중괄호}의 의미가 뭐임⁉⁉⁉⁉⁉ 없으면 왜 결과가 비어서 나옴?????
//중괄호를 씌워줘서 { _postId: '633d58cc0f1fd4cfa7037402' }이렇게 나옴. 안씌우고 그냥 콘솔에 찍으면 633d58cc0f1fd4cfa7037402 번호만 띡 나옴.
//첨에 구조 분해 할당을 안하면 변수.tilte, 변수.contents이런식으로 불러와야되니까... 받아오면서 사전에 분해해서 깔아두는 것. 안그러면 일일이 객체 안에서 ㅊㄹ력해와야됨.
console.log(_postId)
// console.log(1+true)
// console.log({_postId})
// console.log(req.params)
const item = await Posts.find(); //데이터 조회는 find 명령어 씀.
//console.log(item)
const filteredPosts = item.filter((x) => { //이 filter의 문법?
// console.log( x["_id"].toString())
return x["_id"].toString() === _postId; //[_id]이거는 key값 이용해서 value 뽑는다는것은 알겠음. 그러면... 이게, 큰 객체 안에->배열 안에->객체 하나(그 안에 postId부터 다섯개 요소?)가 뽑힌다는건.. 생성할때 그렇게 생성해줘서 아는것....? 콘솔에 찍어보면 아는것... 바로 위에서 item 찍어봤쟈나융
}); //filter가 배열의 속성 하나하나 가져와서 비교하니까..
const mapPosts = filteredPosts.map((item) => {
//console.log(item["_id"])//이거랑 밑줄의 결과가 같은데... 그냥 []든 .든 접근 방법은 상관X? ._id이게 람다식???? ㅇㅇ
//console.log(item._id)//
return { //get은 찾는 것 까지 역할이고... 결과를 보여주는건 return이 하는것?(함수니까 return을 해줘야 결과가 빠짐)(return 빼고 돌리면 null값 나옴)
postId : item["_id"],
writer : item.writerName,
title : item.title,
content : item.contents,
createdAt : item.createdAt
} //여기서 return 안에 한 객체 안에 이렇게 쭉 적어줘서 이 형태 그대로 return되는것? 그러면 따로 return하려면???(해보니까 오류남.. 방법이 없나효?) 질문💛💛💛💛💛
})
// const _postId = req.params._postId;
// const [detail] = item.filter((item) => _id === _postId);
res.json({mapPosts});
})
//3. 게시글 생성 API
router.post("/posts", async (req, res) => {
const {title, writerName, password, contents} = req.body;
//console.log(req.body) //객체구조분해할당을 해서 value값만 가져오는것
const createdPosts = await Posts.create([{title, writerName, password, contents}]);
console.log(createdPosts)
//여기 윗줄에.. [{....}]이렇게 되는것도.. 배열 안에 객체가 있다고 틀 잡아주려고? 아니 단순히 괄호 하나 집어넣는다고 자료 구조가 바뀜????????????????
//console.log({title, writerName, password, contents})
//console.log([{title, writerName, password, contents}])
const mapItem = createdPosts.map((item) => {
return {
postId : item._id,
writer : item.writerName,
title : item.title,
content : item.contents,
createdAt : item.createdAt
}
})
res.json({posts: mapItem});
})
//4. 게시글 수정 API
router.put("/posts/:_postId", async (req, res) => {
const {_postId} = req.params;
const {password, contents, title} = req.body;
const existsPost = await Posts.find({_id:_postId}); //이렇게 : 콜론 하면 앞뒤로 같다는것..? 이런 문법이 있었나?ㅠㅠㅠㅠ 이것도 앞뒤로 중괄호 없으면 오류나는데. .대체 중괄호 역할 무엇..? 긴가민가 ??? :_postID를 파라미터로 받았으면 findOne에서 하나가 나와야할텐데 왜 다른게 나옴??
//console.log(existsPosts)
//console.log(existsPost[0].password)
//console.log(existsPost[0]["password"]) //얘는 undefined고 밑에 []는 찾아짐..왜......?
if (existsPost.length) {
if (password === existsPost[0].password) {
//console.log(_postId)
await Posts.updateOne({_id: _postId}, {$set: {contents, title}});
//console.log(_postId)
} else {
return res.status(400).json({success: false, errorMessage: "패스워드를 다시 입력해주세요"});
}
} else {
return res.status(400).json({success: false, errorMessage: "찾으시는 게시물이 없어요"});
}
res.json({success: true});
})
//5. 게시글 삭제 API
router.delete("/posts/:_postId", async (req, res) => {
const {_postId} = req.params;
const existsPosts = await Posts.find({_id: _postId});
const {password} = req.body;
// console.log(existsPosts.length)
// console.log(existsPosts)
// console.log(existsPosts[0].password)
// console.log(password)
if (existsPosts.length) {
if (password === existsPosts[0].password) {
await Posts.deleteOne({_id: _postId});
} else {
return res.status(400).json({success: false, errorMessage: "패스워드를 다시 입력해주세요"});
}
} else {
return res.status(400).json({success: false, errorMessage: "찾으시는 게시물이 없어요"});
}
res.json({result: "success"});
})
module.exports = router;
routes/comments.js
const express = require('express');
const Comments = require("../schemas/comment.js");
const router = express.Router();
//1. 댓글 목록 조회
router.get("/comments/:_postId", async (req, res) => {
const {_postId} = req.params; //게시물 ID 하나하나
console.log(_postId)
const existsPosts = await Comments.find({_postId: _postId}).sort({updatedAt: -1});
//[ //find라서 배열을 뱉을것
// {
// "writerName" : "ㄷaaa",
// "password" : "0000",
// "contents" : "hhhh"
// }
// ] //20번째줄의 item은 배열 자체가 아니라 안의 요소 하나하나
const mapComments = existsPosts.map((x) => {
return {
writer: x.writerName,
contents: x.contents
}
// {
// xN : "ㄷaaa", xC :"hhhh"
// }
})
//console.log(existsPosts)
res.json({mapComments});
});
//2. 댓글 작성
router.post("/comments/:_postId", async (req, res) => {
const {_postId} = req.params;
const {writerName, password, contents} = req.body;
console.log(contents)
if (contents === "") {
//res.send ("끗")
return res.status(400).json({success: false, errorMessage: "댓글 내용을 입력해주세요"});
} else {
const createdComments = await Comments.create({_postId, writerName, password, contents});
res.json({comments: createdComments});
}
})
//3. 댓글 수정
router.put("/comments/:commentId", async (req, res) => {
const {commentId} = req.params;
const {password, contents} = req.body;
const existsComments = await Comments.findOne({_id: commentId});
// console.log(req.params)
// console.log(req.body)
// console.log(existsComments)
// console.log(password)
// console.log(existsComments.password)
if (password === existsComments.password) {
if (contents === "") {
res.status(400).json({success: false, errorMessage: "댓글 내용을 입력해주세요"});
} else {
await Comments.updateOne({_id: commentId}, {$set: {contents}});
res.send({result: "수정완료"})
}
} else {
return res.status(400).json({success: false, errorMessage: "틀린 패스워드"});
}
})
//4. 댓글 삭제
router.delete("/comments/:commentId", async (req, res) => {
const {commentId} = req.params;
const {password} = req.body;
const existsComments = await Comments.findOne({_id: commentId});
// console.log(req.params)
// console.log(req.body)
// console.log(existsComments)
// console.log(password)
// console.log(existsComments.password)
if (password === existsComments.password) {
await Comments.deleteOne({_id: commentId});
} else {
return res.status(400).json({success: false, errorMessage: "틀린 패스워드"});
}
res.json({result: "success"});
})
module.exports = router;
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
schemas/comments.js
const mongoose = require("mongoose");
const commentsSchema = new mongoose.Schema({
_postId: {
type: String
},
writerName: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
contents: {
type: String,
required: true,
},
},
{
timestamps: true
});
module.exports = mongoose.model("Comments", commentsSchema);
schemas/index.js
const mongoose = require("mongoose"); //mongoose 라이브러리 가져와서 connect(몽구스 라이브러리는 이미 우리가 설치했다!!!! 글고 그 node_modules 열어보면 몽구스 파일 있고, 걔 열어보면 몽구스를 익스포츠 해 주고 있음. 익스포츠를 어디선가 해주기때문에!!! require가 가능한 것)
const connect = () => {
mongoose
.connect("mongodb://localhost:27017/sparta_prac") //여기에 연결하고 sparta_prac이란 db에 연결한다. 아무것도 안적어주면, 알아서 몽고db가 test라고 만들어서 넣어줌.
.catch(err => console.log(err)); //connect가 실패(몽고db에 연결 실패)하면 에러처리 진행(콘솔로그로 발생한 에러 보여주세요~!)
};
mongoose.connection.on("error", err => console.error("몽고디비 연결 에러", err)); //몽구스 커넥션 실패하면 콘솔 에러로 보여줌
module.exports = connect; //현재 모듈에서 connect를 내보내줘서 밖에서 mongodb랑 연결하고 사용할 수 있게 해 줌. 이걸.. app.js에서 받아서 쓸 것 임!~!
schemas/posts.js
//포스트 모델 작성. 데이터 관리하기 위해 모듈을 작성.
const mongoose = require("mongoose"); //몽구스 라이브러리를 mongoose란 변수에 담고
const postsSchema = new mongoose.Schema({ //몽구스 스키마를 새롭게 정의할게.
title: {
type: String,
required: true,
},
writerName: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
contents: {
type: String,
required: true,
},
},
{
timestamps: true //얘는.. 몽구스 라이브러리의 객체임. 직접 입력받을 객체?는 아니고 option으로 몽구스에 저장될때 옵션으로 몽구스가 알아서 그냥 따라 붙여 줄 애임.
});
module.exports = mongoose.model("Posts", postsSchema); //몽구스 스키마를 내보낼게. 저 name으로 app.js에서 PostsRouter이 되는 것? 아니라면 name은 왜 필요??? 아앗 그게 ㅎㅎㅎㅎ 몽구스에 들어갈 때,,, db 이름이 예를들어 sparta_prac이면 그 안에!!!! 짜잘하게 posts, coments 이렇게 각각의 데이터 탭!!!! 그거 말하는것ㅎ 글고 저기 그냥 Post로 적어줘도 자동으로 posts로 바꿔서 적힌당ㅎㅎㅎㅎ
//이게 모듈이라는건... 마지막에 그냥 모듈.익스포츠 이것땜에 모듈 역할을 할 수 있는 것? ㅇㅇ마즘쓰. 글고 모듈이라는건.. 지금 이 해당하는 파일 안에만 '격리'된 애들인데 ex로 내보내줘서 re로 받으면 드디어 접근해서 쓸 수 있게 해줌.
'개발 > 항해99 9기' 카테고리의 다른 글
항해99) 4주차:: 주특기 숙련; 📚쿠키 & 세션 & JWT (0) | 2022.10.11 |
---|---|
항해99) 3주차:: 💡3주차 맺음 WIL; Restful API, package.json + 소회✍🏻 (0) | 2022.10.09 |
항해99) 3주차:: 주특기 입문; 장바구니 전체 코드(JS) (0) | 2022.10.03 |
항해99) 3주차:: 주특기 입문; 📚MongoDB → mongoose (0) | 2022.10.03 |
항해99) 3주차:: 주특기 입문; 📚Express.js (0) | 2022.10.03 |