TIL 20일차 - node.js 입문주차 강의실습

박찬웅·2023년 2월 25일
0

항해99

목록 보기
25/105

23년 2월 25일

대부분 스파르타에서 제공된 강의노트를 위주를 참고해서 정리했으며, 보다 더 자세한 코드는 강의 노트를 참고이며, 오늘의 TIL는 거의다 실습 내용이라 거의 정보보단 일기장 방식으로 적었습니다.

배운 것

오늘은 mongoDB를 다운 받고, node패키지 중 하나인 mongoose를 설치하였다. 또한 studio 3T를 통해서 데이터가 잘 들어왔는지도 실습을 하였다. 그 뒤로 기본 강의 실습을 끝나면 git에 올려보기도 하였으며, 커밋 푸시 연습을 해 보았고, 내가 만든 파일들을 git에다 올렸다. 마지막으로 git 올린 것들을 aws ec2 들어가서 인스턴스 생성을 하고 배포하는 과정도 진행하였다.

시도 한 것

오전에는 mongoDB를 설치하였다. 아무 생각 없이 최신 버전인 6.0.4을 설치했다가 환경변수까지 완벽하게 했는데도 자꾸 실행이 안되었다. 나중에 팀원 한분이 5.0.15를 다시 받아보라고 해서 그것을 받고 덮어 쓰니까 정상적으로 되었다. 이걸로 오전에 설치하는데만 시간이 거의 다 지나갔다. 그리고 패키지인 mongoose는 어제 express 패키지 다운 받는것처럼 npm istall mongoose 하면 자연스럽게 패키지 설치 가능하였다. 그리고 나서 studio 3T도 무난히 받고 사전 준비 작업만 하고 점심이 지났다.

점심이 지나고 나서 본격적으로 moogoose를 통해서 API를 만들기 시작하였다. 강의 노트를 자주 참고했었지만 중간에 철자나 온점을 반점으로 치는 실수해서 오류 나서 오류 해결하는데 힘들었었다.


그리고 나서 최종적으로 다음과 같은 폴더와 파일을 만들고 실습을 진행하였다. 물론 위에 routes는 이번 프로젝트에선 전혀 필요 없었던 것이였는데 모르고 같이 파일 넣고 실습을 하였다.

const express = require('express');
const app = express();
const port = 3000;

// 라우터 연결
const goodsRouter = require("./routes/goods.js");
const cartsRouter = require("./routes/carts.js");

// 웹 서버에서 MongoDB에 연결
const connect = require("./schemas");
connect();

app.use(express.json());
// localhost:3000/api -> goodsRouter, cartsRouter
app.use("/api", [goodsRouter, cartsRouter]);

// app.post("/", (req,res) => {
//   console.log(req.body);

//   res.send("URI에 POST 메소드가 정상적으로 실행되었습니다.");
// });

// app.get("/", (req,res) => {
//   console.log(req.query);
  // 첫번째 방법
  // const obj = {
  //   "KeyKey" : "value 입니다.",
  //   "이름입니다.":"이름일까요?",
  // }
  
  // 두번째 방법
  // res.json({
  //   "KeyKey" : "value 입니다.",
  //   "이름입니다.":"이름일까요?",
  // });

  // 요청 실패 했을 때
//   res.status(400).json({
//     "KeyKey" : "value 입니다.",
//     "이름입니다.":"이름일까요?",
//   });
// });

// app.get("/:id", (req,res) => {
//   console.log(req.params);

//   res.send(": id URI에 정상적으로 반환되었습니다.");
// });

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(port, '포트로 서버가 열렸어요!');
});

첫번째 파일은 app.js로 서버를 실행하기 위한 코드들이다. 당연히 해당 파일로 node.js로 실행을 해야 했기 때문에, 위에 루트 경로도 설정하였다. 중간에 주석 처리 한게 엄청 많은데 이거는 어제 실습 했던 express 공부 했던걸 나중에 복습하거나 개인과제 할때 보존하기 위해서 남겨놓았다.

const express = require("express");
const cart = require("../schemas/cart.js");
const router = express.Router();

// /routes/goods.js
// 상품 목록 리스트
const goods = [
  {
    goodsId: 4,
    name: "상품 4",
    thumbnailUrl:
      "https://cdn.pixabay.com/photo/2016/09/07/02/11/frogs-1650657_1280.jpg",
    category: "drink",
    price: 0.1,
  },
  {
    goodsId: 3,
    name: "상품 3",
    thumbnailUrl:
      "https://cdn.pixabay.com/photo/2016/09/07/02/12/frogs-1650658_1280.jpg",
    category: "drink",
    price: 2.2,
  },
  {
    goodsId: 2,
    name: "상품 2",
    thumbnailUrl:
      "https://cdn.pixabay.com/photo/2014/08/26/19/19/wine-428316_1280.jpg",
    category: "drink",
    price: 0.11,
  },
  {
    goodsId: 1,
    name: "상품 1",
    thumbnailUrl:
      "https://cdn.pixabay.com/photo/2016/09/07/19/54/wines-1652455_1280.jpg",
    category: "drink",
    price: 6.2,
  },
];

//상품 목록 조회 API
router.get("/goods", (req, res) => {
  res.json({ goods: goods });
});

//상품 상세 조회 API
router.get("/goods/:goodsId", (req, res) => {
const { goodsId } = req.params;
        
  // 첫번째 방법 (구버전이라 코드가 조금 다르나 형태는 동일)
  // let result = null;
  // for(const good of goods) {
  //     if(Number(goodsId) === good.goodsId) {
  //         result = good;
  //     }
  // }

// 두번째 방법 (수정안)
const [detail] = goods.filter((goods) => goods.goodsId === Number(goodsId));
  res.json({ detail });
});

// 장바구니에 상품 추가 API
const Cart = require("../schemas/cart.js")
router.post("/goods/:goodsId/cart", async(req, res) => {
  const {goodsId} = req.params;
  const {quantity} = req.body;

  const existCarts = await Cart.find({goodsId});
  if (existCarts.length) {
    return res.status(400).json({
      success:false,
      errorMessage:"이미 장바구니에 해당하는 상품이 존재합니다.",
    });
  }

  await Cart.create({goodsId, quantity});

  res.json({result: "success"});
});

// 장바구니의 상품 수량 수정 API
router.put("/goods/:goodsId/cart", async(req, res) =>{
  const {goodsId} = req.params;
  const {quantity} = req.body;

  const existCarts = await Cart.find({goodsId});
  if(existCarts.length) {
    await Cart.updateOne(
      {goodsId: goodsId},
      {$set: {quantity:quantity}}
    )
  }

  res.status(200).json({success:true});
});

// 장바구니의 상품 수량 수정 API에서 수량을 1미만으로 정했을때 400 오류 뜨게 하기 (퀴즈 추가 내용)
// router.put("/goods/:goodsId/cart", async (req, res) => {
//   const { goodsId } = req.params;
//   const { quantity } = req.body;

//   if (quantity < 1) {
//     res.status(400).json({ errorMessage: "수량은 1 이상이어야 합니다." });
//     return;
//   }

//   const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
//   if (existsCarts.length) {
//     await Cart.updateOne({ goodsId: Number(goodsId) }, { $set: { quantity } });
//   }

//   res.json({ success: true });
// });

// 장바구니의 상품 제거 API
router.delete("/goods/:goodsId/cart", async(req, res) => {
  const {goodsId} = req.params;

  const existCarts = await Cart.find({goodsId});
  if(existCarts.length) {
    await Cart.deleteOne({goodsId});
  }

  res.json({result:"success"});
});

// 상품 생성 API
const Goods = require("../schemas/goods.js");
router.post("/goods/", async (req, res) => {
	const { goodsId, name, thumbnailUrl, category, price } = req.body;

  const goods = await Goods.find({ goodsId });

  if (goods.length) {
    return res.status(400).json({
      success: false, 
      errorMessage: "이미 있는 데이터입니다."
    });
  }

  const createdGoods = await Goods.create({ goodsId, name, thumbnailUrl, category, price });

  res.json({ goods: createdGoods });
});

module.exports = router;

두번째 파일은 routes 폴더 안에 있는 good.js 파일이다. 해당파일은 상품을 관리하기 위한 코드들이 있으면 이를 통해서 상품 조회, 상품 생성, 상품 변경, 상품 삭제 등등 CURD 방식으로 다양하게 구현을 해 보왔다. 주석 처리 한 것은 나중에 QUIZ로 추가하는 내용이였으나 배포를 고려해서 이거는 비활성 하였다.

const express = require("express");
const router = express.Router();

const Cart = require("../schemas/cart.js");
const Goods = require("../schemas/goods.js");

// 장바구니 조회 API
// localhost:3000/api/carts GET Method
router.get("/carts", async(req,res) =>{
    const carts = await Cart.find({}); // 1. 장바구니에 있는 모든 데이터 찾기
    // [
    // {goodId, quantity},
    // {goodId, quantity},
    // ];
    // 2. 그 장바구니 안에 있는 모든 상품에 대한 아이디를 찾기
    const goodsIds = carts.map((cart) =>{
        return cart.goodsId;
    })
    // [2, 11, 19];
    // 3. 그 상품의 아이디를 통해서 해당 상품들에 대한 상세 정보를 가져옴
    const goods = await Goods.find({goodsid: goodsIds});

    // 4. Goods에 해당하는 모든 정보를 가지고 올건데,
    // 만약 goodsIds 변수 안에 존재하는 값일 때에만 조회하라.
    const results = carts.map((cart) => {
        return {
            "quantity": cart.quantity,
            "goods": goods.find((item) => item.goodsId === cart.goodsId),
        }
    })

    res.json({
        "carts": results,
    })

});

module.exports = router;

세번째 파일은 역시 routes 폴더 안에 있는 cart.js 파일이다. 해당 파일은 장바구니에 담은 상품들을 조회하는 API를 작성을 하였다.

// 웹 서버에서 MongoDB에 연결
const mongoose = require("mongoose");

const connect = () => {
  mongoose
    .connect("mongodb://127.0.0.1:27017/spa_mall") // 에러가 뜨면 주소 다음과 같이 변경
    .catch(err => console.log(err));
};

mongoose.connection.on("error", err => {
  console.error("몽고디비 연결 에러", err);
});

mongoose.set("strictQuery", false); // 에러가 뜨면 다음 같은 코드 한줄 추가하면 해결된다.

module.exports = connect;

네번째 파일은 schemas 폴더 안에 있는 index.js 파일이다. 해당 파일은 moogoose패키지와 Studio 3T 프로그램을 통해 웹 서버에 연결이 되게 하는 코드를 작성하였다.
다만 이 파일은 오늘 코드 적은 것 중 가장 깊은 사연이 있었는데 강의노트와 영상을 따라서 했는데도 계속 서버 연결 실패가 나왔었다. 400 에러 조차도 안나오고 그냥 node app.js 실행해도 오류로 아예 서버 접속도 안되었다. 나중에 팀원 한분이 다음과 같이 주소를 다음과 같이 바꾸고, 그런 다음에 아래 코드 한줄을 추가로 작성하면 정상적으로 서버 실행이 되었다. 덕분에 두번째였던 큰 위기를 지나갔었다.

const mongoose = require("mongoose");

// 상품 모델 작성
const goodsSchema = new mongoose.Schema({
  goodsId: {
    type: Number,
    required: true,
    unique: true
  },
  name: {
    type: String,
    required: true,
    unique: true,
  },
  thumbnailUrl: {
    type: String,
  },
  category: {
    type: String
  },
  price: {
    type: Number,
  }
});

module.exports = mongoose.model("Goods", goodsSchema);

다섯번째 파일은 schemas 폴더 안에 있는 goods.js 파일이다. 해당 파일은 상품들의 데이터를 어떤 기준으로 데이터를 만들지 정하였다.

const mongoose = require("mongoose");

// 장바구니 모델 작성
// 어떤 상품을 담았고, 몇개를 담았는지 설정
const cartSchema = new mongoose.Schema({
  goodsId: {
    type: Number,
    required: true,
    unique: true
  },
  quantity: {
    type: Number,
    required: true,
  }
});

module.exports = mongoose.model("Cart", cartSchema);

마지막 파일은 schemas 폴더 안에 있는 carts.js 파일이다. 해당 파일은 장바구니 담은 상품들의 데이터를 어떤 상품을 담았고, 몇개를 담았는지 설정하였다.

이렇게 해서 코드를 다 작성하고 서버를 실행한 뒤 thunder client로 여러가지 요청을 받는 get, 요청을 전달하는 post, 정보를 수정하는 pop, 정보를 삭제하는 delete로 총 4가지 방식으로 실습을 하였고 모두 정상적으로 실행 되었었다.

이제 최종적으로 완성되어서 github에 올리는 작업을 시작하였다. 물론 첫주에 프로젝트 하면서 하기는 했지만 거의 대충 아는 선에서 끝나서 git 연습을 하였다. 근데 터미널로 자꾸 실행하니까 뭔가 코드를 잘못 정한건지 에러가 엄청 많이 나타나게 되었다. 결국은 나중에 터미널로 하지는 않고 vscode 자체적으로 커밋 푸시 할 수 있는 기능이 있는데 이걸로 통해서 github로 내가 지금까지 파일을 업로드 하였다. 물론 그 뒤로 수정하고 커밋 및 푸시도 더 해보았다.

그렇게 git까지 마무리 되고 저녁을 먹고 마지막으로 배포하기 위해 aws 홈페이지에 접속 후 ec2에 들어가서 인스턴스를 생성하였다. 이거는 바로 지난 웹개발 종합반 5주차에서 미리 배운 적이 있어서 인스턴스 생성은 금방하였다. 다만 차이점이라면 그 당시에는 파이선이였고 이번에는 자바 스크립트 파일들이기 때문에 접속하는 방식이 달랐다. 그래서 차이점만 말하자면 github에 있는 내가 만든 파일을 가지고 실행하는 방식이였다. 그래서 파일질라가 젼혀 필요가 없었고 git 파일들을 통해서 받았다.
그런 다음에 git bash에다 설치하는게 역시 달랐는데, node.js와 mongodb를 설치를 하는 것이였다. 마지막으로 영구적으로 git bash를 꺼도 내 도메인이 돌아가게 하기 위해서 shdo를 통해 관리자로 접속 후 npm install -g pm2를 통해서 pm2를 입력해 설치 후 pm2 start app.js 작성하면 영구적으로 홈페이지가 돌아가는것을 알 수 있었다. 영구적으로 돌아가는 방법도 역시 기존과 다른 코드를 입력하면 가능하지만 배포 과정이였기 때문에 이 과정은 생략하였다.

그리고 최종적으로 완성이 되었지만 가비아를 통해서 도매인 구입해서 적용하는것은 하지 않았다. 이것도 역시 웹종반 5주차때 배웠던거라 다 알고 있었기 때문에 이 과정 역시 생략하였다.

해결

그렇게 오늘을 끝으로 기본적인 강의를 모두 다 들었고, 실습을 마친 후 깃허브에 파일들을 올리고 배포까지 하는 과정을 마무리 하였다.
내가 완성한 코드들은 나의 깃허브 링크로 들어가서 확인 할 수 있다.
스파몰 연습 프로젝트 보러 가기

알게 된 점

이렇게 오늘까지 기본으로 제공한 강의를 모두 들었다. 사실 오늘까지 포함해서 이틀동안 무리를 해서 최대한 진도를 뺐는데, 이렇게 해야 돌아오는 월요일부터 개인 과제 실습을 여유 있게 할 수 있기 때문에 오늘까지 무리해서 진도를 빼서 엄청 머리가 잘 안돌아갔었다. 그래도 결국에는 끝내 강의 완주를 해서 좋았다. 물론 강의를 따라 적은 코드들을 완벽하게 이해는 아직 못하였지만 결국에는 무사히 git에다 올리고 배포까지 마무리 하였다.
아침부터 설치를 잘못해서 오전동안 끙끙했었고, 오후부터 본격적인 코드 실습 할 때 도 중간에 실수를 많이 해서 어디가 틀렸는지 찾는데 애를 많이 먹었었다. 늦은 오후에 내가 만든 파일을 올리기 위해 git 커밋 푸시 하는것도 터미널로 했는데 자꾸 막혔었다. 결국 나중에 추가적인 연습으로 터미널을 쓰지 않고 vscode 자체 제공하는 커밋 푸시 기능이 있었는데 그걸로 git을 올리는 것으로 마무리 하였다. 터미널을 이용해서 git 사용 하는 방법은 계속해서 공부해야한다는 것을 알게 되었다.

앞으로 할 일

내일은 일요일이라 WIL만 작성하고 푹 쉴 예정이다. 그리고 월요일부터 지금까지 한 것들을 복습하면서 본격적으로 개인 과제 실습을 수행 할 예정이다.

profile
향해 13기 node.js 백앤드

0개의 댓글