PJH's Shopping Mall - DataBase

λ°•μ •ν˜ΈΒ·2022λ…„ 12μ›” 28일

Shopping Project

λͺ©λ‘ 보기
7/11
post-thumbnail

πŸš€ Start

이제 λ°μ΄ν„°λ² μ΄μŠ€μ— μ‹€μ œ 데이터λ₯Ό λ„£κ³ , μ„œλ²„μ—μ„œ 데이터λ₯Ό 잘 λΆˆλŸ¬μ˜€λŠ”μ§€ ν™•μΈν•˜μž.

βœ… μš°μ„ , JSON 데이터λ₯Ό μ €μž₯ν•˜μ—¬, 정상적인 데이터 전솑이 μ΄λ£¨μ–΄μ§€λŠ”μ§€ 보자.

JSON은 데이터λ₯Ό μ €μž₯ν•˜κ±°λ‚˜ 전솑할 λ•Œ 많이 μ‚¬μš©λ˜λŠ” κ²½λŸ‰μ˜ DATA κ΅ν™˜ν˜•μ‹μœΌλ‘œ, μžλ°”μŠ€ν¬λ¦½νŠΈ 객체의 ν˜•μ‹μ„ 기반으둜 λ§Œλ“€μ–΄μ‘Œλ‹€.

MySQLκ³Ό 같은 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œλ„ JSON ν˜•νƒœλ‘œ 데이터가 μ €μž₯λ˜λ―€λ‘œ, 이번 κΈ°νšŒμ— μˆœμˆ˜ν•˜κ²Œ JSON DBλ₯Ό ν˜•μ„±ν•˜μ—¬ 데이터λ₯Ό μ–΄λ–»κ²Œ κΊΌλ‚΄ μ“°κ³ , μ—…λ°μ΄νŠΈν•˜λŠ”μ§€ μ•Œμ•„λ³΄μž.

μ°Έκ³ ν•˜μž!
πŸ‘‰ [JSON] JSON μ΄λž€ 무엇인가? 간단 정리 및 예제λ₯Ό ν†΅ν•œ μ‚¬μš© 방법
πŸ‘‰ JSON 기초
πŸ‘‰ 거의 λͺ¨λ“  SW 개발의 ν•„μˆ˜β‹―JSON 데이터 포맷의 이해



πŸ“‘ DB Controller

βœ… JSON λ°μ΄ν„°λ² μ΄μŠ€μ˜ μ–΄λ–€ 데이터λ₯Ό, μ–΄λ–»κ²Œ μ²˜λ¦¬ν•  것인지, μ»¨νŠΈλ‘€λŸ¬κ°€ ν•„μš”

  • readDB : 데이터λ₯Ό μ‘°νšŒν•  경우 ν•΄λ‹Ή ν•¨μˆ˜ μ‹€ν–‰

    • JSON.parse: JSON λ¬Έμžμ—΄μ„ JS객체둜 λ³€ν™˜(μ°Έκ³ )

    • fs.readFileSync: κ²½λ‘œμ— λ”°λ₯Έ λ™κΈ°νŒŒμΌλ‘œλΆ€ν„° 데이터λ₯Ό μ½μ–΄μ˜¬ 수 μžˆλ‹€.
      단, utf8둜 λͺ…μ‹œν•˜μ—¬ 인코딩이 λ˜λ„λ‘ν•΄μ€˜μ•Όν•œλ‹€.(μ°Έκ³ )

  • writeDB : 데이터λ₯Ό μˆ˜μ •ν•  경우 ν•΄λ‹Ή ν•¨μˆ˜ μ‹€ν–‰

    • JSON.stringfy: JS객체λ₯Ό JSON λ¬Έμžμ—΄λ‘œ λ³€ν™˜

    • fs.writeFileSync: κ²½λ‘œμ— λ”°λ₯Έ λ™κΈ°νŒŒμΌμ— 데이터λ₯Ό μ“Έ 수 μžˆλ‹€.

// src/dbController.ts
import fs from "fs";
import { resolve } from "path";

export enum DBField {
  CART = "cart",
  PRODUCTS = "products",
}

const basePath = resolve(); // __dirname

const filenames = {
  [DBField.CART]: resolve(basePath, "src/db/cart.json"),
  [DBField.PRODUCTS]: resolve(basePath, "src/db/products.json"),
};

export const readDB = (target: DBField) => {
  try {
    return JSON.parse(fs.readFileSync(filenames[target], "utf-8"));
  } catch (err) {
    console.log(err);
  }
};

export const writeDB = (target: DBField, data: any) => {
  try {
    fs.writeFileSync(filenames[target], JSON.stringify(data));
  } catch (err) {
    console.log(err);
  }
};

βœ… readDB Setting

// src/ index.ts
const server = new ApolloServer({
    typeDefs: schema,
    resolvers,
    context: {
      db: {
        products: readDB(DBField.PRODUCTS),
        cart: readDB(DBField.CART),
      },
    },
  });

βœ… readDB Setting

// src/resolvers/cart.ts
const setJSON = (data: Cart) => writeDB(DBField.CART, data);


πŸ‘• Product


βœ”οΈ JSON DB

βœ… src에 db 폴더λ₯Ό μƒμ„±ν•˜κ³ , mocking Dataλ₯Ό 갖고와 JSONν˜•μ‹μœΌλ‘œ 직접 데이터λ₯Ό μ €μž₯.

// src/db/products.json
[
  {
    "id": "1",
    "imageUrl": "http://placeimg.com/640/480/1",
    "price": 50000,
    "title": "μž„μ‹œμƒν’ˆ-1",
    "description": "μž„μ‹œμƒμ„Έλ‚΄μš©-1"
  },
  {
    "id": "2",
    "imageUrl": "http://placeimg.com/640/480/2",
    "price": 50000,
    "title": "μž„μ‹œμƒν’ˆ-2",
    "description": "μž„μ‹œμƒμ„Έλ‚΄μš©-2"
  },
  {
    "id": "3",
    "imageUrl": "http://placeimg.com/640/480/3",
    "price": 50000,
    "title": "μž„μ‹œμƒν’ˆ-3",
    "description": "μž„μ‹œμƒμ„Έλ‚΄μš©-3"
  },
  ...
]


βœ”οΈ Query

그럼 이제 JSON DB에 μžˆλŠ” μƒν’ˆλ“€μ„ μ‘°νšŒν•΄λ³΄μž.

βœ… Products

// src/resolvers/products.ts
const productResolver: Resolver = {
  Query: {
    products: async (parent, args, { db }, info) => {
      return db.products;
    },
    ...
    },
  },
};

πŸ’‘ Product JSON DB에 μ‘΄μž¬ν•˜λŠ” 20개의 μƒν’ˆ 데이터 쑰회

βœ… Product

// src/resolvers/products.ts
const productResolver: Resolver = {
  Query: {
     ...
     product: async (parent, { id }, { db }) => {
      const found = db.products.find((item) => item.id === id);
      if (found) return found;
      return null;
    },
    },
  },
};

πŸ’‘ Product JSON DB에 μ‘΄μž¬ν•˜λŠ” idκ°€ 2인 μƒν’ˆμ„ 쑰회



βœ”οΈ Mutation




πŸ›’ Cart


βœ”οΈ JSON DB

βœ… src에 db 폴더λ₯Ό μƒμ„±ν•˜κ³ , mocking Dataλ₯Ό 갖고와 JSONν˜•μ‹μœΌλ‘œ 직접 데이터λ₯Ό μ €μž₯.

  • μž₯λ°”κ΅¬λ‹ˆμ— 2개의 μƒν’ˆμ΄ μžˆλŠ” 것을 κ°€μ •μœΌλ‘œ 데이터 자μž₯.
// src/db/cart.json
[
  { "id": "1", "amount": 1 },
  { "id": "2", "amount": 1 }
]


βœ”οΈ Query

그럼 이제 JSON DB에 μžˆλŠ” μž₯λ°”κ΅¬λ‹ˆμ— μ‘΄μž¬ν•˜λŠ” μƒν’ˆλ“€μ„ μ‘°νšŒν•΄λ³΄μž.

// src/resolvers/products.ts
const cartResolver: Resolver = {
  Query: {
    cart: async (parent, args, { db }, info) => {
      return db.cart;
    },
  },
  ...
}

πŸ’‘ Cart JSON DB에 μ‘΄μž¬ν•˜λŠ” μž₯λ°”κ΅¬λ‹ˆ μƒν’ˆ 데이터 쑰회



βœ”οΈ Mutation

βœ… μž₯λ°”κ΅¬λ‹ˆ 데이터λ₯Ό μ—…λ°μ΄νŠΈν•΄λ³΄μž.

  • μž₯λ°”κ΅¬λ‹ˆμ— μƒν’ˆμ„ μΆ”κ°€ (add)
  • μž₯λ°”κ΅¬λ‹ˆμ˜ μƒν’ˆ μˆ˜λŸ‰ μˆ˜μ • (update)
  • μž₯λ°”κ΅¬λ‹ˆμ—μ„œ μƒν’ˆ μ‚­μ œ (delete)
  • μž₯λ°”κ΅¬λ‹ˆμ˜ μƒν’ˆ κ²°μ œν•˜κΈ° (execute)

πŸ‘‰ Add

// src/resolvers/cart.ts
const cartResolver: Resolver = {
  Mutation: {
     addCart: (parent, { id }, { db }, info) => {
      if (!id) throw Error("μƒν’ˆidκ°€ μ—†μŠ΅λ‹ˆλ‹€");
      const targetProduct = db.products.find((item) => item.id === id);
      if (!targetProduct) throw new Error("μƒν’ˆμ΄ μ—†μŠ΅λ‹ˆλ‹€");

      const existCartIndex = db.cart.findIndex((item) => item.id === id);
      if (existCartIndex > -1) {
        const newCartItem = {
          id,
          amount: db.cart[existCartIndex].amount + 1,
        };
        db.cart.splice(existCartIndex, 1, newCartItem);
        setJSON(db.cart);
        return newCartItem;
      }
      const newItem = {
        id,
        amount: 1,
      };
      db.cart.push(newItem);
      setJSON(db.cart);
      return newItem;
    },
  },
  CartItem: {
    product: (cartItem, args, { db }) =>
      db.products.find((product) => product.id === cartItem.id),
  },
};

πŸ’‘ Cart JSON DB에 μ‘΄μž¬ν•˜λŠ” μž₯λ°”κ΅¬λ‹ˆ μƒν’ˆ 데이터 쑰회

πŸ’‘ cart.json에 idκ°€ 3인 μƒν’ˆμ΄ μΆ”κ°€λœ 것을 확인!



πŸ‘‰ Update

// src/resolvers/cart.ts
const cartResolver: Resolver = {
  Mutation: {
     updateCart: async (parent, { id, amount }, { db }) => {
      const existCartIndex = db.cart.findIndex((item) => item.id === id);
      if (existCartIndex < 0) {
        throw new Error("μƒν’ˆμ΄ μ—†μŠ΅λ‹ˆλ‹€");
      }
      const newCartItem = {
        id,
        amount,
      };
      db.cart.splice(existCartIndex, 1, newCartItem);
      setJSON(db.cart);
      return newCartItem;
    },
  CartItem: {
    product: (cartItem, args, { db }) =>
      db.products.find((product) => product.id === cartItem.id),
  },
};

πŸ’‘ Cart JSON DB에 μ‘΄μž¬ν•˜λŠ” idκ°€ 3인 μƒν’ˆμ˜ amountλ₯Ό 5둜 μˆ˜μ •

πŸ’‘ cart.json에 idκ°€ 3인 μƒν’ˆμ˜ μˆ˜λŸ‰μ΄ 5κ°€ 된 것을 확인!



πŸ‘‰ Delete

// src/resolvers/cart.ts
const cartResolver: Resolver = {
  Mutation: {
     deleteCart: async (parent, { id }, { db }) => {
      const existCartIndex = db.cart.findIndex((item) => item.id === id);
      if (existCartIndex < 0) {
        throw new Error("μƒν’ˆμ΄ μ—†μŠ΅λ‹ˆλ‹€");
      }
      db.cart.splice(existCartIndex, 1);
      setJSON(db.cart);
      return id;
    },
  CartItem: {
    product: (cartItem, args, { db }) =>
      db.products.find((product) => product.id === cartItem.id),
  },
};

πŸ’‘ Cart JSON DB에 μ‘΄μž¬ν•˜λŠ” idκ°€ 3인 μƒν’ˆμ„ μ‚­μ œ

πŸ’‘ cart.json에 idκ°€ 3인 μƒν’ˆ μ‚­μ œ 확인!



πŸ‘‰ Execute

// src/resolvers/cart.ts
const cartResolver: Resolver = {
  Mutation: {
   executePay: (parent, { ids }, { db }) => {
      const newCartData = db.cart.filter((cartItem) => {
        !ids.includes(cartItem.id);
      });
      db.cart = newCartData;
      setJSON(db.cart);
      return ids;
    },
  CartItem: {
    product: (cartItem, args, { db }) =>
      db.products.find((product) => product.id === cartItem.id),
  },
};

πŸ’‘ Cart JSON DB에 μ‘΄μž¬ν•˜λŠ” idκ°€ 2인 μƒν’ˆμ„ 결제



πŸ–₯ Client to DB

이제 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ DB의 데이터λ₯Ό λ°›μ•„μ˜€λŠ” 것을 κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€.
μ§€κΈˆκΉŒμ§€λŠ” μ„œλ²„μ™€ APIκ°€ μƒμ„±λ˜κΈ° 이전에 MSWλ₯Ό 톡해 λͺ¨μ˜ 톡신을 ν•˜λ©° 데이터 νŒ¨μΉ­μ„ ν•˜μ˜€λ‹€.

βœ… μ΄μ œλŠ” μ•žμ„œ λ§Œλ“  JSON DB의 데이터λ₯Ό 가져와 좜λ ₯ν•΄λ³΄μž.

  • 이미 μ„œλ²„μ™€μ˜ 톡신은 MSWλ₯Ό 톡해 λͺ¨μ˜ 톡신을 해놓은 μƒνƒœμ΄κΈ° λ•Œλ¬Έμ—, κ°€μ§œ 데이터듀을 λΆˆλŸ¬μ˜€λŠ” URL이 μ•„λ‹Œ, μ„œλ²„ URL을 Base Url둜 μ„€μ •ν•˜μ—¬ JSON DB의 데이터듀을 λΆˆλŸ¬μ˜¨λ‹€.
// gueryClient.ts

//λ³€κ²½ μ „
const BASE_URL = "https://fakestoreapi.com"

// λ³€κ²½ ν›„
const BASE_URL = "http://localhost:8000";

πŸ’‘ CORS Error

ν•œκ°€μ§€ μ£Όμ˜ν•  점은 Vite 3.0μ—μ„œ λ‘œμ»¬ν˜ΈμŠ€νŠΈκ°€ 5173으둜 작히기 λ•Œλ¬Έμ—, Serverμ—μ„œ cors origin 섀정을 3000번이 μ•„λ‹Œ 5173으둜 ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€!

βœ… μ‹€μ œ 데이터λ₯Ό 뢈러였고, μž₯λ°”κ΅¬λ‹ˆμ˜ 데이터λ₯Ό 직접 μˆ˜μ •ν•˜λ‹ˆ, JSON DBμ—μ„œλ„ μ‹€μ‹œκ°„μœΌλ‘œ λ³€κ²½λ˜λŠ” 것을 확인할 수 μžˆλ‹€.



profile
κΈ°λ‘ν•˜μ—¬ κΈ°μ–΅ν•˜κ³ , κ³„νšν•˜μ—¬ μ‹€μ²œν•˜μž. will be a FE developer (HOMEλ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ Notion으둜 λ†€λŸ¬μ˜€μ„Έμš”!)

0개의 λŒ“κΈ€