10 กฎการตั้งชื่อ REST API ที่ช่วยลดหนี้ทางเทคนิค
เปิดโค้ดเบสใดๆ ที่มีอายุเกินสองปี คุณมักจะพบร่องรอยอย่าง /getUser, /user_list, [REDACTED PATH]ข้างorder_id` ในการตอบกลับเดียวกัน สิ่งเหล่านี้อาจไม่ทำให้ระบบพัง แต่ทำให้ทุกคนทำงานช้าลง
{% cta https://apidog.com/?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation %} ลองใช้ Apidog วันนี้ {% endcta %}
การตั้งชื่อเป็นหนึ่งในการตัดสินใจออกแบบ API ที่มีต้นทุนต่ำที่สุด แต่แก้ไขได้แพงที่สุด เมื่อไคลเอนต์พึ่งพา /getOrders แล้ว คุณอาจต้องรองรับชื่อนี้ไปอีกหลายปี
บทความนี้สรุปกฎที่ชัดเจนสำหรับการตั้งชื่อ REST API พร้อมตัวอย่างที่ควรทำและควรหลีกเลี่ยง โดยเน้นประเด็นที่ทีมมักถกเถียงกันมากที่สุด: จะเรียกสิ่งต่างๆ ว่าอย่างไร
1. ใช้คำนามพหูพจน์สำหรับคอลเล็กชัน
URL ควรระบุชื่อทรัพยากร ไม่ใช่การดำเนินการ คอลเล็กชันคือชุดของทรัพยากร จึงควรใช้คำนามพหูพจน์
ควรทำ
http
GET /v1/products
GET /v1/products/89
GET /v1/orders
ควรหลีกเลี่ยง
http
GET /v1/getProducts
GET /v1/product
GET /v1/productList
รูปแบบพหูพจน์ใช้ได้ทั้งสองระดับ:
-
/products= คอลเล็กชันของผลิตภัณฑ์ -
/products/89= ผลิตภัณฑ์หมายเลข 89 ในคอลเล็กชัน
รูปแบบเอกพจน์อาจทำให้ URL สับสน เช่น /product/89 สำหรับหนึ่งรายการ แต่ /product สำหรับหลายรายการ แนวทางปฏิบัติของ Microsoft REST API รวมถึง API สาธารณะอย่าง Stripe, GitHub และ Shopify ต่างใช้คำนามพหูพจน์
ข้อยกเว้นคือ ทรัพยากรแบบซิงเกิลตัน (singleton) เช่น ผู้ใช้หนึ่งคนมีตะกร้าสินค้าเพียงใบเดียว:
http
GET /v1[REDACTED PATH]
2. หลีกเลี่ยงคำกริยาในพาธ
เมธอด HTTP ทำหน้าที่เป็นคำกริยาอยู่แล้ว การใส่คำกริยาในพาธจึงซ้ำซ้อนและทำให้โมเดลทรัพยากรไม่ชัดเจน
ควรทำ
http
GET /v1/orders/42
DELETE /v1/orders/42
PATCH /v1/orders/42
ควรหลีกเลี่ยง
http
GET /v1/fetchOrder/42
POST /v1/deleteOrder/42
POST /v1/updateOrderStatus
การใช้คำกริยายังเพิ่มจำนวนเอนด์พอยต์ที่ต้องดูแล ทดสอบ ทำเอกสาร และแคช ตัวอย่างเช่น CDN สามารถแคช GET /v1/orders/42 และทำให้แคชเป็นโมฆะเมื่อ DELETE /v1/orders/42 ได้ เพราะทั้งสองใช้ URL เดียวกัน แต่จะเชื่อมโยง /fetchOrder/42 กับ /deleteOrder/42 ได้ยากกว่า
3. ใช้ kebab-case ในพาธ URL
พาธที่มีหลายคำควรใช้เครื่องหมายขีดกลาง (-) เป็นตัวคั่น
ควรทำ
http
/v1/gift-cards
/v1/shipping-addresses
ควรหลีกเลี่ยง
http
/v1/giftCards
/v1/gift_cards
/v1/GiftCards
เหตุผลสำคัญมีสามข้อ:
- Google ใช้เครื่องหมายขีดกลางเป็นตัวคั่นคำในการจัดทำดัชนี
- เครื่องหมายขีดล่างอาจมองไม่เห็นเมื่อ URL ถูกขีดเส้นใต้ในอีเมลหรือเอกสาร
- camelCase เพิ่มโอกาสเกิดข้อผิดพลาดเรื่องตัวพิมพ์ใหญ่-เล็ก เช่น
/giftCardsและ/giftcardsเป็นคนละ URL บนเซิร์ฟเวอร์ส่วนใหญ่
แนวทางปฏิบัติของ Zalando RESTful API กำหนดให้ใช้ kebab-case และนำไปใช้กับบริการภายในหลายร้อยรายการ
4. เลือกรูปแบบชื่อฟิลด์ JSON เพียงแบบเดียว
ทั้ง camelCase และ snake_case ใช้งานได้ สิ่งที่ควรหลีกเลี่ยงคือการผสมกัน
ควรทำ
เลือกแบบใดแบบหนึ่งและใช้ให้สม่ำเสมอ:
json
{
"orderId": 42,
"createdAt": "2026-08-30T09:15:00Z",
"totalAmount": 4999
}
หรือ:
json
{
"order_id": 42,
"created_at": "2026-08-30T09:15:00Z",
"total_amount": 4999
}
ควรหลีกเลี่ยง
json
{
"orderId": 42,
"created_at": "2026-08-30T09:15:00Z",
"TotalAmount": 4999
}
camelCase เหมาะกับไคลเอนต์ JavaScript และ Java ส่วน snake_case อ่านง่ายและเข้ากับ Ruby, Python รวมถึงชื่อคอลัมน์ SQL โดย Stripe ใช้ snake_case ตลอดทั้ง API
เลือกตามกลุ่มผู้ใช้หลักของ API แล้วบันทึกไว้ในสไตล์ไกด์ การผสมรูปแบบระหว่างเอนด์พอยต์มักเกิดจากการกำกับดูแลที่ไม่เพียงพอ ไม่ใช่เพราะรูปแบบใดรูปแบบหนึ่งดีกว่าโดยสมบูรณ์
5. จำกัดการซ้อนกันไม่เกินสองระดับ
การซ้อนกันช่วยสื่อความเป็นเจ้าของ:
http
[REDACTED PATH]
หมายถึงคำสั่งซื้อของผู้ใช้หมายเลข 42 แต่เมื่อซ้อนลึกเกินสองระดับ URL จะเริ่มใช้งานยาก
ควรทำ
http
GET /v1[REDACTED PATH]
GET /v1/orders/1337/refunds
ควรหลีกเลี่ยง
http
GET /v1[REDACTED PATH]
URL ที่ลึกเกินไปบังคับให้ไคลเอนต์ส่ง ID ของบรรพบุรุษทุกตัว แม้ทรัพยากรปลายทางจะมี ID ที่ไม่ซ้ำกันทั่วโลกก็ตาม
หากการคืนเงินมี ID 7 ให้ใช้:
http
GET /v1/refunds/7
หรือ:
http
GET /v1/orders/1337/refunds/7
กฎง่ายๆ คือ หาก URL มี ID สามตัวขึ้นไป ให้พิจารณาทำให้แบนราบ เมื่อมี /orders/1337 แล้ว ก็ไม่จำเป็นต้องใส่ `[REDACTED PATH]
6. ใส่การกรอง การเรียงลำดับ และการแบ่งหน้าใน query parameters
พาธระบุทรัพยากร ส่วน query parameters ระบุวิธีดูทรัพยากรนั้น อย่าเข้ารหัสตัวกรองไว้ในพาธ
ควรทำ
GET /v1/orders?status=active&sort=-created_at&limit=50&cursor=eyJpZCI6NDJ9
GET /v1/products?category=electronics&min_price=1000
ควรหลีกเลี่ยง
GET /v1/orders/active
GET /v1/orders/sorted-by-date-desc
GET /v1/getOrdersByStatusAndDate
รูปแบบ sort=-created_at ใช้เครื่องหมายลบเพื่อระบุการเรียงจากมากไปน้อย แนวคิดนี้มาจากข้อกำหนด JSON:API และไม่ต้องใช้พารามิเตอร์ order=desc เพิ่ม
พาธอย่าง /orders/active ดูเรียบง่ายในตอนแรก แต่จะมีปัญหาเมื่อจำเป็นต้องรวมหลายตัวกรอง เพราะคุณอาจต้องสร้างเอนด์พอยต์ใหม่สำหรับทุกชุดตัวกรอง
เลือกรูปแบบการแบ่งหน้าให้ชัดเจน เช่น:
-
limitและcursor -
pageและper_page
จากนั้นใช้รูปแบบเดียวกันกับทุกคอลเล็กชัน โดยแนวทางเลือกระหว่าง cursor กับ offset มีรายละเอียดใน คู่มือการแบ่งหน้า API
7. ใช้เวอร์ชันหลักในพาธ
มีสองแนวทางหลักในการกำหนดเวอร์ชัน API:
- ในพาธ:
/v1/products - ในเฮดเดอร์:
Accept: application/vnd.myapi.v1+json
การระบุเวอร์ชันในเฮดเดอร์เป็นแนวทาง REST ที่บริสุทธิ์กว่า เพราะ URL ยังคงระบุทรัพยากรเดิมในทุกเวอร์ชัน และแนวทางการออกแบบ API ของ Google รองรับทั้งสองวิธี
อย่างไรก็ตาม การใส่เวอร์ชันในพาธมีข้อดีในทางปฏิบัติ:
- มองเห็นได้ในล็อกทุกบรรทัด
- ทดสอบได้จากเบราว์เซอร์
- แคชได้ง่ายกว่าโดยไม่ต้องจัดการ
Vary - ไคลเอนต์ไม่สามารถลืมส่งเฮดเดอร์เวอร์ชัน
ใช้เฉพาะเวอร์ชันหลัก:
/v1/products
อย่าใช้เวอร์ชันย่อยใน URL:
/v1.2/products
การเปลี่ยนแปลงเล็กน้อยควรเป็นการเพิ่มเติมที่ไม่ทำลายความเข้ากันได้ สำหรับรายละเอียดเพิ่มเติม โปรดดู กลยุทธ์การกำหนดเวอร์ชัน API
8. ถือว่า ID เป็นค่าทึบและหลีกเลี่ยงตัวเลขลำดับ
ID แบบลำดับเปิดเผยข้อมูลภายในและช่วยให้ผู้โจมตีไล่สำรวจทรัพยากรได้:
/orders/41
/orders/42
/orders/43
รูปแบบนี้ทำให้คาดเดาจำนวนคำสั่งซื้อได้ และเปิดช่องให้เกิด enumeration attacks เพื่อค้นหาทรัพยากรที่ผู้โจมตีไม่ควรเข้าถึง ปัญหานี้เกี่ยวข้องกับ Broken Object Level Authorization (BOLA) ซึ่งอยู่ในอันดับหนึ่งของ OWASP API Security Top 10
ควรทำ
GET /v1/orders/ord_9f8e2a71b3
GET /v1[REDACTED PATH]
ควรหลีกเลี่ยงเมื่อ ID ถูกเปิดเผยต่อสาธารณะ
GET /v1/orders/42
GET /v1/invoices/10883
ID แบบสุ่มที่มีคำนำหน้า เช่น ord_9f8e2a71b3 มีข้อดีหลายด้าน:
- เดายาก
- อ่านแล้วเข้าใจประเภททรัพยากรจากล็อก
- ปลอดภัยกว่าที่จะเปิดเผย
อย่างไรก็ตาม การตรวจสอบสิทธิ์ยังจำเป็นเสมอ ID แบบทึบช่วยลดผลกระทบจากการตรวจสอบที่ผิดพลาด แต่ไม่ใช่สิ่งทดแทน authorization
ภายในระบบยังเก็บ primary key แบบตัวเลขได้ กฎนี้ใช้กับ ID ที่เปิดเผยใน URL เท่านั้น
9. จำลองการกระทำที่ไม่ใช่ CRUD เป็นทรัพยากรตัวควบคุม
บางการกระทำไม่สามารถจับคู่กับ CRUD ได้โดยตรง เช่น:
- ยกเลิกคำสั่งซื้อ
- ลองชำระเงินใหม่
- ส่งอีเมลซ้ำ
อย่าซ่อนการกระทำเหล่านี้ไว้ในการอัปเดตฟิลด์สถานะ และอย่าวางคำกริยาไว้ที่ระดับบนสุด
ควรทำ
POST /v1/orders/42/cancel
POST /v1/payments/pay_88a1/retry
ควรหลีกเลี่ยง
PATCH /v1/orders/42
{ "status": "cancelled" }
POST /v1/cancelOrder
{ "orderId": 42 }
นี่คือรูปแบบ ตัวควบคุม (controller) และเป็นข้อยกเว้นที่เหมาะสมสำหรับกฎห้ามใช้คำกริยาในพาธ: คำกริยาจะอยู่ท้ายพาธ ภายใต้ทรัพยากรที่เกี่ยวข้อง และใช้ POST
PATCH ที่เปลี่ยนสถานะอาจซ่อนผลข้างเคียงสำคัญ เช่น การคืนเงิน การปล่อยสินค้าคงคลัง และการส่งการแจ้งเตือน เอนด์พอยต์อย่าง /cancel ทำให้เจตนาชัดเจน พร้อมเปิดทางให้กำหนดสิทธิ์ การตรวจสอบ และข้อมูลเฉพาะการกระทำ เช่น เหตุผลในการยกเลิก
10. ใช้รูปแบบตัวอักษรของเฮดเดอร์และ query parameters ให้สอดคล้องกัน
เฮดเดอร์แบบกำหนดเองควรใช้ Hyphenated-Pascal-Case:
Idempotency-Key: abc123
[REDACTED IDENTIFIER]_456
ไม่ต้องใช้คำนำหน้า X- แบบเก่า เพราะถูกยกเลิกโดย RFC 6648 ตั้งแต่ปี 2012 แม้ชื่อเฮดเดอร์จะไม่คำนึงถึงตัวพิมพ์ใหญ่-เล็ก แต่เอกสารและ SDK ควรกำหนดรูปแบบการเขียนไว้เพียงแบบเดียว
ชื่อ query parameters ควรสอดคล้องกับรูปแบบ JSON หากเนื้อหาใช้ snake_case ให้ใช้:
?min_price=1000&created_after=2026-01-01
ไม่ใช่:
?minPrice=1000
เมื่อการตอบกลับใช้ created_at แต่วิธีค้นหาใช้ createdAfter นักพัฒนาจะต้องจำรูปแบบสองแบบและมีโอกาสพิมพ์ผิดมากขึ้น
สรุปกฎทั้ง 10 ข้อ
| # | กฎ | ควรทำ | ควรหลีกเลี่ยง |
|---|---|---|---|
| 1 | ใช้คำนามพหูพจน์สำหรับคอลเล็กชัน |
/products, /products/89
|
/getProducts, /productList
|
| 2 | ไม่มีคำกริยาในพาธ | DELETE /orders/42 |
POST /deleteOrder/42 |
| 3 | ใช้ kebab-case ในพาธ | /gift-cards |
/giftCards, /gift_cards
|
| 4 | ใช้รูปแบบ JSON เดียวกัน |
order_id ทุกที่ |
ผสม orderId และ order_id
|
| 5 | จำกัดการซ้อนกันไม่เกินสองระดับ | /orders/1337/refunds |
`[REDACTED PATH] |
| 6 | ใช้ query parameters สำหรับการกรองและแบ่งหน้า | ?status=active&sort=-created_at |
/orders/active |
| 7 | ใช้เวอร์ชันหลักในพาธ | /v1/products |
/v1.2/products, เฮดเดอร์เวอร์ชันที่ไม่สม่ำเสมอ |
| 8 | ใช้ ID แบบทึบ | /orders/ord_9f8e2a71b3 |
/orders/42 ที่เปิดเผยต่อสาธารณะ |
| 9 | ใช้ controller สำหรับการกระทำ | POST /orders/42/cancel |
PATCH พร้อม {"status":"cancelled"}
|
| 10 | ใช้รูปแบบตัวอักษรที่สอดคล้องกัน |
Idempotency-Key, ?min_price=
|
X-IDEMPOTENCY_KEY, ?minPrice=
|
บังคับใช้ข้อตกลงตั้งแต่ขั้นตอนการออกแบบ
คู่มือสไตล์ในวิกิอย่างเดียวไม่เพียงพอ ทีมที่รักษาความสอดคล้องของ API ได้มักมีแนวทางร่วมกันคือ ออกแบบและบังคับใช้ข้อตกลงก่อนเขียนโค้ด ซึ่งเป็นหัวใจของ การกำกับดูแล API
Apidog ช่วยให้ทีมกำหนดเอนด์พอยต์ด้วยตัวออกแบบแบบ schema-first:
- พาธ รูปแบบตัวอักษร และชื่อพารามิเตอร์เป็นส่วนหนึ่งของการออกแบบที่ตรวจสอบได้
- สคีมา Pagination, Error และ Money กำหนดครั้งเดียวแล้วนำกลับมาใช้ซ้ำได้
- ลดความเสี่ยงที่บริการใหม่จะใช้
pageSizeแทนper_page - ตรวจพบชื่ออย่าง
/getUserOrdersได้ตั้งแต่การรีวิวการออกแบบ - ใช้สเปกเดียวกันสร้างเอกสาร เซิร์ฟเวอร์จำลอง และการทดสอบ
การเปลี่ยนชื่อก่อนมีไคลเอนต์ใช้งานเพียงไม่กี่คลิก ย่อมง่ายกว่าการเปลี่ยนหลังมีไคลเอนต์สามรายเชื่อมต่อแล้ว ลอง ดาวน์โหลด Apidog และทดลองใช้ฟรีกับเอนด์พอยต์ใหม่ของคุณ การปรับปรุง API เก่าอาจยาก แต่การรักษามาตรฐานสำหรับ API ใหม่ไม่จำเป็นต้องยาก
คำถามที่พบบ่อย
URL ของ REST ควรเป็นพหูพจน์หรือเอกพจน์?
ใช้รูปแบบพหูพจน์สำหรับทรัพยากรที่มีได้หลายอินสแตนซ์:
http
/products
/orders
/users
รูปแบบนี้ยังเป็นธรรมชาติเมื่ออ้างถึงสมาชิกหนึ่งรายการ:
http
/orders/42
สงวนรูปแบบเอกพจน์ไว้สำหรับ singleton จริงๆ เช่น:
http
[REDACTED PATH]
ดูหลักการเพิ่มเติมได้จากบทความ REST API คืออะไร
camelCase หรือ snake_case แบบไหนดีกว่าสำหรับชื่อฟิลด์ JSON?
ไม่มีรูปแบบใดดีที่สุดสำหรับทุกทีม camelCase เหมาะกับผู้ใช้ JavaScript ส่วน snake_case อ่านง่ายและเข้ากับ Python, Ruby และ API สาธารณะของ Stripe
กฎสำคัญคือเลือกเพียงแบบเดียว บันทึกไว้ในสไตล์ไกด์ และบังคับใช้ในการรีวิวสคีมา
ควรใส่เวอร์ชัน API ใน URL หรือเฮดเดอร์?
ใช้เวอร์ชันในพาธ เช่น /v1/orders เว้นแต่คุณมีความต้องการด้าน hypermedia อย่างชัดเจน เวอร์ชันในพาธมองเห็นได้ในล็อก แคช และการทดสอบผ่านเบราว์เซอร์ โดยไม่ต้องพึ่งการตั้งค่าเฮดเดอร์จากไคลเอนต์
ใช้เฉพาะเวอร์ชันหลัก การเปลี่ยนแปลงเล็กน้อยควรเป็นการเพิ่มเติมที่ไม่กระทบต่อความเข้ากันได้
คำกริยาใช้ในพาธ REST API ได้หรือไม่?
ได้ในกรณีเดียว: เอนด์พอยต์ controller สำหรับการกระทำที่ไม่ใช่ CRUD เช่น:
http
POST /orders/42/cancel
POST /payments/pay_88a1/retry
คำกริยาควรอยู่ท้ายพาธ ภายใต้ทรัพยากรที่เกี่ยวข้อง และใช้เมธอด POST ส่วนเอนด์พอยต์ทั่วไปควรใช้คำนามในพาธ และให้เมธอด HTTP ทำหน้าที่เป็นคำกริยา
Top comments (0)