Back to notes
foundations-web
Featured

API Design Mastery: ออกแบบรากฐานการสื่อสารระดับ Senior

ออกแบบ API ยังไงให้ Frontend รัก? เจาะลึก HTTP Status Code, N+1 Problem และหัวใจของการทำ Contract-First Design

January 30, 20262 min read readNNexis by Seereen

🛑 1. The Problem First: API ที่ "คุยกันคนละภาษา"

ลองมองการออกแบบ API แบบจูเนียร์ที่เน้นเร็วและสะดวกตัวเอง:

HLJS BASH
# ❌ Naive Approach: ใช้ HTTP Method มั่ว และ Status Code 200 อย่างเดียว
POST /get-user-data-now?id=123
# ผลลัพธ์: { "status": "error", "message": "Not found" } และ HTTP 200 OK!

ปัญหา: เมื่อคุณใช้ HTTP 200 สำหรับทุกอย่าง (แม้แต่ตอน Error) ระบบ Caching ของ Browser/CDN จะงง และ Frontend ต้องเขียน if-else เช็คข้างในวุ่นวายมหาศาล และการตั้งชื่อแบบ "Action" (get-user-data) จะทำให้ API คุณไม่เป็นระบบเมื่อโปรเจกต์โตขึ้น คุยกันคนละภาษาคือจุดเริ่มต้นของความหายนะในทีมครับ


💡 2. Real-Life Analogy: ร้านอาหารที่มีเมนู (REST) vs บุฟเฟต์ตามสั่ง (GraphQL)

  • REST API: เหมือน "ร้านอาหารตามสั่ง (A La Carte)". คุณสั่งเมนูเบอร์ 1 (GET /users) คุณได้ข้าวมันไก่แบบเซ็ตมาตรฐานมาเลย คุณเลือกไม่ได้ว่าจะเอาแค่ข้าวข้อนึง ไก่ชิ้นนึง (Over-fetching)
  • GraphQL: เหมือน "บุฟเฟต์ที่เชฟทำตามสั่งเป๊ะๆ". คุณยื่นกระดาษบอกว่า "ขอข้าว 2 ช้อน ไก่ 3 ชิ้น ไม่เอาแตงกวา" (Query) แล้วเชฟจะจัดใส่จานมาให้ตามนั้นเป๊ะ ไม่ขาดไม่เกิน
  • Status Codes: เหมือน "สัญญาณไฟหน้าร้าน".
    • เขียว (200): เลือกเมนูได้
    • แดง (401): ต้องโชว์บัตรสมาชิกก่อนเข้า
    • ส้ม (400): สั่งเมนูที่ไม่มีในร้าน

🚀 3. Execution Journey: มหากาพย์ N+1 และทางแก้ระดับโปร

ปัญหาที่พบบ่อยที่สุดใน API คือ N+1 Problem (ยิง Query เยอะเกินจำเป็น)

🛠 Step-by-step:

  1. The Trap: ดึงรายชื่อ User 10 คน (1 Query)
  2. The Loop: สำหรับ User แต่ละคน ให้ไปดึง Posts ของเขาออกมา (10 Queries)
  3. The Result: กลายเป็นยิง Database 11 ครั้ง! (ช้าและเปลือง)
  4. The Fix (DataLoader): รวบ ID ทั้งหมด (1, 2, 3...) แล้วยิง Query เดียวหา Posts ทั้งหมดที่เกี่ยวข้อง (WHERE id IN (1,2,3...))
HLJS TYPESCRIPT
// ✅ Best Practice: ใช้ DataLoader เพื่อ Batch ข้อมูล
const batchPosts = async (authorIds) => {
  const posts = await db.post.findMany({
    where: { authorId: { in: authorIds } }, // 🛠 ยิงครั้งเดียวจบ!
  });
  return authorIds.map((id) => posts.filter((p) => p.authorId === id));
};

🪤 4. The Junior Trap: โรค "หวงข้อมูล/ส่งข้อมูลมั่ว"

จูเนียร์มักจะส่ง Error Message จาก Database ให้ Frontend โดยตรง:

HLJS JAVASCRIPT
// ❌ Junior Trap: รั่วไหลข้อมูลความปลอดภัย
res.status(500).json({
  error:
    "Internal Server Error: Table 'users' does not have column 'password_plain'",
});

ระวัง: การส่ง Error ลึกๆ แบบนี้คือการ "บอกโครงสร้าง Database ให้ Hacker". ✅ การแก้ไข: กรอง Error เสมอ! ส่งแค่รหัส Error หรือข้อความทั่วไปที่ User เข้าใจได้ ส่วน Error จริงๆ ให้ Log เก็บไว้ดูหลังบ้านคนเดียว


⚖️ 5. The Why Matrix: REST vs GraphQL

หัวข้อREST (มาตรฐาน)GraphQL (ยืดหยุ่น)
Caching⚡⚡⚡ ง่ายมาก (ใช้ Browser/CDN ได้เลย)ยาก (ต้องทำที่ Client)
ปริมาณข้อมูลมักจะได้เกิน (Over-fetching)⚡⚡⚡ แม่นยำ (ขอเท่าไหร่ได้เท่านั้น)
การเรียนรู้ง่าย ใครๆ ก็เป็นปานกลาง (ต้องเรียน Query Language)
Versioningต้องทำ /v1/, /v2/ใช้วิธี Deprecated (ไม่ต้องเปลี่ยน URL)

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "API คือสัญญา (Contract) ระหว่างทีม". ก่อนจะเขียนโค้ดบรรทัดแรก คุณต้องตกลง "ภาษา" และ "Status Code" กับ Frontend ให้จบก่อน สิ่งนี้เรียกว่า Contract-First Design ซึ่งจะช่วยลดงานแก้ในอนาคตได้หลักร้อยชั่วโมงครับ!

Share this note

© 2026 My Notes by Seereen