그저 내가 되었고

항해99) 3주차:: 주특기 입문; 장바구니 전체 코드(JS) 본문

개발/항해99 9기

항해99) 3주차:: 주특기 입문; 장바구니 전체 코드(JS)

hyuunii 2022. 10. 3. 16:33

주특기 입문주 학습 목표

Javascript의 기초 문법을 이해할 수 있고, 동기 비동기에 대한 설명을 할 수 있다.

상 ES6 문법의 심화까지 잘 습득했고, 동기 비동기에 대한 설명도 완벽하게 할 수 있다.
중 JS의 기초 문법에 대해서 숙지하고 있으나, 아직 동기/비동기의 개념에 대한 습득이 부족하다.
하 JS의 기초 문법에 대해서 숙지하고 있지 않고, 동기/비동기에 대한 이해가 부족하다.


Express.js의 Request(req), Response(res)가 무엇인지 이해할 수 있고, REST API를 구현할 수 있다.

상 Express.js의 req, res의 역할을 이해하였고, REST API를 구현할 수 있다.
중 Express.js의 req, res의 역할을 이해하고 있으나, REST API를 구현할 수 없다.
하 Express.js의 req, res에 대해 숙지하고 있지 않고, REST API를 구현할 수 없다.


Mongoose 라이브러리를 이용하여 Schema를 작성하고, MongoDB의 정보를 조회 및 삭제할 수 있다.

상 mongoose(ODM)를 이용해 MongoDB의 데이터를 활용할 수 있고, ODM을 이용했을 때 어떤 장단점이 있는지 설명할 수 있다.
중 mongoose 라이브러리를 Schema를 설계할 수 있고, MongoDB의 데이터를 활용할 수 있다.
하 mongoose의 Schema에 대한 이해가 부족하다.


AWS Web Console을 이용하여 EC2를 생성할 수 있고, Express.js 서버를 배포할 수 있다.

상 AWS EC2를 이용해 Express.js 서버를 배포할 수 있고, 보안그룹이 어떤 역할을 하는지 설명할 수 있다.
중 AWS EC2를 생성하거나 보안 그룹을 설정할 수 있고, Express.js 서버를 배포할 수 있다.
하 AWS EC2에 대한 이해가 부족하다.

 

 

 

 

app.js //메인 부품이라고 생각. 여기에 모듈같은 작은 부품들을 붙일거임.

더보기
const express = require('express');
const app = express();
const port = 3000;
app.listen(port, () => {
    console.log(port, '포트로 서버가 열렸어요!');
});

const connect = require("./schemas");  //connect라는 변수로 require로 ./schemas의 모듈 갖고 올 것. 노드에서는 모듈 갖고 올 때 폴더 이름까지만 지정해줘도 자동적으로 index 파일 갖고올 수 있음
connect();

//하단의 middleware가 app.use("/api", [goodsRouter]) 보다 위에 작성되어야 합니다. 미들웨어는 순차적으로 거쳐가기 때문
app.use(express.json());

const goodsRouter = require("./routes/goods.js");
app.use("/api", [goodsRouter]);


//res.json? 실제로 응답으로 들어가는 것.
app.get('/', (req, res) => {
    console.log(req.query);
    //res.send('안녕!!!!')

    const obj = {
        "key": "value",
        "이름": "이름?",
    }

    res.json(obj);  //json이란 문법 통해 반환. 얘는 단순하게 객체 형태로 바로 넣어도 됨(위의 const obj) 글고!!! 변수로 const obj 만드는게 아니라.. 그냥 json( )여기 괄호 안에 저 obj 뒤의 { }부분 전부 갖다 넣어도 됨~!!
    //글고 지금 json 형태로 반환하면 기본적으로 status200인데, 오류가 난 것 처럼 표시하고싶다?
    // res.status(400).json({
    //     "key": "value",
    //     "이름": "이름?",
    // }); //이렇게 써주면 됨~!
});

//router 쓰지 않고 바로 TEST
app.get('/', (req, res) => {  //기본 url에 들어왔을 때 동작하는 API 만들기~!
    console.log(req.query);  //req에 들어온, 즉 query string으로 전달 받은 데이터를 query를 변수에 할당 안하고 바로 출력한다..
    res.send("반환완료쓰~!");  //res.send로 결과값 반환
});

//const cartsRouter = require("./routes/carts");
app.use("/api", [goodsRouter]);

//req.body는 post 메소드 때 제일 많이 씀니다.
app.post('/', (req, res) => {  //기본 url에 호출하는 함수에여
    console.log(req.body);  //실제 body에 들어온 데이터를 확인할거구여
    res.send('기본 URI에 POST 메소드가 정상 실행되었어요~!')
})

//req.params
app.get("/:id", (req, res) => {  //id라는 params 받도록 만듦. req, res 객체 써서 함수 만든다!!
    console.log(req.params);  //req.params를 출력할거고
    res.send(":id URI에 정상 반환되었어요~!")
})

 

/routes/goods.js

1. 상품 목록 조회 API

2. 장바구니 목록 조회 API

3. 상품 상세 조회 API

4. 장바구니의 상품 제거 API

5. 장바구니의 상품 수량 수정 API

6. 상품 생성 API

7. 장바구니에 상품 추가 API

더보기
// routes/goods.js 
const express = require('express');
const router = express.Router();

router.get("/goods", (req, res) => {   //상품 목록 조회 API
    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,
        },
    ];
    res.json({goods: goods});
});

router.get("/goods/cart", async (req, res) => { //이전까지는 장바구니 목록 조회만 /api/carts 경로로 API 제공
//여기서 장바구니 목록 조회도 /api/goods/cart 경로로 제공할 수 있도록 변경.
//cart 리소스가 goods리소스에 의존하는 데이터라는걸 간접적으로 표현한 것
    const carts = await Cart.find();
    const goodsIds = carts.map((cart) => cart.goodsId);
    const goods = await Goods.find({goodsId: goodsIds});
    res.json({
        carts: carts.map((cart) => ({
            quantity: cart.quantity,
            goods: goods.find((item) => item.goodsId === cart.goodsId),
        })),
    });
});

router.get("/goods/:goodsId", (req, res) => {  //상품 상세 조회 API
    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,
        },
    ];
//const goodsId = req.params.goodsId; 파라미터 내의 goodsId를 꺼내는 것. 원래 이렇게 했는데 얘를 좀 더 다르게 하려면!!
    const {goodsId} = req.params;  //params 안의 goodsId는 오브젝트라서 객체 구조 분해 할당을 해서 간단하게 처리하면 됨! 위의 주석 처리한 const goodsId랑 얘랑은 똑같지만, 이번엔 객체 구조 분해 할당을 사용하는 것~! 이렇게 URL 파라미터에 들어온 데이터를 {goodsId}라는 변수에 할당했드아
    const [detail] = goods.filter((item) => {
        item.goodsId === Number(goodsId)
    });  //입력받은 굿즈 id와 일치하는 것들을 필터링하는 API를 만들겠으~! 근데 지금 goods가 array 형식으로 되어 있으니까,, 진짜로 filter 메쏘드 쓴 것~~!ㅋㅋ goods 안의 데이터들을 item으로 정의하고, 입력받은 req.params의 goodsId와(string으로 들어오니까 num처리 한 후) 그 item의 goodsId가 정확히 같은지 췤췤해서 detail이란 변수에 할당한다!!
    res.json({"detail": detail});  //이 detail 변수 내의 정보를 json으로(detail이라는 key값 이용해서) 변환합니다유. 즉! 우리가 확인한 하나의 데이터(특정 id 한개)만 detail이란 key값의 value로 반환한다~!
})

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

    const existsCarts = await Cart.find({goodsId});
    if (existsCarts.length > 0) {
        await Cart.deleteOne({goodsId});
    }

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

router.get('/', (req, res) => {
    res.send('goods 기본 url입니다.');
});

router.get('/:goodId', (req, res) => {
    const goodId = req.params.goodId;
    res.json({goodId: goodId});
});

router.put("/goods/:goodsId/cart", async (req, res) => {  //장바구니의 상품 수량 수정 API
    const {goodsId} = req.params;
    const {quantity} = req.body;
    const existsCarts = await Cart.find({goodsId: Number(goodsId)});
    if (existsCarts.length) {
        if (quantity >= 1) {
            await Cart.updateOne({goodsId: Number(goodsId)}, {$set: {quantity}});
        } else {
            return res.status(400).json({success: false, errorMessage: "1개 이상을 설정해주시겠어요?"});
        }
    }

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

//상품 생성 API
const Goods = require("../schemas/goods");  //스키마 선언한 굿즈 스키마 가져와서 굿즈라는 변수에 할당한 굿즈를 실제로 API 동작시 사용할 것
router.post("/goods", async (req, res) => {
    const {goodsId, name, thumbnailUrl, category, price} = req.body;  //post 메소드로 요청 했을 때 body에 데이터가 있었다면 있는 데이터를 객체 구조 분해 할당을 통해 가지고 오란 것(내부에 들어갈 데이터는 저렇게 goodsId부터 4개)
    const goods = await Goods.find({goodsId});  //데이터 조회는 find 명령어 씀. goodsId에 해당하는 값이 존재하는지에 대해서 확인한 후, 그 값이 있거나 없거나 무조건 goods란 변수에 할당.
    if (goods.length) {  //만약 goods란 변수에 데이터가 존재한다면
        return res.status(400).json({success: false, errorMessage: "이미 있는 데이터입니다."});  //만약 데이터 삽입 전 동일 데이터가 존재하는것을 확인 했었다면 status 400번 코드로, json 형식으로 반환할 것.
    }  //goods라는 데이터가 똑같이 존재하지 않는다면 goods란 스키마를 통해서 데이터를 생성할 것. goodsId, name 등등 이런걸 통해서 데이터 생성하고 생성된 데이터를 createdGoods에 할당해서
    const createdGoods = await Goods.create({goodsId, name, thumbnailUrl, category, price});
    res.json({goods: createdGoods});  //res.json 형식으로 이런 goods가 생성되었다고 반환
});

//장바구니에 상품 추가 API 작성
const Cart = require("../schemas/cart");
router.post("/goods/:goodsId/cart", async (req, res) => {
    const {goodsId} = req.params;
    const {quantity} = req.body;
    const existsCarts = await Cart.find({goodsId: Number(goodsId)});
    if (existsCarts.length) {
        return res.json({success: false, errorMessage: "이미 장바구니에 존재하는 상품입니다."});
    }
    await Cart.create({goodsId: Number(goodsId), quantity: quantity});
    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;

 

routes/users.js

더보기
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

 

 

schemas/cart.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/goods.js

더보기
//실제 상품 모델 작성. 몽고디비에선 스키마를 작성한다고 함. 굿즈라는 파일에서 굿즈라는 스키마 작성.

const mongoose = require("mongoose");

const goodsSchema = new mongoose.Schema({  //몽구스에 스키마를 새롭게 정의한다는 뜻
    goodsId: {  //내부의 이렇게 하나하나 중괄호들이 들어가는 스키마!! 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/index.js (mongoose를 이용해 데이터베이스에 연결)

더보기
const mongoose = require("mongoose");  //mongoose 라이브러리 가져와서 connect

const connect = () => {
    mongoose
        .connect("mongodb://localhost:27017/sparta_prac")  //여기에 연결하고 sparta_prac이란 db에 연결한다
        .catch(err => console.log(err));  //connect가 실패(몽고db에 연결 실패)하면 에러처리 진행(콘솔로그로 발생한 에러 보여주세요~!)
};

mongoose.connection.on("error", err => console.error("몽고디비 연결 에러", err));  //몽구스 커넥션 실패하면 콘솔 에러로 보여줌

module.exports = connect;  //현재 모듈에서 connect를 내보내줘서 밖에서 mongodb랑 연결하고 사용할 수 있게 해 줌