Kết nối Backend để lưu Todo thật giúp ứng dụng Vue hoạt động như một sản phẩm thực tế, với hệ thống lưu todo vào cơ sở dữ liệu, có thể dùng được đa thiết bị và hỗ trợ đăng nhập sau này.
Mục tiêu:
- Xây dựng REST API bằng NodeJS
- Lưu dữ liệu vào MongoDB
- Kết nối từ Vue (frontend) → gọi API thay vì giả lập
- Hướng tới việc có multi-user + authentication
Phần 1: Tạo Backend với Express
1.1 Khởi tạo project Node
mkdir todo-api
cd todo-api
npm init -y
npm install express mongoose cors
1.2 File index.js
const express = require('express')
const mongoose = require('mongoose')
const cors = require('cors')
const app = express()
const port = 5000
app.use(cors())
app.use(express.json())
mongoose.connect('mongodb://localhost:27017/todoapp')
.then(() => console.log('MongoDB Connected'))
// Schema
const Todo = mongoose.model('Todo', {
title: String,
completed: Boolean,
createdAt: {
type: Date,
default: Date.now
}
})
// Routes
app.get('/todos', async (req, res) => {
const todos = await Todo.find().sort({ createdAt: -1 })
res.json(todos)
})
app.post('/todos', async (req, res) => {
const todo = new Todo(req.body)
await todo.save()
res.json(todo)
})
app.put('/todos/:id', async (req, res) => {
const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, { new: true })
res.json(todo)
})
app.delete('/todos/:id', async (req, res) => {
await Todo.findByIdAndDelete(req.params.id)
res.json({ message: 'Deleted' })
})
app.listen(port, () => {
console.log(`🚀 API running at http://localhost:${port}`)
})
Phần 2: Kết nối từ Vue (Pinia Store)
Cập nhật file:
src/store/todoStore.js
import { defineStore } from 'pinia'
const API_URL = 'http://localhost:5000/todos'
export const useTodoStore = defineStore('todo', {
state: () => ({
todos: [],
loading: false,
error: null
}),
actions: {
async fetchTodos() {
this.loading = true
try {
const res = await fetch(API_URL)
this.todos = await res.json()
} catch (e) {
this.error = 'Lỗi kết nối backend'
} finally {
this.loading = false
}
},
async addTodo(title) {
const res = await fetch(API_URL, {
method: 'POST',
body: JSON.stringify({ title, completed: false }),
headers: { 'Content-Type': 'application/json' }
})
const data = await res.json()
this.todos.unshift(data)
},
async deleteTodo(id) {
await fetch(`${API_URL}/${id}`, { method: 'DELETE' })
this.todos = this.todos.filter(t => t._id !== id)
},
async toggleTodo(id) {
const todo = this.todos.find(t => t._id === id)
const res = await fetch(`${API_URL}/${id}`, {
method: 'PUT',
body: JSON.stringify({ ...todo, completed: !todo.completed }),
headers: { 'Content-Type': 'application/json' }
})
const updated = await res.json()
todo.completed = updated.completed
}
}
})
Lưu ý MongoDB:
- Bạn cần MongoDB local (
mongodb://localhost:27017
) hoặc dùng MongoDB Atlas (miễn phí) - Dùng môi trường
.env
để ẩn thông tin nhạy cảm nếu deploy
Bạn đã học được:
Kỹ năng Backend | Mục đích |
---|---|
Express Router | Tạo API RESTful |
Mongoose | Giao tiếp với MongoDB |
CORS + JSON Body | Kết nối frontend Vue |
Kết nối API thật | Dữ liệu lưu được, dùng đa thiết bị |
Bài tập mở rộng:
- Thêm field
userId
để phân biệt người dùng - Triển khai token-based auth (JWT)
- Triển khai project này lên:
- Backend: Render / Railway / Vercel
- Frontend: Netlify / Firebase Hosting
Thảo luận