
μ΄μ λ°μ΄ν°λ² μ΄μ€μ μ€μ λ°μ΄ν°λ₯Ό λ£κ³ , μλ²μμ λ°μ΄ν°λ₯Ό μ λΆλ¬μ€λμ§ νμΈνμ.
β μ°μ , JSON λ°μ΄ν°λ₯Ό μ μ₯νμ¬, μ μμ μΈ λ°μ΄ν° μ μ‘μ΄ μ΄λ£¨μ΄μ§λμ§ λ³΄μ.
JSONμ λ°μ΄ν°λ₯Ό μ μ₯νκ±°λ μ μ‘ν λ λ§μ΄ μ¬μ©λλ κ²½λμ DATA κ΅ννμμΌλ‘, μλ°μ€ν¬λ¦½νΈ κ°μ²΄μ νμμ κΈ°λ°μΌλ‘ λ§λ€μ΄μ‘λ€.
MySQLκ³Ό κ°μ λ°μ΄ν°λ² μ΄μ€μμλ JSON ννλ‘ λ°μ΄ν°κ° μ μ₯λλ―λ‘, μ΄λ² κΈ°νμ μμνκ² JSON DBλ₯Ό νμ±νμ¬ λ°μ΄ν°λ₯Ό μ΄λ»κ² κΊΌλ΄ μ°κ³ , μ λ°μ΄νΈνλμ§ μμ보μ.
μ°Έκ³ νμ!
π [JSON] JSON μ΄λ 무μμΈκ°? κ°λ¨ μ 리 λ° μμ λ₯Ό ν΅ν μ¬μ© λ°©λ²
π JSON κΈ°μ΄
π κ±°μ λͺ¨λ SW κ°λ°μ νμβ―JSON λ°μ΄ν° ν¬λ§·μ μ΄ν΄
β JSON λ°μ΄ν°λ² μ΄μ€μ μ΄λ€ λ°μ΄ν°λ₯Ό, μ΄λ»κ² μ²λ¦¬ν κ²μΈμ§, 컨νΈλ‘€λ¬κ° νμ
readDB : λ°μ΄ν°λ₯Ό μ‘°νν κ²½μ° ν΄λΉ ν¨μ μ€ν
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);
β 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"
},
...
]
κ·ΈλΌ μ΄μ 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μΈ μνμ μ‘°ν
β srcμ db ν΄λλ₯Ό μμ±νκ³ , mocking Dataλ₯Ό κ°κ³ μ JSONνμμΌλ‘ μ§μ λ°μ΄ν°λ₯Ό μ μ₯.
// src/db/cart.json
[
{ "id": "1", "amount": 1 },
{ "id": "2", "amount": 1 }
]
κ·ΈλΌ μ΄μ JSON DBμ μλ μ₯λ°κ΅¬λμ μ‘΄μ¬νλ μνλ€μ μ‘°νν΄λ³΄μ.
// src/resolvers/products.ts
const cartResolver: Resolver = {
Query: {
cart: async (parent, args, { db }, info) => {
return db.cart;
},
},
...
}
π‘ Cart JSON DBμ μ‘΄μ¬νλ μ₯λ°κ΅¬λ μν λ°μ΄ν° μ‘°ν
β μ₯λ°κ΅¬λ λ°μ΄ν°λ₯Ό μ λ°μ΄νΈν΄λ³΄μ.
// 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μΈ μνμ΄ μΆκ°λ κ²μ νμΈ!
// 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κ° λ κ²μ νμΈ!
// 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μΈ μν μμ νμΈ!
// 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μΈ μνμ κ²°μ
μ΄μ ν΄λΌμ΄μΈνΈμμ DBμ λ°μ΄ν°λ₯Ό λ°μμ€λ κ²μ ꡬνν΄μΌ νλ€.
μ§κΈκΉμ§λ μλ²μ APIκ° μμ±λκΈ° μ΄μ μ MSWλ₯Ό ν΅ν΄ λͺ¨μ ν΅μ μ νλ©° λ°μ΄ν° ν¨μΉμ νμλ€.
β μ΄μ λ μμ λ§λ 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μμλ μ€μκ°μΌλ‘ λ³κ²½λλ κ²μ νμΈν μ μλ€.
