Syw.Frontend

๐Ÿงฉ Vue 2๋กœ ๋ฐฐ์šฐ๋Š” ํ”„๋ก ํŠธ์—”๋“œ ๊ธฐ์ดˆ

1๋‹จ๊ณ„. Vue 2 + Express + Axios ์ธ์ฆ ๊ธฐ๋ฐ˜ ํˆฌ๋‘์•ฑ ๋งŒ๋“ค๊ธฐ

1-10. ์ธ์ฆ/๋ณด์•ˆ ๊ธฐ์ดˆ โ€“ ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„ ๋ฐ API ๋ณดํ˜ธ ์„ค๊ณ„

๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ

  • ์‚ฌ์šฉ์ž๋ณ„ ํ•  ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ €์žฅ/์กฐํšŒํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค.
  • ์ถ”ํ›„ ๋กœ๊ทธ์ธ ์—ฐ๋™์„ ๋Œ€๋น„ํ•˜์—ฌ ๊ธฐ๋ณธ ์ธ์ฆ ์„ค๊ณ„๋ฅผ ๊ฐ–์ถ˜๋‹ค.
  • ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ todos.json ํŒŒ์ผ์— ์˜๊ตฌ ์ €์žฅํ•œ๋‹ค.

โœ… 1. ์™œ ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„์ด ํ•„์š”ํ•œ๊ฐ€?

ํ˜„์žฌ ์„œ๋ฒ„๋Š” **๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ํ•  ์ผ ๋ชฉ๋ก(todos)**์„ ๊ณต์œ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์‹ค์ œ ์„œ๋น„์Šค์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

์š”๊ตฌ์‚ฌํ•ญ ์„ค๋ช…
์‚ฌ์šฉ์ž๋ณ„ ํ•  ์ผ ๋ถ„๋ฆฌ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์—†์–ด์•ผ ํ•จ
์ˆ˜์ •/์‚ญ์ œ ์ œํ•œ ๋ณธ์ธ์˜ ๋ฐ์ดํ„ฐ๋งŒ ์ˆ˜์ • ๊ฐ€๋Šฅํ•ด์•ผ ํ•จ
์˜์†์„ฑ ์„œ๋ฒ„ ๊บผ์กŒ๋‹ค ์ผœ๋„ ๊ฐ์ž์˜ ํ•  ์ผ ๋ชฉ๋ก ์œ ์ง€

โœ… 2. ์‚ฌ์šฉ์ž ์‹๋ณ„์ž(userId) ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ ์„ค๊ณ„

โœ”๏ธ ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„ ๋ฐฉ์‹

  • Vue ํ”„๋ก ํŠธ์—”๋“œ์—์„œ Axios ์š”์ฒญ ์‹œ๋งˆ๋‹ค userId๋ฅผ ํ•จ๊ป˜ ์ „๋‹ฌ
  • ์„œ๋ฒ„์—์„œ๋Š” userId๋ณ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜๋ˆ  ์ €์žฅ (todosByUser[userId])

โœ”๏ธ ์ €์žฅ ๊ตฌ์กฐ ์˜ˆ์‹œ (todos.json)

{
  "abc123": [
    { "id": 1, "title": "์‚ฌ์šฉ์ž A์˜ ํ•  ์ผ" }
  ],
  "def456": [
    { "id": 2, "title": "์‚ฌ์šฉ์ž B์˜ ํ•  ์ผ" }
  ]
}

โœ… 3. ์„œ๋ฒ„ ์ฝ”๋“œ: routes/todos.js (์ตœ์ข…)

const express = require('express')
const fs = require('fs').promises
const path = require('path')
const router = express.Router()

const DATA_FILE = path.join(__dirname, '../data/todos.json')
let todosByUser = {}

// ๐Ÿ“‚ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
const loadTodos = async () => {
  try {
    const data = await fs.readFile(DATA_FILE, 'utf-8')
    todosByUser = JSON.parse(data)
    console.log('โœ… todos.json ๋กœ๋“œ ์™„๋ฃŒ')
  } catch {
    todosByUser = {}
    console.log('๐Ÿ“ ์ƒˆ todos.json ์‹œ์ž‘')
  }
}

// ๐Ÿ’พ ๋ฐ์ดํ„ฐ ์ €์žฅ
const saveTodos = async () => {
  await fs.writeFile(DATA_FILE, JSON.stringify(todosByUser, null, 2))
}

// GET /todos?user=abc123
router.get('/', async (req, res) => {
  const userId = req.query.user
  if (!userId) return res.status(400).json({ message: 'userId๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค' })

  const todos = todosByUser[userId] || []
  res.json(todos)
})

// POST /todos
router.post('/', async (req, res) => {
  const { title, userId } = req.body
  if (!title || !userId) {
    return res.status(400).json({ message: 'title๊ณผ userId๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค' })
  }

  const newTodo = {
    id: Date.now(),
    title,
    completed: false
  }

  if (!todosByUser[userId]) todosByUser[userId] = []
  todosByUser[userId].unshift(newTodo)
  await saveTodos()
  res.status(201).json(newTodo)
})

// DELETE /todos/:id?user=abc123
router.delete('/:id', async (req, res) => {
  const userId = req.query.user
  const id = Number(req.params.id)

  if (!userId || !todosByUser[userId]) return res.sendStatus(204)

  todosByUser[userId] = todosByUser[userId].filter(todo => todo.id !== id)
  await saveTodos()
  res.sendStatus(204)
})

// PUT /todos/:id
router.put('/:id', async (req, res) => {
  const userId = req.body.userId
  const id = Number(req.params.id)
  const { title } = req.body

  if (!userId || !title || !todosByUser[userId]) {
    return res.status(400).json({ message: '์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ์ž…๋‹ˆ๋‹ค' })
  }

  todosByUser[userId] = todosByUser[userId].map(todo =>
    todo.id === id ? { ...todo, title } : todo
  )

  await saveTodos()
  res.sendStatus(200)
})

// ์„œ๋ฒ„ ์‹œ์ž‘ ์‹œ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
loadTodos()

module.exports = router

โœ… 4. ํด๋ผ์ด์–ธํŠธ(Vue)์—์„œ ์š”์ฒญ ๋ฐฉ์‹

const userId = 'abc123' // ์ถ”ํ›„ localStorage์—์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

// GET
axios.get(`/api/todos?user=${userId}`)

// POST
axios.post('/api/todos', { title: this.newTodo, userId })

// DELETE
axios.delete(`/api/todos/${id}?user=${userId}`)

// PUT
axios.put(`/api/todos/${id}`, { title: newTitle, userId })

โœ… 5. ์œ ์ง€๋˜๋Š” ํŒŒ์ผ ์˜ˆ์‹œ (data/todos.json)

{
  "abc123": [
    { "id": 1721383512188, "title": "Vue ํ•™์Šต", "completed": false },
    { "id": 1721383469384, "title": "Express ์—ฐ๋™", "completed": false }
  ],
  "def456": []
}

๐Ÿง  ์š”์•ฝ

ํ•ญ๋ชฉ ์„ค๋ช…
์‚ฌ์šฉ์ž ๊ตฌ๋ถ„ ๋ฐฉ์‹ ๋ชจ๋“  ์š”์ฒญ์— userId ํฌํ•จ
์„œ๋ฒ„ ์ €์žฅ ๊ตฌ์กฐ todosByUser[userId]๋กœ ๋ถ„๋ฆฌ
์˜์†ํ™” JSON ํŒŒ์ผ(todos.json)๋กœ ์ €์žฅ/๋ถˆ๋Ÿฌ์˜ค๊ธฐ
๋ณด์•ˆ ์ค€๋น„ ์ถ”ํ›„ ๋กœ๊ทธ์ธ + ์ธ์ฆ ํ† ํฐ์œผ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ

FE ์ €์žฅ์†Œ

GitHub - heroyooi/vue2-app at ch10

BE ์ €์žฅ์†Œ

GitHub - heroyooi/vue2-api at ch10

๐Ÿ’ฌ ๋Œ“๊ธ€

    โ€ป ๋กœ๊ทธ์ธ ํ›„ ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.