การดู : 0

12/04/2026 18:16น.

JS2GO EP.46 การสร้าง Middleware และ Modular Architecture ใน Go และ Node.js

JS2GO EP.46 การสร้าง Middleware และ Modular Architecture ใน Go และ Node.js

#Node.js

#Go

#Modular Architecture

#Middleware

เขียน API ให้รันได้ = ง่าย

เขียน API ให้ดูแลง่าย ขยายง่าย และรอดใน Production = ต้องใช้สถาปัตยกรรมที่ดี

 

บทความนี้จะสรุปตั้งแต่พื้นฐาน → ระดับองค์กร (Enterprise)

 

สิ่งที่คุณจะได้เรียนรู้

✔ การสร้าง Middleware (Auth, Logging, Rate Limit)
✔ Service / Repository Pattern
✔ Modular Architecture แบบ Production-ready
✔ ตัวอย่างโค้ด Express + Fiber ที่ถูกต้อง
✔ Best Practices ที่ใช้ในบริษัทจริง

 

⭐ 1) Middleware คืออะไร?

 

Middleware = ฟังก์ชันที่ถูกเรียกก่อน (หรือหลัง) Handler

 

มีไว้สำหรับงานประเภท:

  • ตรวจสอบ Authorization / Token
  • Logging request
  • Rate Limiting
  • Request Transform (เช่น normalize headers)
  • Validation
  • ตรวจสอบสิทธิ์ของผู้ใช้

 

Flow (เหมือนกันทั้ง Go และ Node.js)

Request → Middleware A → Middleware B → Handler → Response

 

Handler ควร “บางที่สุด” เพราะงานหนักควรถูกดันไป Service Layer หรือ Middleware

 

⭐ 2) ตัวอย่าง Middleware ที่ถูกต้องและใช้งานได้จริง

 

🔹 Logging Middleware

 

Go (Fiber)

func Logging() fiber.Handler {
    return func(c *fiber.Ctx) error {
        start := time.Now()

        err := c.Next()

        fmt.Printf("[%s] %s - %d (%v)\n",
            c.Method(),
            c.Path(),
            c.Response().StatusCode(),
            time.Since(start),
        )

        return err
    }
}

 

Register

app.Use(Logging())

 

Node.js (Express)

function logger(req, res, next) {
  const start = Date.now();
  res.on("finish", () => {
    console.log(`[${req.method}] ${req.url} - ${res.statusCode} (${Date.now() - start}ms)`);
  });
  next();
}

app.use(logger);

 

🔹 Authentication Middleware

 

Go (Fiber)

func Auth() fiber.Handler {
    return func(c *fiber.Ctx) error {
        token := c.Get("Authorization")
        if token == "" {
            return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
                "error": "Missing Authorization header",
            })
        }
        return c.Next()
    }
}

 

Node.js (Express)

function auth(req, res, next) {
  const token = req.headers.authorization;
  if (!token) return res.status(401).json({ error: "Unauthorized" });
  next();
}

app.use(auth);

 

🔹 Rate Limit (Basic Example สำหรับสาธิต ไม่เหมาะกับ Production)

 

Go

func RateLimit() fiber.Handler {
    var mu sync.Mutex
    var count = 0

    return func(c *fiber.Ctx) error {
        mu.Lock()
        if count >= 100 {
            mu.Unlock()
            return c.Status(429).SendString("Too Many Requests")
        }
        count++
        mu.Unlock()

        return c.Next()
    }
}

 

Node.js

let count = 0;

function rateLimit(req, res, next) {
  if (count >= 100) {
    return res.status(429).send("Too Many Requests");
  }
  count++;
  next();
}

app.use(rateLimit);

 

➡ ใน Production ควรใช้ Redis + Token Bucket / Sliding Window

 

⭐ 3) Modular Architecture คืออะไร?

 

โครงสร้างแบบ Modular = ทุกโมดูลดูแลตัวเอง (self-contained)

 

ช่วยให้ระบบ:

  • แก้ไขง่าย
  • เพิ่มฟีเจอร์ได้โดยไม่แตะส่วนอื่น
  • แยก test ได้ง่าย
  • เหมาะกับระบบขนาดกลาง–ใหญ่

 

📌 โครงสร้างใน Go (Production-ready)

 

/cmd/server/main.go
/internal
   /user
      handler.go
      service.go
      repository.go
      model.go
   /product
      handler.go
      service.go
      repository.go
/pkg
   /database

 

📌 โครงสร้างใน Node.js (Express)

 

src/
 ├─ modules/
 │   ├─ user/
 │   │   ├─ user.controller.js
 │   │   ├─ user.service.js
 │   │   ├─ user.repository.js
 │   │   ├─ user.model.js
 │   ├─ product/
 ├─ middlewares/
 ├─ routes/
 ├─ database/
 ├─ app.js
 ├─ server.js

 

⭐ 4) Service / Repository Pattern คืออะไร?

 

แยกความรับผิดชอบตามลำดับชั้น:

Layerหน้าที่
Handler / Controllerรับ Request → เรียก Service → ส่ง Response
ServiceLogic ธุรกิจ เช่น Validation, Rule, Workflow
Repositoryคุยกับ Database เท่านั้น

 

ตัวอย่างใน Go (Fiber)

 

Handler

func (h *UserHandler) GetUser(c *fiber.Ctx) error {
    id := c.Params("id")

    user, err := h.Service.GetUser(c.Context(), id)
    if err != nil {
        return c.Status(404).JSON(fiber.Map{"error": "User not found"})
    }

    return c.JSON(user)
}

 

Service

func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
    return s.Repo.FindByID(ctx, id)
}

 

Repository

func (r *UserRepository) FindByID(ctx context.Context, id string) (*User, error) {
    row := r.DB.QueryRow(ctx, "SELECT id, name FROM users WHERE id=$1", id)

    var u User
    if err := row.Scan(&u.ID, &u.Name); err != nil {
        return nil, err
    }

    return &u, nil
}

 

ตัวอย่าง Node.js (Express)

 

Controller

export const getUser = async (req, res) => {
  const user = await userService.getUser(req.params.id);
  if (!user) return res.status(404).send("User not found");
  res.json(user);
};

 

Service

export const userService = {
  getUser: async (id) => userRepository.findById(id),
};

 

Repository

export const userRepository = {
  findById: async (id) => {
    const result = await pool.query(
      "SELECT id, name FROM users WHERE id=$1",
      [id]
    );
    return result.rows[0];
  },
};

 

⭐ 5) Project Structure ที่ใช้จริงใน Production

 

ทั้ง Go และ Node.js ใช้ pattern แบบแยก module + service + repository เพื่อให้รองรับทีมใหญ่และระบบที่เติบโตต่อเนื่อง

 

⭐ 6) Best Practices สำหรับองค์กร

 

✔ Controller ต้อง “บาง” ไม่มี business logic
✔ Service ไม่แตะ database
✔ Repository ไม่รู้กฎของธุรกิจ
✔ อย่าทำ middleware ทำงานหนัก (เพิ่ม latency)
✔ ใช้ Dependency Injection (จะสอนใน EP.47)
✔ ตั้งชื่อไฟล์ตามหน้าที่ เช่น user.service.js ไม่ใช่ service.js
✔ Mock service/repository เพื่อเขียน unit test

 


 

📌 สรุป

 

เมื่อคุณใช้:

  • Middleware ที่ออกแบบดี
  • Modular Architecture
  • Service/Repository Pattern

 

ระบบของคุณจะ:

🚀 ขยายง่าย
🧱 เสถียร
🔍 เทสง่าย
💼 พร้อมใช้งาน Production จริง

 

นี่คือเหตุผลว่าทำไมองค์กรใหญ่และซอฟต์แวร์เฮาส์มืออาชีพถึงใช้สถาปัตยกรรมแนวนี้

 

🔵 ตอนต่อไป: EP.47 Dependency Injection ใน Go และ Node.js

 

คุณจะได้เรียนรู้ว่า:

  • DI ทำให้ระบบ testable ขนาดไหน
  • Constructor-based Injection ใน Go
  • DI Container ใน Node.js
  • Mock Service/Repository อย่างไรให้เทสง่าย
  • ออกแบบ Dependency Graph ของระบบอย่างถูกต้อง