วิธีสร้าง REST API: การออกแบบ ความปลอดภัย และการนำขึ้นใช้งานจริง
วิธีสร้าง REST API ให้เริ่มจากการเขียนรายการ resource ที่แอปของคุณจัดการ (ผู้ใช้ ออเดอร์ การจอง) ให้แต่ละรายการมี URL เช่น /orders และ /orders/{id} แล้วใช้ HTTP method สำหรับการทำงาน ได้แก่ GET เพื่ออ่าน, POST เพื่อสร้าง, PATCH เพื่อแก้ไข และ DELETE เพื่อลบ ส่งผลลัพธ์กลับเป็น JSON พร้อม status code ที่มีความหมาย ตรวจสอบข้อมูลขาเข้าทุกรายการ บังคับ การยืนยันตัวตน และตรวจสิทธิ์รายข้อมูลที่เซิร์ฟเวอร์ แบ่งหน้าของรายการด้วย pagination แล้วจึงเขียนเอกสารของ endpoint และนำ API ขึ้นใช้งานหลัง HTTPS
คู่มือนี้ครอบคลุมการตัดสินใจด้านการออกแบบ ชุด route ตัวอย่าง พรอมต์สำหรับเครื่องมือสร้างแอปด้วย AI และข้อผิดพลาดที่ก่อให้เกิดช่องโหว่ด้านความปลอดภัย หากยังไม่คุ้นกับ API ให้เริ่มจาก API คืออะไร
เมื่อไรที่คุณต้องใช้ REST API
- หน้าเว็บฝั่ง frontend ของคุณต้องบันทึกและโหลดข้อมูลจากเซิร์ฟเวอร์
- แอปมือถือ พาร์ตเนอร์ หรือเครื่องมืออัตโนมัติต้องเข้าถึงข้อมูลของคุณ
- บริการอื่นส่ง event มาให้คุณ (webhook)
- คุณแบ่งงานระหว่างทีม frontend และทีม backend
REST เป็นสไตล์ที่นิยมที่สุด แต่ไม่ใช่สไตล์เดียว REST กับ GraphQL อธิบายว่าเมื่อไรการใช้ endpoint สำหรับ query ที่ยืดหยุ่นเพียงจุดเดียวจะเหมาะกว่า
ออกแบบก่อน: resource และ route
เขียนคำนามทั้งหมดในแอปของคุณ และสิ่งที่ผู้ใช้ทำกับคำนามเหล่านั้น ตัวอย่างสำหรับแอปจองคิวอย่างง่าย:
| Method | Route | ทำอะไร | รหัสสำเร็จ |
|---|---|---|---|
GET | /api/bookings | แสดงรายการการจองของผู้เรียก (แบ่งหน้า) | 200 |
POST | /api/bookings | สร้างการจอง | 201 |
GET | /api/bookings/{id} | ดูการจองหนึ่งรายการ | 200 |
PATCH | /api/bookings/{id} | เปลี่ยนบางฟิลด์ | 200 |
DELETE | /api/bookings/{id} | ยกเลิกการจอง | 204 |
GET | /api/health | health check สำหรับระบบมอนิเตอร์ | 200 |
เหล่านี้ตรงกับ create, read, update และ delete ดู CRUD คืออะไร แนวทางที่ควรทำตาม:
- ใช้คำนามพหูพจน์และไม่ใส่คำกริยาใน URL:
/bookingsไม่ใช่/getBookings - ซ้อนได้เพียงชั้นเดียว เมื่อช่วยให้เห็นความเป็นเจ้าของ เช่น
/bookings/{id}/notes - การกระทำที่ไม่ใช่ CRUD สามารถเป็น sub-resource ได้ เช่น
POST /bookings/{id}/cancelชัดเจนกว่าการใช้ PATCH แบบซ่อนความหมาย - ตั้งชื่อฟิลด์ให้สม่ำเสมอ เช่น ใช้
created_atทุกที่
status code และข้อผิดพลาด
ใช้ HTTP code มาตรฐาน เพื่อให้ client รู้ผลลัพธ์โดยไม่ต้องแยกข้อความ:
| Code | ความหมาย | ใช้เมื่อ |
|---|---|---|
| 200 | OK | อ่านหรืออัปเดตสำเร็จ |
| 201 | Created | POST สร้างข้อมูลสำเร็จ |
| 204 | No Content | สำเร็จและไม่มีข้อมูลส่งกลับ |
| 400 | Bad Request | ข้อมูลขาเข้าไม่ผ่านการตรวจสอบ |
| 401 | Unauthorized | ยังไม่ได้เข้าสู่ระบบ หรือ token ไม่ถูกต้อง |
| 403 | Forbidden | เข้าสู่ระบบแล้วแต่ไม่มีสิทธิ์ |
| 404 | Not Found | ไม่มีข้อมูลนี้ หรือไม่ควรให้ผู้เรียกรู้ว่ามีอยู่ |
| 409 | Conflict | ข้อมูลซ้ำ หรือช่วงเวลานั้นถูกจองไปแล้ว |
| 429 | Too Many Requests | เกินขีดจำกัดอัตราการเรียก |
| 500 | Server Error | บางอย่างพังที่ฝั่งเซิร์ฟเวอร์ของคุณ |
ส่งข้อผิดพลาดกลับในโครงสร้าง JSON เดียวที่สม่ำเสมอ เช่น {"error": {"code": "slot_taken", "message": "เวลานั้นไม่ว่างแล้ว"}} และอย่าใส่ stack trace หรือข้อผิดพลาดของฐานข้อมูลลงในการตอบกลับเด็ดขาด
ตัวเลือกและการแลกเปลี่ยน
| การตัดสินใจ | ตัวเลือกที่ง่าย | ทางเลือกอื่น |
|---|---|---|
| API อยู่ที่ไหน | API route ในเฟรมเวิร์กเว็บของคุณ | บริการ API แยกต่างหาก เหมาะกับหลาย client หรือภาษาอื่น |
| การยืนยันตัวตน | session cookie สำหรับเว็บแอปของคุณเอง | token (bearer token หรือ API key) สำหรับแอปมือถือและบุคคลที่สาม |
| การแบ่งหน้า | ?page=2&limit=20 | แบบ cursor (?after=...) มั่นคงกว่าสำหรับรายการขนาดใหญ่ที่เปลี่ยนบ่อย |
| การกำหนดเวอร์ชัน | ไม่มี จนกว่าจะมีผู้ใช้ภายนอก | /v1/ ในพาธ เมื่อมีคนอื่นพึ่งพาแล้ว |
| เอกสาร | README ที่แสดงรายการ route | ข้อกำหนด OpenAPI ซึ่งเครื่องมือแปลงเป็นเอกสารแบบโต้ตอบและโค้ด client ได้ |
ทีละขั้นตอน
- แสดงรายการ resource และ route ตามที่กล่าวข้างต้น รวมถึงระบุว่าใครเรียก route แต่ละตัวได้บ้าง
- ออกแบบข้อมูล ในฐานข้อมูลด้วยฟิลด์และความสัมพันธ์ที่ต้องใช้
- สร้าง route สำหรับการอ่านก่อน แล้วจึงสร้างการเพิ่ม การแก้ไข และการลบ
- ตรวจสอบข้อมูลขาเข้า ทุกครั้งที่เขียนข้อมูล ด้วยไลบรารี schema: ฟิลด์ที่จำเป็น ชนิดข้อมูล ความยาว ค่าที่อนุญาต ปฏิเสธฟิลด์ที่ไม่รู้จัก
- เพิ่มการยืนยันตัวตน แล้วตามด้วย การอนุญาตรายข้อมูล: การเปิดดู
/bookings/42ต้องตรวจว่าการจอง 42 เป็นของผู้เรียก ไม่ใช่แค่ตรวจว่ามีคนเข้าสู่ระบบอยู่ - แบ่งหน้ารายการทุกรายการ และจำกัดขนาดหน้าสูงสุด
- จำกัดอัตราการเรียก สำหรับการเข้าสู่ระบบและ route ที่ใช้ทรัพยากรมาก ดู rate limiting
- ตั้งค่า CORS เฉพาะเมื่อเบราว์เซอร์จากโดเมนอื่นต้องเรียก API และระบุ origin เหล่านั้นอย่างชัดเจน วิธีแก้ข้อผิดพลาด CORS อธิบายข้อผิดพลาดที่คุณจะพบ
- เขียนเอกสารและการทดสอบ สำหรับแต่ละ route รวมถึงกรณีที่ล้มเหลว
- นำขึ้นใช้งาน โดยเก็บความลับในตัวแปรสภาพแวดล้อม ใช้ HTTPS มี log และ health check
พรอมต์สำหรับเครื่องมือสร้างแอปด้วย AI
สร้างโครง:
สร้าง REST API สำหรับการจอง โดยมี route ดังนี้ GET /api/health, GET /api/bookings (แบ่งหน้า สูงสุด 50 รายการต่อหน้า), POST /api/bookings, GET /api/bookings/:id, PATCH /api/bookings/:id, DELETE /api/bookings/:id เก็บข้อมูลในฐานข้อมูลของเรา ตรวจสอบเนื้อหาคำขอด้วยไลบรารี schema และปฏิเสธฟิลด์ที่ไม่รู้จัก ส่งข้อผิดพลาดเป็น JSON ในรูปแบบ {"error": {"code", "message"}} พร้อม status code ที่ถูกต้อง (400, 401, 403, 404, 409) เก็บความลับในตัวแปรสภาพแวดล้อม
ความปลอดภัย:
ให้ทุก route ของการจองต้องเข้าสู่ระบบก่อน ในทุกการอ่าน แก้ไข และลบ ให้ตรวจที่เซิร์ฟเวอร์ว่าการจองเป็นของผู้ใช้ปัจจุบัน ถ้าไม่ใช่ให้ส่ง 404 อย่ารับ user ID หรือ role จากเนื้อหาคำขอเด็ดขาด จำกัด POST /api/bookings ไว้ที่ 20 ครั้งต่อนาทีต่อผู้ใช้ บันทึกข้อผิดพลาดไว้ที่เซิร์ฟเวอร์ และอย่าส่ง stack trace กลับไปยังผู้ใช้
เอกสาร:
เขียนคำอธิบาย OpenAPI ของ route เหล่านี้ และ README สั้น ๆ ที่มีตัวอย่างคำขอและการตอบกลับของแต่ละ route
ทดสอบ API ของคุณ
ทดสอบจากภายนอก frontend เพราะผู้โจมตีก็จะทำเช่นนั้น:
- แต่ละ route ทำงานกับข้อมูลที่ถูกต้อง และส่งรูปแบบและ code ตามที่เอกสารระบุ
- ฟิลด์ที่ขาดหรือไม่ถูกต้องส่ง 400 พร้อมข้อความที่ชัดเจน
- ไม่มี token แล้วได้ 401 ในทุก route ที่ต้องยืนยันตัวตน
- ผู้ใช้ A ขอข้อมูลของผู้ใช้ B ด้วย ID แล้วได้ 404 หรือ 403
- รายการถูกแบ่งหน้า และค่า
limitที่สูงมากถูกจำกัด - การสร้างข้อมูลซ้ำหรือขัดแย้งส่ง 409 ไม่ใช่ 500
- การเกินขีดจำกัดส่ง 429
- การตอบกลับข้อผิดพลาดไม่มี stack trace, SQL หรือความลับ
- CORS อนุญาตเฉพาะ origin ที่ตั้งใจไว้
ข้อผิดพลาดที่พบบ่อย
- ตรวจการเข้าสู่ระบบแต่ไม่ตรวจความเป็นเจ้าของ เป็นช่องโหว่ของ API ที่พบบ่อยที่สุด: ผู้ใช้ที่เข้าสู่ระบบคนไหนก็ได้สามารถอ่านข้อมูลของคนอื่นได้ด้วยการเปลี่ยน ID
- เชื่อ client มากเกินไป ราคา role และ user ID ในเนื้อหาคำขอสามารถถูกแก้ไขได้
- ส่งแถวทั้งหมดจากฐานข้อมูลกลับไป รหัสผ่านที่แฮชแล้วและฟิลด์ภายในจะรั่วไหล ให้เลือกว่าแต่ละการตอบกลับควรมีอะไรบ้าง
- รายการที่ไม่มีขอบเขต คำขอเดียวที่ดึงข้อมูลทุกรายการอาจทำให้ทั้งแอปช้าลง
200 OKพร้อมข้อความผิดพลาดอยู่ข้างใน client และระบบมอนิเตอร์จะไม่รู้ว่าล้มเหลว- ตั้ง CORS ให้อนุญาตทุกอย่าง ใน API ที่ใช้ cookie
- ไม่มี health check หรือ log ทำให้คุณรู้ว่าระบบล่มจากผู้ใช้เท่านั้น
สำหรับการตรวจสอบก่อนเปิดตัวในภาพรวม ดู เช็กลิสต์ความปลอดภัยสำหรับแอปที่สร้างด้วย AI
สร้าง REST API ใน Mythex
คุณสามารถขอ API ใน Mythex ได้ ทั้งเป็นส่วนหนึ่งของแอปหรือเป็นบริการแยกต่างหาก เอกสารสูตร REST API backend มีพรอมต์เริ่มต้น: ระบุเฟรมเวิร์กและ route ของคุณ ขอข้อผิดพลาดแบบ JSON ที่ชัดเจน เก็บความลับในตัวแปรสภาพแวดล้อม และรวม Dockerfile ไว้ด้วย backend แบบ container ที่ใช้ Node, Python, C#, Java และภาษาอื่นจะเผยแพร่ผ่าน Dockerfile และ Mythex จัดการการนำขึ้นใช้งานจากเมนู Publish (API backend) โปรเจกต์หนึ่งสามารถรันเว็บไซต์และ API server คู่กันได้ และคุณสลับระหว่างสองอย่างในการพรีวิวได้ เก็บคีย์เป็น secret ของโปรเจกต์ และหาก API ต้องใช้ฐานข้อมูล ให้ขอในแชท สำหรับงานเบื้องหลังที่กำหนดเวลาซึ่งทำงานร่วมกับ API ของคุณ ดู วิธีรันงานเบื้องหลัง
คำถาม
REST API คืออะไร
REST API คือวิธีที่โปรแกรมใช้ทำงานกับข้อมูลในแอปของคุณผ่าน HTTP ข้อมูลแต่ละประเภทคือ resource ที่มี URL ของตัวเอง เช่น /orders และ method มาตรฐานใช้จัดการข้อมูลนั้น โดย GET ใช้อ่าน, POST ใช้สร้าง, PATCH หรือ PUT ใช้แก้ไข และ DELETE ใช้ลบ ข้อมูลมักส่งกันในรูปแบบ JSON
ควรสร้าง REST API ด้วยภาษาอะไร
เลือกภาษาที่คุณหรือทีมดูแลได้ไหว Node.js กับ Express หรือ Fastify, Python กับ FastAPI และเฟรมเวิร์กของ C# หรือ Java ใช้ได้ดีทั้งหมด กฎการออกแบบ route, status code, การตรวจสอบข้อมูล และการยืนยันตัวตนสำคัญกว่าตัวภาษาเสียอีก
จะทำให้ REST API ปลอดภัยได้อย่างไร
ให้ทุก route ที่ไม่ได้เปิดสาธารณะต้องยืนยันตัวตนก่อน ตรวจที่เซิร์ฟเวอร์ว่าผู้เรียกมีสิทธิ์เข้าถึงข้อมูลแต่ละรายการนั้นจริง ตรวจสอบข้อมูลขาเข้าทั้งหมด ใช้ HTTPS จำกัดจำนวนคำขอ และเก็บความลับไว้ในตัวแปรสภาพแวดล้อม อย่าไว้ใจ ID หรือ role ที่ฝั่ง client ส่งมาเด็ดขาด
ต้องมี backend แยกต่างหากสำหรับ REST API หรือไม่
ไม่จำเป็นเสมอไป เฟรมเวิร์กอย่าง Next.js สามารถให้บริการ API route ควบคู่กับหน้าเว็บได้ บริการ API แยกต่างหากเหมาะเมื่อมีหลาย client (เว็บ มือถือ พาร์ตเนอร์) ใช้งาน หรือเมื่อต้องการภาษาและระบบปรับขนาดของตัวเอง