Dev Nest


กำลังเตรียมห้องเรียน... 🎓
เรียนรู้ไปพร้อมกับเรา ทุกขั้นตอนของการพัฒนาซอฟต์แวร์
ถ้าคุณเขียนหน้าเว็บสวย ๆ ออกมาได้แล้ว แต่พอถึงตอนที่ต้องเอา "ข้อมูลจริง" จากเซิร์ฟเวอร์มาแสดงบนหน้าจอ กลับงงไปหมดว่ามันมาจากไหนยังไง — บทความนี้เขียนมาเพื่อคุณ
เราจะไม่ท่องนิยามแห้ง ๆ แต่จะ ตามรอย 1 request ตั้งแต่ผู้ใช้กดปุ่มบนหน้าเว็บ (frontend) วิ่งไปหา server (backend) ทักทายฐานข้อมูล แล้วส่งข้อมูลกลับมาแสดงผล ให้เห็นทั้งวงจรในที่เดียว พร้อมโค้ดตัวอย่างจริงทั้งฝั่ง Next.js และ Nest.js ที่ DevNest ใช้สอน
ลองนึกภาพว่าคุณทำหน้าโปรไฟล์ผู้ใช้เสร็จแล้ว layout เป๊ะ สีสวย แต่ตรงที่ควรจะเป็นชื่อผู้ใช้ดันเป็นข้อความ "ชื่อตัวอย่าง" ที่ฮาร์ดโค้ดไว้ คำถามคือ ชื่อจริงของผู้ใช้แต่ละคนที่เก็บอยู่ในฐานข้อมูล จะเดินทางจาก server มาโผล่บนหน้าจอได้ยังไง?
นี่คือจุดที่มือใหม่เกือบทุกคน "ติด" เพราะ frontend (ส่วนหน้าที่ผู้ใช้เห็น) กับ backend (ส่วนหลังบ้านที่เก็บข้อมูลและประมวลผล) เป็นคนละโปรแกรม รันคนละที่ คุยกันตรง ๆ ไม่ได้ ต้องมี "ตัวกลาง" ที่ทำหน้าที่รับคำขอและส่งข้อมูลกลับ
ตัวกลางนั้นในงานจริงเกือบทั้งหมดคือ REST API — และในบทความนี้เราจะค่อย ๆ แกะมันออกมาทีละชิ้นจนคุณเห็นภาพชัดว่ามันทำงานยังไง
ก่อนจะไปถึง REST เรามาเคลียร์คำว่า API กันก่อน เพราะสองคำนี้คนชอบสับสนปนกัน
พูดให้ชัด: API คือ "ประตู" ส่วน REST คือ "กติกาว่าประตูบานนี้ควรออกแบบยังไงให้เป็นระเบียบ" เมื่อ API ตัวไหนออกแบบตามแนวทาง REST เราก็เรียกมันว่า REST API หรือ RESTful API
แนวคิด REST ถูกนิยามไว้โดย Dr. Roy Fielding ในวิทยานิพนธ์ปริญญาเอกของเขาตั้งแต่ปี 2000 และกลายมาเป็นแนวทางยอดนิยมในการสร้าง web API จนถึงทุกวันนี้ (เกร็ดนี้รู้ไว้พอ ไม่ต้องจำลึก)
ถ้ายังนึกภาพไม่ออก ลองนึกถึงร้านอาหาร:
ลูกค้าไม่ได้เดินเข้าไปทำอาหารเองในครัว แต่บอกออเดอร์กับพนักงานเสิร์ฟ พนักงานเสิร์ฟเอาออเดอร์ไปส่งครัว รอครัวทำเสร็จ แล้วยกอาหารกลับมาเสิร์ฟ — REST API ก็ทำหน้าที่เหมือนพนักงานเสิร์ฟคนนี้ คือรับคำขอจาก frontend ไปบอก backend แล้วเอาผลลัพธ์กลับมาให้
ทีนี้มาถึงหัวใจของบทความ เราจะตามรอยคำขอ 1 ครั้ง (request) ตั้งแต่ต้นจนจบ สมมติว่าผู้ใช้เปิดหน้าที่ต้องการแสดง "ข้อมูลผู้ใช้ id 1" วงจรจะเป็นแบบนี้:
ลองมาดูทีละฝั่งว่าโค้ดจริงหน้าตาเป็นยังไง
ใน Next.js (App Router) เราสามารถดึงข้อมูลใน Server Component ได้เลยด้วยฟังก์ชัน fetch() ที่มีมาให้ในตัว โค้ดจะประมาณนี้:
// app/users/[id]/page.tsx (Server Component)
export default async function UserPage({
params,
}: {
params: { id: string };
}) {
// ยิง request แบบ GET ไปที่ endpoint ของ backend
const res = await fetch(`https://api.example.com/users/${params.id}`);
// แปลงข้อมูลที่ได้กลับมา (JSON) ให้เป็น object ที่ใช้งานได้
const user = await res.json();
return (
<main>
<h1>{user.name}</h1>
<p>{user.email}</p>
</main>
);
}
จุดที่ต้องสังเกต: ตรง fetch(...) คือการยิง request ออกไป โดยถ้าเราไม่ระบุอะไรเพิ่ม fetch จะใช้ method เป็น GET ซึ่งหมายถึง "ขอดึง/อ่านข้อมูล" — ตรงกับสิ่งที่เราต้องการพอดี คือไปขอข้อมูลผู้ใช้มาแสดง
ฝั่ง backend เราใช้ Nest.js สร้าง controller ที่คอยรับ request ที่วิ่งเข้ามาที่ endpoint /users/:id แล้วตอบกลับด้วยข้อมูลผู้ใช้:
// users.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
// รับ request แบบ GET ที่ /users/:id
@Get(':id')
async findOne(@Param('id') id: string) {
// คุยกับ database ผ่าน service เพื่อหาข้อมูลผู้ใช้
const user = await this.usersService.findById(id);
// ค่าที่ return จะถูกแปลงเป็น JSON ส่งกลับให้ frontend อัตโนมัติ
return user;
}
}
@Get(':id') คือตัวบอกว่า "ถ้ามี request แบบ GET วิ่งเข้ามาที่ /users/<อะไรสักอย่าง> ให้รันฟังก์ชันนี้" จากนั้น controller ก็ไปคุยกับ database (ผ่าน service) ดึงข้อมูลออกมา แล้ว return กลับไป Nest.js จะจัดการแปลงให้เป็น JSON ส่งกลับให้ฝั่ง frontend เอง
ข้อมูลที่ backend ส่งกลับมาให้ frontend หน้าตาจะเป็น JSON ประมาณนี้:
{
"id": 1,
"name": "สมชาย ใจดี",
"email": "somchai@example.com"
}
JSON (JavaScript Object Notation) เป็นรูปแบบข้อมูลที่อ่านง่ายทั้งคนและเครื่อง ขนาดเล็ก เลยเป็นรูปแบบที่ REST API นิยมใช้กันมากที่สุด แต่ขอย้ำว่า REST ไม่ได้บังคับว่าต้องเป็น JSON จะส่งกลับเป็น XML, HTML หรือ text ธรรมดาก็ได้ เพียงแต่ JSON เป็นตัวเลือกที่สะดวกที่สุดในงานเว็บสมัยใหม่
พอ Next.js ได้ JSON ก้อนนี้กลับมา ก็เอาไปแสดงผลบนหน้าจอตามที่เราเขียนไว้ใน component — ครบ 1 รอบพอดี
ภาพที่ frontend ยิงคำขอไปคุยกับ backend แบบ end-to-end ตั้งแต่หน้าจอจนถึงฐานข้อมูลแล้วกลับมานี้ คือหัวใจของงาน fullstack ถ้าเข้าใจ loop นี้ คุณก็เข้าใจแกนกลางของการสร้างเว็บแอปทั้งระบบแล้ว
ทีนี้มาแกะ "คำขอ 1 ครั้ง" ออกเป็นชิ้น ๆ ว่าจริง ๆ แล้วใน request หนึ่งมีอะไรอยู่บ้าง เพราะตอน debug หรืออ่านโค้ดคนอื่น คุณจะเจอชิ้นส่วนเหล่านี้ตลอด
HTTP method คือ "คำกริยา" ที่บอกว่า request นี้อยากให้ทำอะไรกับข้อมูล ตัวที่ใช้บ่อยจับคู่กับการทำงานพื้นฐานที่เรียกว่า CRUD (Create, Read, Update, Delete) ได้ตามนี้:
| Method | ทำอะไร | ตรงกับ CRUD | ตัวอย่าง |
|---|---|---|---|
GET | อ่าน/ดึงข้อมูล | Read | ดึงรายชื่อผู้ใช้ทั้งหมด |
POST | สร้างข้อมูลใหม่ | Create | สมัครสมาชิกใหม่ |
PUT | อัปเดต/แทนที่ข้อมูลทั้งก้อน | Update | แก้ไขโปรไฟล์ทั้งหน้า |
PATCH | อัปเดตข้อมูลบางส่วน | Update | แก้แค่เบอร์โทรช่องเดียว |
DELETE | ลบข้อมูล | Delete | ลบบัญชีผู้ใช้ |
จำง่าย ๆ: GET คือไป "ขอดู" ส่วน POST คือไป "สร้างของใหม่" สองตัวนี้คนสับสนกันบ่อยและบางบทความก็เขียนสลับกัน อย่าจำผิดเด็ดขาด — ถ้าจะดึงข้อมูลมาแสดงใช้ GET ถ้าจะส่งข้อมูลไปสร้างใหม่ (เช่นกดสมัคร กดโพสต์) ใช้ POST
Endpoint (หรือ URI — ที่อยู่ของทรัพยากร) คือ "ที่อยู่" ที่บอกว่า request นี้จะไปจัดการกับข้อมูลตัวไหน REST นิยมตั้งชื่อ endpoint ตามตัว "ทรัพยากร" (resource) เช่น:
/users — ผู้ใช้ทั้งหมด/users/1 — ผู้ใช้ที่มี id เท่ากับ 1/orders/5/consumers — ผู้ซื้อทั้งหมดของ order หมายเลข 5 (เรียกว่า nested resource คือทรัพยากรซ้อนอยู่ในอีกทรัพยากร)สังเกตว่า endpoint เป็นคำนาม (users, orders) ไม่ใช่คำกริยา เพราะ "กริยา" ว่าจะทำอะไรเป็นหน้าที่ของ HTTP method แล้ว เช่น GET /users = ดึงผู้ใช้ทั้งหมด, POST /users = สร้างผู้ใช้ใหม่ — endpoint เดียวกันแต่ method ต่างกัน ความหมายก็ต่างกัน
นอกจาก method กับ endpoint แล้ว request ยังพก 2 ส่วนนี้ไปด้วยได้:
Authorization (บัตรผ่าน บอกว่าใครเป็นคนขอ ใช้ตอนต้องล็อกอิน) และ Content-Type (บอกว่าข้อมูลที่ส่งไปเป็นรูปแบบอะไร เช่น application/json)ทุกครั้งที่ server ตอบกลับ มันจะแนบ status code มาด้วย เป็นตัวเลข 3 หลักที่บอกว่า "ผลลัพธ์เป็นยังไง" แบ่งเป็นกลุ่มตามหลักร้อย:
(ยังมีกลุ่ม 1xx กับ 3xx อีก แต่มือใหม่เจอน้อยกว่ามาก เอาไว้ค่อยรู้ทีหลังได้)
ตัวที่เจอบ่อยและควรจำไว้ใช้ตอน debug:
| Code | ความหมาย | เจอตอนไหน |
|---|---|---|
200 OK | สำเร็จ | GET ดึงข้อมูลได้ปกติ |
201 Created | สร้างสำเร็จ | POST สร้างข้อมูลใหม่เรียบร้อย |
400 Bad Request | คำขอผิดรูปแบบ | ส่ง body ผิด/ข้อมูลไม่ครบ |
401 Unauthorized | ยังไม่ได้ยืนยันตัวตน | ลืมแนบ token / ยังไม่ล็อกอิน |
404 Not Found | หาไม่เจอ | เรียก endpoint หรือ id ที่ไม่มีอยู่ |
500 Internal Server Error | server พังเอง | มี bug ในโค้ดฝั่ง backend |
ทำไมต้องรู้? เพราะตอนเขียนเว็บจริงแล้วข้อมูลไม่ขึ้น สิ่งแรกที่มือโปรทำคือเปิด DevTools ดูว่า request ตอบกลับ status code อะไร เห็น 404 ก็รู้ทันทีว่า endpoint ผิด เห็น 401 ก็รู้ว่าเรื่อง token เห็น 500 ก็รู้ว่าปัญหาอยู่ฝั่ง backend ไม่ใช่ฝั่งเรา — status code คือเข็มทิศที่ช่วยให้คุณ debug ได้เร็วขึ้นมาก
อ่านมาถึงตรงนี้ ลองลงมือยิง API จริงสักครั้งจะเห็นภาพชัดขึ้นเยอะ และทำได้ง่ายกว่าที่คิด
วิธีที่ 1: ยิง GET ผ่าน browser ตรง ๆ — เพราะการเปิดเว็บก็คือการยิง request แบบ GET อยู่แล้ว ลองเปิด public API ฟรีอย่างเช่นเอา URL นี้ไปวางในแถบ address bar:
https://jsonplaceholder.typicode.com/users/1
คุณจะเห็น JSON response โผล่ขึ้นมาในหน้าจอเลย — นั่นแหละคือสิ่งที่ fetch() ในโค้ดเราได้รับกลับมา แค่ปกติมันทำงานเบื้องหลังจนเราไม่เห็น
วิธีที่ 2: ใช้ Postman หรือ curl — ถ้าอยากลองยิง method อื่นนอกจาก GET (เช่น POST) browser ทำไม่ได้ ให้ใช้เครื่องมืออย่าง Postman (โปรแกรมกดยิง API แบบมี UI) หรือคำสั่ง curl ใน terminal:
# ยิง GET ดูข้อมูลผู้ใช้ id 1
curl https://jsonplaceholder.typicode.com/users/1
ลองเปลี่ยน /1 เป็น /2 หรือ /999 ดูว่าผลต่างกันยังไง (id ที่ไม่มีอยู่จะตอบกลับมาว่างหรือ 404) — แค่นี้คุณก็ได้สัมผัส request/response ของจริงด้วยมือตัวเองแล้ว
ก่อนจบ มาเก็บกวาดความเข้าใจผิดยอดฮิตที่ทำให้มือใหม่งงกันบ่อย:
อีกเรื่องที่ควรรู้ไว้แบบไม่ต้องเครียด: API ที่ใช้ HTTP ในงานจริงส่วนใหญ่ "อิงแนวทาง REST" แต่ไม่ได้ทำตามหลักการครบทุกข้อแบบเป๊ะ ๆ เสมอไป เพราะฉะนั้นถ้าเห็นใครเรียก API ว่า "REST" ทั้งที่ไม่ครบทุกหลักการ ก็ถือเป็นเรื่องปกติของงานจริง ไม่ต้องซีเรียส ตอนนี้เข้าใจภาพรวมก่อนก็พอ
REST เป็นตัวเลือกเริ่มต้นที่ดีและใช้ได้กับงานส่วนใหญ่ แต่มันก็มีข้อจำกัดที่ทำให้บางสถานการณ์มีทางเลือกที่เหมาะกว่า:
ไม่ต้องรีบไปเรียนทุกอย่างตอนนี้ แค่รู้ว่า "REST ไม่ใช่คำตอบเดียวในโลก" และมีเครื่องมืออื่นรอให้หยิบใช้เมื่อเจอโจทย์ที่เหมาะ ก็เพียงพอแล้วสำหรับตอนนี้
ถ้าให้เก็บกลับบ้านแค่ภาพเดียว ขอให้จำ loop นี้:
frontend → ยิง request ผ่าน REST API → backend → คุย database → ส่ง JSON กลับ → frontend เอาไป render
REST API คือสะพานที่ทำให้หน้าเว็บที่คุณเขียนกับข้อมูลในเซิร์ฟเวอร์มาเจอกันได้ และเมื่อเข้าใจว่า 1 request ประกอบด้วย method, endpoint, headers, body และตอบกลับมาพร้อม status code คุณก็มีเครื่องมือพอที่จะอ่านโค้ด ดึงข้อมูล และ debug ได้ด้วยตัวเองแล้ว
ถ้าอ่านจบแล้วรู้สึกว่าอยากลงมือทำ fullstack จริงตั้งแต่ frontend ยันต่อ backend ด้วย stack Next.js + Nest.js แบบในบทความนี้ DevNest มี fullstack bootcamp ที่พาทำตั้งแต่ศูนย์จนต่อ frontend เข้ากับ backend ได้เป็นวงจรจริง ลองแวะไปดูเป็นไอเดียต่อยอดได้