node.js 03 혼공

장재원·2021년 9월 20일

REST API


  • REST(Representational State Transfer)는 월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식

  • 웹에 존재하는 모든 자원(이미지, 동영상, DB 자원)에 고유한 URI를 부여해 활용 하는 것

  • REST API의 구성

    REST API의 구성은 크게 세 가지로 이루어 집니다

    1. 자원(Resource) - URL

      • 우리가 만들 소프트웨어가 관리하는 모든 것을 자원으로 표현할 수 있습니다. 쇼핑몰이라면 상품(Goods)에 대해서 정보를 관리할것이고 또는 장바구니(Carts)에 담긴 상품들도 관리해야겠죠.
    2. 행위 - HTTP method

      • 이전에 배웠던 HTTP method 기억나시나요? GET, POST 등등이 있다고 했었는데요. 이것으로 해당 자원에 대한 행위를 표현할 수 있습니다. 예를 들어 GET 메소드는 해당 자원의 조회, POST 메소드는 해당 자원의 생성 이런 식으로요.

      • 이렇게 나누어진 것을 보통 CRUD 라고 합니다. 자원에 대한 생성/조회/수정/삭제를 각각의 method 로 나누어놓은 것이지요.

        Create : 생성(POST)
        Read : 조회(GET)
        Update : 수정(PUT)
        Delete : 삭제(DELETE)
      • 위 이미지의 예시처럼 쓰이는 것이 일반적인 method 사용방식입니다. 하지만 이것은 필수인 부분이 아니고 모든 곳에서 다 이렇게 지켜서 사용하지는 않습니다. 상황에 따라 저것을 완벽하게 지키기 어려운 부분들도 있으니 이 부분 참고 해주세요.

    3. 표현

      • 해당 자원을 어떻게 표현할지에 대한 설명입니다. 보통 JSON, XML 같은 형식을 이용해서 자원을 표현합니다.

mongoose


  • mongoose 는 mongoDB 에 연결하고 데이터 모델링을 제공해주는 툴 입니다.

  • 작동 확인

    const mongoose = require('mongoose');
    
    app.get('/mongodb', async (req, res) => {
        await mongoose.connect('mongodb://localhost/voyage', {
            useNewUrlParser: true,
    				ignoreUndefined: true
        });
    
    		res.send('ok');
    })
  • 모델링 만들고 데이터 추가하기

    • 상품 goods를 판매 시 나타나야 될 정보들

      • 상품 이미지, 상품 이름, 상품 가격, 상품의 종류(카테고리)
    • moongoose 에서는 이런 데이터를 모델링할 때 Schema 객체를 사용합니다.

       const { Schema } = mongoose;
          const goodsSchema = new Schema({
              goodsId: {
                  type: Number,
                  required: true,
                  unique: true
              },
              name: {
                  type: String,
                  required: true,
                  unique: true
              },
              thumbnailUrl: {
                  type: String
              },
              category: {
                  type: String
              },
              price: {
                  type: Number
              }
          });
      
          let Goods = mongoose.model("Goods", goodsSchema)
      
      		await Goods.create({
              goodsId: 1,
              name: "맛있는 저녁",
              thumbnailUrl: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRKRQ3NDs5bjulPr3JaXJzP7DH3Y-71WX9wzQ7N8XD9KLUHjT6L&usqp=CAc",
              category: "food",
              price: 15000
          })
  • 구조 만들기

    지금 한 route 에 기능을 다 모아놓았던 것을 api 로 쓰기 위해 구조를 변경.

    • schemas/index.js

      const mongoose = require("mongoose");
      
      const connect = () => {
        mongoose
          .connect("mongodb://localhost:27017/voyage", {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true,
            ignoreUndefined: true
          })
          .catch(err => console.log(err));
      };
      
      mongoose.connection.on("error", err => {
        console.error("몽고디비 연결 에러", err);
      });
      
      module.exports = connect;
    • schemas/goods.js

      const mongoose = require("mongoose");
      
      const { Schema } = mongoose;
      const goodsSchema = new 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);
    • index.js 파일 수정

      const connect = require("./schemas");
      connect();

GET 요청


  • api 추가하기

    • goods route 생성

      • index.js 파일에 추가

        const goodsRouter = require("./routers/goods");
        app.use("/api", [goodsRouter]);
    • router 내용 추가

      • /routers/goods.js

        router.get("/goods", async (req, res, next) => {
          try {
            const { category } = req.query;
            const goods = await Goods.find({ category }).sort("-goodsId");
            res.json({ goods: goods });
          } catch (err) {
            console.error(err);
            next(err);
          }
        });
    • 위에 코드대로 /api/goods 으로 json data 가지고 옵니다.

    • 클라이언트에게 보여 줄 부분 추가

      • /views/index.js 추가

        function get_goods(category) {
            $("#goodsList").empty()
            console.log(category)
            $.ajax({
                type: "GET",
                url: `/api/goods${category ? "?category=" + category : ""}`,
                data: {},
                success: function (response) {
                    let goods = response["goods"]
                    for (let i = 0; i < goods.length; i++) {
                        make_card(goods[i])
                    }
                }
            })
        }
  • 상세 페이지 만들기

    • router 내용 추가

      • /routers/goods.js

        router.get("/goods/:goodsId", async (req, res) => {
          const { goodsId } = req.params;
          goods = await Goods.findOne({ goodsId: goodsId });
          res.json({ detail: goods });
        });
    • 클라이언트에게 보여줄 상세페이지 부분

      • /views/detail.ejs

        function get_detail() {
                $.ajax({
                  type: "GET",
                  url: `/api/goods/${goodsId}`,
                  data: {},
                  error: function(xhr, status, error) {
                    if (status == 404) {
                      alert("존재하지 않는 상품입니다.");
                    }
                    window.location.href = "/goods";
                  },
                  success: function(response) {
                    let goodsDetail = response["detail"];
                    $("#goodsUrl").attr("src", goodsDetail["thumbnailUrl"]);
                    $("#goodsName").text(goodsDetail["name"]);
                    $("#goodsPrice").text("$" + number2decimals(goodsDetail["price"]));
        
                    sessionStorage.setItem("goodsId", goodsId);
                    sessionStorage.setItem("goodsName", goodsDetail["name"]);
                    sessionStorage.setItem("goodsPrice", goodsDetail["price"]);
                    sessionStorage.setItem("orderNum", 1);
                  }
                });
              }
profile
화이팅!!

0개의 댓글