iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0
自我挑戰組

《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》系列 第 18

Day18 - 持續成長學習藍圖 - Node.js(小作品_Todo API 整合)

  • 分享至 

  • xImage
  •  

經過 Day 13 ~ Day 17 的努力,我已經學會:

  • 用 Express 寫 CRUD API
  • 連接 MongoDB / PostgreSQL
  • 錯誤處理與日誌紀錄

今天的任務就是把這些東西整合起來,做出一個完整的 Todo API 小作品 🚀


1. 專案架構

todo-api/
├── app.js
├── db.js
├── models/
│   └── Todo.js   (如果用 MongoDB)
├── package.json
└── README.md

2. app.js

這是核心 API 程式:

import express from "express";
import morgan from "morgan";
import { pool } from "./db.js"; // 如果要用 PostgreSQL
// import { connectDB } from "./db.js"; // 如果要用 MongoDB
// import { Todo } from "./models/Todo.js";

const app = express();
const port = 3000;

app.use(express.json());
app.use(morgan("dev"));

// ✅ PostgreSQL 版本 API
app.get("/todos", async (req, res, next) => {
  try {
    const result = await pool.query("SELECT * FROM todos ORDER BY id ASC");
    res.json(result.rows);
  } catch (err) {
    next(err);
  }
});

app.post("/todos", async (req, res, next) => {
  try {
    const { task } = req.body;
    if (!task) return res.status(400).json({ error: "task 欄位必填" });

    const result = await pool.query(
      "INSERT INTO todos (task) VALUES ($1) RETURNING *",
      [task]
    );
    res.status(201).json(result.rows[0]);
  } catch (err) {
    next(err);
  }
});

app.put("/todos/:id", async (req, res, next) => {
  try {
    const id = parseInt(req.params.id, 10);
    const { task, done } = req.body;

    const result = await pool.query(
      "UPDATE todos SET task = COALESCE($1, task), done = COALESCE($2, done) WHERE id = $3 RETURNING *",
      [task, done, id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({ error: "找不到這筆 Todo" });
    }

    res.json(result.rows[0]);
  } catch (err) {
    next(err);
  }
});

app.delete("/todos/:id", async (req, res, next) => {
  try {
    const id = parseInt(req.params.id, 10);
    const result = await pool.query("DELETE FROM todos WHERE id=$1 RETURNING *", [id]);

    if (result.rows.length === 0) {
      return res.status(404).json({ error: "找不到這筆 Todo" });
    }

    res.json(result.rows[0]);
  } catch (err) {
    next(err);
  }
});

// 全域錯誤處理
app.use((err, req, res, next) => {
  console.error("❌ 發生錯誤:", err.stack);
  res.status(500).json({ error: "伺服器錯誤,請稍後再試" });
});

app.listen(port, () => {
  console.log(`✅ Todo API 伺服器啟動:http://localhost:${port}`);
});

👉 如果用 MongoDB,可以把 pool.query 換成 Todo.find() / Todo.create() / Todo.findByIdAndUpdate() / Todo.findByIdAndDelete()


3. 測試 API

新增 Todo

curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{"task": "完成 Day 18 文章"}'

讀取所有 Todo

curl http://localhost:3000/todos

更新 Todo

curl -X PUT http://localhost:3000/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

刪除 Todo

curl -X DELETE http://localhost:3000/todos/1

4. README.md

# Todo API

一個使用 Node.js + Express 實作的簡單 Todo API。  
支援 CRUD,並可選擇 MongoDB 或 PostgreSQL 作為資料庫。

## 使用方式

安裝依賴:
```bash
npm install

啟動伺服器:

node app.js

API 介面

  • GET /todos → 取得所有 Todo
  • POST /todos → 新增一個 Todo
  • PUT /todos/:id → 更新 Todo
  • DELETE /todos/:id → 刪除 Todo

範例

curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{"task": "寫鐵人賽 Day 18"}'

🎯 學習心得 / 今日收穫

這 6 天的努力(Day 13 ~ Day 18),終於讓我完成了一個完整的 Todo API 🎉
雖然功能很基礎,但過程中我學到:

  • Express 的路由與 Middleware
  • REST API 的設計方法
  • MongoDB / PostgreSQL 的差異
  • 如何做錯誤處理與 log 紀錄
  • 把學過的東西整合成一個小專案

這讓我更有信心往後端工程師的方向邁進。


上一篇
Day17 - 持續成長學習藍圖 - Node.js(錯誤處理與日誌紀錄)
下一篇
Day19 - 持續成長學習藍圖 - TypeScript(type 與 interface)
系列文
《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言