2020.코딩일지

[DB]im-sprint-cmarket-database/Cmarket ServerAPI[#MVC패턴][BEB 6th] 본문

WebServer&DB&CTI

[DB]im-sprint-cmarket-database/Cmarket ServerAPI[#MVC패턴][BEB 6th]

개발하는라푼젤 2022. 8. 9. 21:17
728x90
코드스테이츠 블록체인 부트캠프 6기 

 

(테스트마다 다르긴한데... 이번 스프린트는 npm test시,  서버 두개 모두 켜져있어야함.)

/server/들어가서 `npm start` 노드익스프레스 서버ON   &  `mysql.server start` 데이터베이스ON

혹시나 에러가 난다면 여기

 

server/routes/index.js부분 분기추가

더보기

server/routes/index.js

const express = require("express");
const router = express.Router();
const itemsRouter = require("./items");
const usersRouter = require("./users");

// TODO: Endpoint에 따라 적절한 Router로 연결해야 합니다.
router.use("/items", itemsRouter);
router.use("/users", usersRouter);

module.exports = router;

 

server/routes/items.js

const router = require('express').Router();
const controller = require('./../controllers');

// GET /items Router와 Controller를 연결합니다.
router.get('/', controller.items.get);

module.exports = router;

 

sercer/routes/위치에 users.js파일 추가 (controllers의 index.js참고해서 수정)

더보기

sercer/routes/users.js

const router = require("express").Router();
const controller = require("./../controllers");

router.get("/:userId/orders", controller.orders.get);
router.post("/:userId/orders", controller.orders.post);

module.exports = router;

 

controllers/index.js : (models/index.js참고하여)컨트롤러 작성 ‘메소드별 예외처리 및 status’

더보기
const models = require("../models");

module.exports = {
  items: {
    get: (req, res) => {
      // * DB 접근 함수 실행 결과를 반환
      models.items.get((error, result) => {
        if (error) {
          res.status(500).send("Internal Server Error");
        } else {
          res.status(200).json(result);
        }
      });
    },
  },
  orders: {
    get: (req, res) => {
      const userId = req.params.userId;
      // TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
      if (!userId) {
        //예외처리1) userId가 없는경우
        return res.status(401).send("Unauthorized user.");
      }
      models.orders.get(userId, (error, result) => {
        //models/index.js참고하여 보내야할 인자확인
        if (error) {
          return res.status(500).send("Internal Server Error");
        }
        return res.status(200).json(result);
      });
    },
    post: (req, res) => {
      const userId = req.params.userId;
      const { orders, totalPrice } = req.body;
      // TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
      if (!userId) {
        //예외처리1) userId가 없는경우
        return res.status(401), send("Unauthorized user");
      }
      if (!orders || !totalPrice) {
        //예외처리2) 바디값이없는경우
        return res.status(400).send("Bad request");
      }
      models.orders.post(userId, orders, totalPrice, (error, result) => {
        //models/index.js참고하여 보내야할 인자확인
        if (error) {
          //에러일경우
          return res.status(500).send("Internal Server Error");
        } //정상적일경우
        return res.status(201).send("Order has been created");
      });
    },
  },
};

 

models/index.js : 쿼리문작성 (schema.sql참고하여)

 items.get으로들어오면 상품내역보여주는 쿼리문

 oders.get으로 들어오면 해당유저의 주문내용을 보여주는 쿼리문

 oders.post로 들어오면 해당유저의 주문내용을 데이터베이스에 입력하는 쿼리문

더보기

models/index.js 

const db = require("../db");
//여기는 sql문법으로 연결된 데이터베이스와 CRUD를 할 수 있도록 함수가 구현되어있는 곳
module.exports = {
  items: {
    get: (callback) => {
      // TODO: Cmarket의 모든 상품을 가져오는 함수를 작성하세요
      const queryString = `SELECT * FROM items`;

      db.query(queryString, (error, result) => {
        console.log(result);
        callback(error, result);
      });
    },
  },
  orders: {
    get: (userId, callback) => {
      // TODO: 해당 유저가 작성한 모든 주문을 가져오는 함수를 작성하세요
      const sql = `SELECT orders.id, orders.created_at, orders.total_price, items.name, items.price, items.image, order_items.order_quantity
      FROM orders 
      INNER JOIN order_items ON (orders.id = order_items.order_id)
      INNER JOIN items ON (order_items.item_id = items.id)
      WHERE (orders.user_id = ?)`;
      // WHERE (users.id =${userId});

      const params = [userId];

      db.query(sql, params, (error, result) => {
        // console.log(result);
        callback(error, result);
      });
    },

    post: (userId, orders, totalPrice, callback) => {
      // TODO: 해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성하세요(INSERT INTO입력하는것!)
      // orders: [{ quantity: 1, itemId: 2 },{ quantity: 1, itemId: 4 }]
      const sql1 = `INSERT INTO orders (user_id, total_price) VALUES (?, ?)`;
      const params = [userId, totalPrice];

      db.query(sql1, params, (error, result) => {
        if (result) {
          const sql2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`;
          let params = orders.map((el) => [
            //orders에 배열형식으로 넣기 좋은 map. [[],[]]이중배열을 만들어주기위한 []
            //😎여러개의 레코드를 한번의 쿼리로 저장하려고 이중배열형태로 만들어 bulk insert 한것이다!
            result.insertId,
            el.itemId,
            el.quantity,
          ]);
          return db.query(sql2, [params], (error, result) => {
            //이중배열을 또 묶...
            callback(error, result);
          });
        }
        callback(error, null);
      });
    },
  },
};

tables;

(참고)schema.sql

더보기

schema.sql

 
CREATE TABLE users (
  id INT AUTO_INCREMENT,
  username varchar(255),
  PRIMARY KEY (id)
);

CREATE TABLE items (
  id INT AUTO_INCREMENT,
  name varchar(255),
  price INT,
  image varchar(255),
  PRIMARY KEY (id)
);

CREATE TABLE orders (
  id INT AUTO_INCREMENT,
  user_id INT,
  total_price INT,
  created_at datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

CREATE TABLE order_items (
  id INT AUTO_INCREMENT,
  order_id INT,
  item_id INT,
  order_quantity INT,
  PRIMARY KEY (id)
);

ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users (id);

ALTER TABLE order_items ADD FOREIGN KEY (order_id) REFERENCES orders (id);

ALTER TABLE order_items ADD FOREIGN KEY (item_id) REFERENCES items (id);

/*  Execute this file from the command line by typing:
 *    mysql -u root < server/schema.sql -p -Dcmarket
 *  to create the database and the tables.*/

 

 


 

🤖 ${}달러사인으로넣는것은 sql injection공격에 대해 보호하기위해  (?,?)이렇게생긴 prepared 방식을 쓴다.  

기본적으로 유저에게 받은 값을 직접 SQL로 넘기는것${}은 위험하다.

 orders: {
    get: (userId, callback) => {
      // ..생략
      WHERE (orders.user_id = ?)`;
      const params = [userId];

 

//im-sprint-database/server/models/index.js의 예시
//--❌❌❌❌❌❌❌$달러사인방법은 비추❌❌❌❌❌❌❌
post: (userId, orders, totalPrice, callback) => {
  // TODO: 해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성하세요(INSERT INTO입력하는것!)
  // orders: [{ quantity: 1, itemId: 2 },{ quantity: 1, itemId: 4 }]
  let sql1 = `INSERT INTO orders (user_id, total_price) VALUES (${userId}, ${totalPrice})`; 

  db.query(sql1, (err, result) => {
    console.log(result);
    let sql2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`;
    let params = orders.map((el) => [
      result.insertId,
      el.itemId,
      el.quantity,
    ]);
    console.log(params);

    db.query(sql2, [params]);
    callback(err, result);
  });
},

 


 

Comments