DEV Community

Cover image for หลักเกณฑ์การตั้งชื่อ REST API: แนวทางปฏิบัติ
Thanawat Wongchai
Thanawat Wongchai

Posted on Originally published at apidog.com

หลักเกณฑ์การตั้งชื่อ REST API: แนวทางปฏิบัติ

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

เหตุผลสำคัญมีสามข้อ:

  1. Google ใช้เครื่องหมายขีดกลางเป็นตัวคั่นคำในการจัดทำดัชนี
  2. เครื่องหมายขีดล่างอาจมองไม่เห็นเมื่อ URL ถูกขีดเส้นใต้ในอีเมลหรือเอกสาร
  3. 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
Enter fullscreen mode Exit fullscreen mode

ควรหลีกเลี่ยง

GET /v1/orders/active
GET /v1/orders/sorted-by-date-desc
GET /v1/getOrdersByStatusAndDate
Enter fullscreen mode Exit fullscreen mode

รูปแบบ 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
Enter fullscreen mode Exit fullscreen mode

อย่าใช้เวอร์ชันย่อยใน URL:

/v1.2/products
Enter fullscreen mode Exit fullscreen mode

การเปลี่ยนแปลงเล็กน้อยควรเป็นการเพิ่มเติมที่ไม่ทำลายความเข้ากันได้ สำหรับรายละเอียดเพิ่มเติม โปรดดู กลยุทธ์การกำหนดเวอร์ชัน API

8. ถือว่า ID เป็นค่าทึบและหลีกเลี่ยงตัวเลขลำดับ

ID แบบลำดับเปิดเผยข้อมูลภายในและช่วยให้ผู้โจมตีไล่สำรวจทรัพยากรได้:

/orders/41
/orders/42
/orders/43
Enter fullscreen mode Exit fullscreen mode

รูปแบบนี้ทำให้คาดเดาจำนวนคำสั่งซื้อได้ และเปิดช่องให้เกิด enumeration attacks เพื่อค้นหาทรัพยากรที่ผู้โจมตีไม่ควรเข้าถึง ปัญหานี้เกี่ยวข้องกับ Broken Object Level Authorization (BOLA) ซึ่งอยู่ในอันดับหนึ่งของ OWASP API Security Top 10

ควรทำ

GET /v1/orders/ord_9f8e2a71b3
GET /v1[REDACTED PATH]
Enter fullscreen mode Exit fullscreen mode

ควรหลีกเลี่ยงเมื่อ ID ถูกเปิดเผยต่อสาธารณะ

GET /v1/orders/42
GET /v1/invoices/10883
Enter fullscreen mode Exit fullscreen mode

ID แบบสุ่มที่มีคำนำหน้า เช่น ord_9f8e2a71b3 มีข้อดีหลายด้าน:

  • เดายาก
  • อ่านแล้วเข้าใจประเภททรัพยากรจากล็อก
  • ปลอดภัยกว่าที่จะเปิดเผย

อย่างไรก็ตาม การตรวจสอบสิทธิ์ยังจำเป็นเสมอ ID แบบทึบช่วยลดผลกระทบจากการตรวจสอบที่ผิดพลาด แต่ไม่ใช่สิ่งทดแทน authorization

ภายในระบบยังเก็บ primary key แบบตัวเลขได้ กฎนี้ใช้กับ ID ที่เปิดเผยใน URL เท่านั้น

9. จำลองการกระทำที่ไม่ใช่ CRUD เป็นทรัพยากรตัวควบคุม

บางการกระทำไม่สามารถจับคู่กับ CRUD ได้โดยตรง เช่น:

  • ยกเลิกคำสั่งซื้อ
  • ลองชำระเงินใหม่
  • ส่งอีเมลซ้ำ

อย่าซ่อนการกระทำเหล่านี้ไว้ในการอัปเดตฟิลด์สถานะ และอย่าวางคำกริยาไว้ที่ระดับบนสุด

ควรทำ

POST /v1/orders/42/cancel
POST /v1/payments/pay_88a1/retry
Enter fullscreen mode Exit fullscreen mode

ควรหลีกเลี่ยง

PATCH /v1/orders/42
{ "status": "cancelled" }

POST /v1/cancelOrder
{ "orderId": 42 }
Enter fullscreen mode Exit fullscreen mode

นี่คือรูปแบบ ตัวควบคุม (controller) และเป็นข้อยกเว้นที่เหมาะสมสำหรับกฎห้ามใช้คำกริยาในพาธ: คำกริยาจะอยู่ท้ายพาธ ภายใต้ทรัพยากรที่เกี่ยวข้อง และใช้ POST

PATCH ที่เปลี่ยนสถานะอาจซ่อนผลข้างเคียงสำคัญ เช่น การคืนเงิน การปล่อยสินค้าคงคลัง และการส่งการแจ้งเตือน เอนด์พอยต์อย่าง /cancel ทำให้เจตนาชัดเจน พร้อมเปิดทางให้กำหนดสิทธิ์ การตรวจสอบ และข้อมูลเฉพาะการกระทำ เช่น เหตุผลในการยกเลิก

10. ใช้รูปแบบตัวอักษรของเฮดเดอร์และ query parameters ให้สอดคล้องกัน

เฮดเดอร์แบบกำหนดเองควรใช้ Hyphenated-Pascal-Case:

Idempotency-Key: abc123
[REDACTED IDENTIFIER]_456
Enter fullscreen mode Exit fullscreen mode

ไม่ต้องใช้คำนำหน้า X- แบบเก่า เพราะถูกยกเลิกโดย RFC 6648 ตั้งแต่ปี 2012 แม้ชื่อเฮดเดอร์จะไม่คำนึงถึงตัวพิมพ์ใหญ่-เล็ก แต่เอกสารและ SDK ควรกำหนดรูปแบบการเขียนไว้เพียงแบบเดียว

ชื่อ query parameters ควรสอดคล้องกับรูปแบบ JSON หากเนื้อหาใช้ snake_case ให้ใช้:

?min_price=1000&created_after=2026-01-01
Enter fullscreen mode Exit fullscreen mode

ไม่ใช่:

?minPrice=1000
Enter fullscreen mode Exit fullscreen mode

เมื่อการตอบกลับใช้ 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)