บทที่ 1backend|14 KB

บทที่ 1: พื้นฐาน Node.js และ Express Framework

บทที่ 1: พื้นฐาน Node.js และ Express Framework

🎯 เป้าหมายการเรียนรู้

หลังจากเรียนบทนี้แล้ว คุณจะสามารถ:

  • เข้าใจว่า Node.js คืออะไร และทำไมถึงเหมาะกับการพัฒนา Backend
  • สร้าง REST API Server ด้วย Express Framework
  • เข้าใจ Middleware Pattern และการใช้งาน
  • จัดการ Environment Variables ด้วย dotenv
  • ตั้งค่า CORS และ Security Headers

📚 ทฤษฎีและแนวคิด

Node.js คืออะไร?

Node.js คือ JavaScript Runtime ที่ทำงานนอก Browser โดยใช้ V8 Engine (เครื่องมือที่ Google Chrome ใช้รัน JavaScript) ทำให้เราสามารถเขียน JavaScript เพื่อสร้าง Backend Server ได้

ข้อดีของ Node.js:

  • ✅ ใช้ JavaScript ทั้ง Frontend และ Backend (Full-stack JavaScript)
  • ✅ Non-blocking I/O ทำงานได้เร็วและรองรับ Concurrent Requests ได้มาก
  • ✅ มี NPM (Node Package Manager) ที่มี Library มากมาย
  • ✅ เหมาะกับ Real-time Applications (Chat, Notifications)

Express Framework คืออะไร?

Express คือ Web Framework สำหรับ Node.js ที่ช่วยให้การสร้าง Web Server และ API ง่ายขึ้น

ฟีเจอร์หลัก:

  • 🔹 Routing (จัดการ URL paths)
  • 🔹 Middleware (ประมวลผล Request ก่อนถึง Route Handler)
  • 🔹 Request/Response Handling
  • 🔹 Template Engine Support

💻 โค้ดจริงจาก QUOM App

มาดูโค้ดจากไฟล์ backend/src/server.js กัน:

1. Import Dependencies (นำเข้า Libraries)

import express from "express";
import cors from "cors";
import morgan from "morgan";
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";

อธิบายแต่ละบรรทัด:

  • import express from "express"

    • นำเข้า Express Framework เพื่อสร้าง Web Server
  • import cors from "cors"

    • นำเข้า CORS (Cross-Origin Resource Sharing) เพื่อให้ Frontend จาก Domain อื่นเรียก API ได้
  • import morgan from "morgan"

    • นำเข้า Morgan สำหรับ Logging (บันทึก HTTP Requests)
  • import dotenv from "dotenv"

    • นำเข้า dotenv เพื่ออ่านค่าจากไฟล์ .env (Environment Variables)
  • import path from "path"

    • นำเข้า path module สำหรับจัดการ file paths
  • import { fileURLToPath } from "url"

    • ใช้แปลง URL เป็น file path (จำเป็นใน ES Modules)

2. Load Environment Variables

dotenv.config();

คำอธิบาย:

  • เรียกใช้ dotenv.config() เพื่อโหลดค่าจากไฟล์ .env เข้าสู่ process.env
  • ตัวอย่างไฟล์ .env:
    PORT=4010
    MONGODB_URI=mongodb://localhost:27017/quom
    JWT_SECRET=your-secret-key
    

3. Connect to Database

import { connectDB } from "./config/db.js";

try {
  await connectDB();
} catch (err) {
  console.error("❌ DB Connection Failed:", err.message);
}

คำอธิบาย:

  • เรียกฟังก์ชัน connectDB() เพื่อเชื่อมต่อกับ MongoDB
  • ใช้ try-catch เพื่อจัดการ Error หากเชื่อมต่อไม่สำเร็จ
  • await หมายความว่ารอให้การเชื่อมต่อเสร็จก่อนทำงานต่อ

4. Create Express Application

const app = express();

คำอธิบาย:

  • สร้าง Express Application instance
  • app คือตัวแปรที่เราจะใช้ตั้งค่า Routes, Middleware ต่างๆ

5. Apply Middleware

5.1 Morgan Logger

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

คำอธิบาย:

  • ใช้ Morgan เพื่อ log HTTP requests ในรูปแบบ "dev"
  • ตัวอย่าง output:
    GET /api/notes 200 45.123 ms - 1234
    

5.2 JSON Body Parser

app.use(express.json({ limit: "2mb" }));

คำอธิบาย:

  • แปลง Request Body ที่เป็น JSON ให้เป็น JavaScript Object
  • กำหนด limit ที่ 2MB เพื่อป้องกัน Request ขนาดใหญ่เกินไป
  • หลังจากใช้ middleware นี้ เราสามารถเข้าถึง req.body ได้

6. CORS Configuration (สำคัญมาก!)

const allowed = (process.env.CORS_ORIGIN || "")
  .split(",")
  .map(s => s.trim())
  .filter(Boolean);

app.use(
  cors({
    origin: function (origin, cb) {
      // Allow non-browser clients (curl, Postman) with no Origin
      if (!origin) return cb(null, true);

      // ✅ Allow any localhost port
      const isLocalhost =
        origin.startsWith("http://localhost:") ||
        origin.startsWith("http://127.0.0.1:");

      if (isLocalhost) return cb(null, true);

      // ✅ Allow explicitly whitelisted origins from env
      if (allowed.length === 0 || allowed.includes(origin)) 
        return cb(null, true);

      return cb(new Error("CORS blocked: " + origin));
    },
    credentials: true,
  })
);

คำอธิบาย Step-by-Step:

  1. อ่านค่า CORS_ORIGIN จาก .env

    const allowed = (process.env.CORS_ORIGIN || "")
      .split(",")           // แยกด้วย comma
      .map(s => s.trim())   // ตัด whitespace
      .filter(Boolean);     // เอาค่าว่างออก
    
  2. Custom Origin Function

    • origin: URL ของ Frontend ที่ส่ง Request มา
    • cb: Callback function เพื่อบอกว่าอนุญาตหรือไม่
  3. กรณีที่อนุญาต:

    • ไม่มี origin (เช่น Postman, curl)
    • localhost ทุก port (สำหรับ Development)
    • Origins ที่ระบุใน CORS_ORIGIN
  4. credentials: true

    • อนุญาตให้ส่ง Cookies และ Authorization Headers

7. Static Files Serving

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

app.use(
  "/uploads",
  express.static(path.join(__dirname, "..", process.env.UPLOAD_DIR || "uploads"))
);

คำอธิบาย:

  • fileURLToPath(import.meta.url): แปลง URL เป็น file path
  • path.dirname(__filename): ได้ directory path ของไฟล์นี้
  • express.static(): Serve static files (รูปภาพ, PDF, etc.)
  • เมื่อเข้า http://localhost:4010/uploads/image.jpg จะได้ไฟล์จากโฟลเดอร์ uploads

8. Health Check Endpoint

app.get("/api/health", (req, res) => 
  res.json({ ok: true, service: "QUOM API" })
);

app.get("/", (req, res) => 
  res.send("QUOM Backend is running! 🚀<br>Port: " + (process.env.PORT || "Unknown"))
);

คำอธิบาย:

  • app.get(path, handler): กำหนด Route สำหรับ HTTP GET
  • req: Request object (ข้อมูลที่ Client ส่งมา)
  • res: Response object (ใช้ส่งข้อมูลกลับ)
  • res.json(): ส่ง JSON response
  • res.send(): ส่ง HTML/Text response

9. API Routes

import { authRouter } from "./routes/auth.js";
import { notesRouter } from "./routes/notes.js";
import { chatRouter } from "./routes/chat.js";
import { userRouter } from "./routes/user.js";
import { adminRouter } from "./routes/admin.js";
import { passwordResetRouter } from "./routes/password-reset.js";

app.use("/api/auth", authRouter);
app.use("/api/notes", notesRouter);
app.use("/api/chat", chatRouter);
app.use("/api/user", userRouter);
app.use("/api/admin", adminRouter);
app.use("/api/password-reset", passwordResetRouter);

คำอธิบาย:

  • แยก Routes ออกเป็นไฟล์ต่างๆ เพื่อความเป็นระเบียบ
  • app.use(path, router): Mount router ที่ path ที่กำหนด
  • ตัวอย่าง: Request ไป /api/auth/login จะถูกจัดการโดย authRouter

10. Error Handler Middleware

import { errorHandler } from "./middleware/errorHandler.js";

app.use(errorHandler);

คำอธิบาย:

  • Error Handler ต้องอยู่ ท้ายสุด หลังจาก Routes ทั้งหมด
  • จะจับ Errors ที่เกิดขึ้นจาก Routes และส่ง Response ที่เหมาะสม

11. Start Server

const port = process.env.PORT || 4010;
app.listen(port, () => 
  console.log(`🚀 QUOM Backend running on :${port}`)
);

คำอธิบาย:

  • app.listen(port, callback): เริ่ม Server ที่ port ที่กำหนด
  • ใช้ port จาก Environment Variable หรือ 4010 เป็นค่า default
  • Callback จะทำงานเมื่อ Server พร้อมรับ Requests

🔄 Flow Diagram: Request Lifecycle

Client Request
    ↓
CORS Middleware → ตรวจสอบ Origin
    ↓
Morgan Logger → บันทึก Request
    ↓
JSON Parser → แปลง Body เป็น Object
    ↓
Route Matching → หา Route ที่ตรงกับ URL
    ↓
Route Handler → ประมวลผล Request
    ↓
Send Response → ส่งข้อมูลกลับ Client
    ↓
Error Handler → จัดการ Error (ถ้ามี)

🎓 แนวคิดสำคัญ: Middleware Pattern

Middleware คืออะไร?

Middleware คือฟังก์ชันที่ทำงาน ระหว่าง Request และ Response

Signature:

function middleware(req, res, next) {
  // ทำงานบางอย่าง
  next(); // เรียก middleware ถัดไป
}

ตัวอย่าง Custom Middleware:

// Logger Middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Authentication Middleware
app.use((req, res, next) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: "No token" });
  }
  // Verify token...
  next();
});

📝 แบบฝึกหัด

คำถามทบทวน

  1. Node.js ใช้ Engine อะไรในการรัน JavaScript?
  2. Express Middleware ทำงานในลำดับใด?
  3. CORS ย่อมาจากอะไร และทำไมถึงสำคัญ?
  4. app.use() และ app.get() ต่างกันอย่างไร?
  5. ทำไม Error Handler ต้องอยู่ท้ายสุด?

โจทย์ปฏิบัติ

โจทย์ที่ 1: สร้าง Express Server ง่ายๆ

// TODO: สร้าง Express app
// TODO: เพิ่ม middleware สำหรับ JSON parsing
// TODO: สร้าง GET endpoint ที่ /api/hello ให้ return { message: "Hello World" }
// TODO: Start server ที่ port 3000

โจทย์ที่ 2: สร้าง Custom Logger Middleware

// TODO: สร้าง middleware ที่แสดง timestamp, method, และ url ของทุก request
// ตัวอย่าง output: [2026-01-20 15:00:00] GET /api/users

โจทย์ที่ 3: ตั้งค่า CORS

// TODO: อนุญาตเฉพาะ http://localhost:3000 และ https://myapp.com

📌 สรุป

ในบทนี้เราได้เรียนรู้:

✅ Node.js คือ JavaScript Runtime ที่ทำงานนอก Browser
✅ Express คือ Web Framework ที่ช่วยสร้าง API ได้ง่าย
✅ Middleware คือฟังก์ชันที่ประมวลผล Request ก่อนถึง Route Handler
✅ CORS สำคัญสำหรับการอนุญาตให้ Frontend เรียก API
✅ Environment Variables ช่วยแยกค่า configuration ออกจากโค้ด

ไฟล์ที่เกี่ยวข้อง


🔜 บทถัดไป

บทที่ 2: MongoDB และ Mongoose Models
เราจะเรียนรู้การเชื่อมต่อ Database, สร้าง Schema, และทำ CRUD Operations


📚 แหล่งเรียนรู้เพิ่มเติม