ใน RESTful API design, PUT และ PATCH คือ HTTP method สองตัวที่ใช้อัปเดต resource บนเซิร์ฟเวอร์ แต่ความแตกต่างระหว่าง PUT กับ PATCH ใน REST API อยู่ที่วิธีดำเนินการอัปเดตและสถานการณ์ที่เหมาะกับแต่ละตัว ทั้งสอง method ออกแบบมาเพื่อแก้ไขข้อมูลที่มีอยู่ แต่การเข้าใจความแตกต่างระหว่าง PUT และ PATCH ใน REST API จะช่วยให้นักพัฒนาเลือกใช้ได้ถูกต้องตามลักษณะของการอัปเดตที่ต้องการ บทความนี้จะอธิบายความแตกต่างระหว่าง PUT และ PATCH ใน REST API โดยเน้นที่การถกเถียงระหว่าง PATCH กับการอัปเดตแบบ REST พร้อมแนะนำว่าควรใช้ตัวใดเมื่อไหร่ และแนวทางเลือก method ที่เหมาะสมสำหรับแต่ละ use case
PUT ใน REST API คืออะไร?
ก่อนจะเข้าใจความแตกต่างระหว่าง PUT กับ PATCH ใน REST API เราต้องรู้จัก PUT ก่อน โดยอ้างอิงจาก ส่วนที่ 9.6 RFC 2616, PUT method ใน REST API ร้องขอให้เก็บ entity ที่แนบมาภายใต้ Request-URI ที่ระบุ
หาก Request-URI อ้างอิงถึง resource ที่มีอยู่แล้ว entity ที่แนบมาควรถือเป็นเวอร์ชันที่แก้ไขแล้วของ resource บน origin server หาก Request-URI ไม่ได้ชี้ไปยัง resource ที่มีอยู่ และ URI นั้นสามารถกำหนดให้เป็น resource ใหม่ได้โดย user agent ที่ร้องขอ origin server ก็สามารถสร้าง resource ใหม่ด้วย URI นั้นได้
กล่าวอีกนัยหนึ่ง PUT method ใช้เพื่ออัปเดต resource ทั้งหมดบนเซิร์ฟเวอร์ นี่ทำให้ PUT เป็นการอัปเดตแบบ "สมบูรณ์" ซึ่งมักใช้เมื่อต้องการแทนที่ resource ทั้งหมด
PUT เหมาะที่สุดสำหรับ use case ต่อไปนี้:
- อัปเดต resource ทั้งหมด (เช่น อัปเดตโปรไฟล์ผู้ใช้ด้วยข้อมูลใหม่ทั้งหมด)
- แทนที่ item หรือ record ทั้งหมด
- เมื่อ identity ของ resource ชัดเจน และต้องการรีเฟรชข้อมูลทั้งหมด
ในระบบต่างๆ เช่น Elasticsearch, การดำเนินการแบบ idempotent จำเป็นต่อการรับประกันความสอดคล้องของข้อมูล ตัวอย่างเช่น การอัปเดตเอกสารใน Elasticsearch ด้วย PUT ทำให้มั่นใจได้ว่าการส่ง request เดิมซ้ำหลายครั้งจะไม่ก่อให้เกิดผลข้างเคียงที่ไม่ต้องการ
PATCH ใน REST API คืออะไร?
เมื่อเราเข้าใจ PUT ใน REST API แล้ว มาดูกันว่า PATCH ใน REST API คืออะไรและทำงานอย่างไร ก่อนที่เราจะเปรียบเทียบ PUT กับ PATCH ใน REST API ตามที่นิยามไว้ใน RFC 5789ในส่วนของ REST API นั้น เมธอด PATCH ทำหน้าที่ส่งคำขอให้เซิร์ฟเวอร์นำชุดการเปลี่ยนแปลงที่ระบุไว้ใน request entity ไปใช้กับ resource ที่ชี้โดย Request-URI
แนวคิดนี้สอดคล้องกับความแตกต่างระหว่าง PUT และ PATCH ใน REST API โดยคุณส่งเฉพาะข้อมูลที่ต้องการแก้ไข แล้วเซิร์ฟเวอร์จะนำการเปลี่ยนแปลงนั้นไปใช้กับ resource ที่มีอยู่โดยไม่แตะส่วนอื่น นักพัฒนามักสร้าง patch เพื่อแสดงการเปลี่ยนแปลงเล็กน้อยเหล่านี้ ซึ่งช่วยลดปริมาณข้อมูลที่รับส่งและทำให้การอัปเดตมีประสิทธิภาพมากขึ้น
เพราะเหตุนี้ เมธอด PATCH ใน REST API จึงเหมาะกับกรณีการใช้งานต่อไปนี้มากกว่า:
- การอัปเดตเฉพาะบางฟิลด์ใน resource เช่น เปลี่ยนอีเมลหรือเบอร์โทรศัพท์ของผู้ใช้ ตัวอย่าง PATCH API อาจเป็นการส่งเฉพาะอีเมลใหม่โดยปล่อยให้ฟิลด์อื่นคงเดิม
- ลดขนาด payload เพื่อเพิ่มประสิทธิภาพการทำงาน
- เมื่อต้องการอัปเดต resource แบบทีละส่วน แทนที่จะแทนที่ทั้งหมด
- สร้าง patch เพื่อระบุการเปลี่ยนแปลงในฟิลด์ที่ต้องการ เช่น แก้ไขอีเมลของผู้ใช้ โดยไม่กระทบข้อมูลส่วนอื่น
สำหรับแพลตฟอร์มอย่าง Headless CMS ที่มักจัดการโครงสร้างเนื้อหาที่ซับซ้อน การใช้ PATCH สำหรับการอัปเดตเล็กน้อย เช่น แก้ไขฟิลด์เดียว ช่วยลดภาระของเซิร์ฟเวอร์และเพิ่มประสิทธิภาพได้
เมื่อครอบคลุมทั้งสองเมธอดแล้ว คุณน่าจะเข้าใจแล้วว่า PUT และ PATCH ใน REST API คืออะไร แต่ก่อนจะไปถึงความแตกต่างระหว่าง PUT กับ PATCH ใน REST API เราต้องพูดถึงเรื่อง Idempotence ในสองเมธอดนี้ก่อน
Idempotence ใน PUT กับ PATCH ใน REST API
ใน REST API นั้น Idempotence หมายถึงคุณสมบัติของ operation ที่เมื่อเรียกซ้ำหลายครั้งด้วย input เดิม จะได้ผลลัพธ์เหมือนเดิมทุกครั้ง กล่าวคือ การส่ง request เดิมซ้ำกี่ครั้งก็ตาม ผลที่เกิดกับเซิร์ฟเวอร์จะเหมือนกันเสมอ คุณสมบัตินี้สำคัญต่อความเสถียรและความคาดเดาได้ของ API แล้วมันเกี่ยวข้องกับความแตกต่างระหว่าง PUT และ PATCH ใน REST API อย่างไร?
PUT Method กับ Idempotence
เมธอด PUT ใน REST API เป็น idempotent เสมอ เพราะออกแบบมาให้แทนที่ resource ทั้งหมดที่ URI ที่กำหนดด้วยข้อมูลใน request พูดง่ายๆ คือ ไม่ว่าจะส่ง PUT request ซ้ำกี่ครั้งด้วยข้อมูลเดิม ผลลัพธ์จะเหมือนกันทุกครั้ง
ทำไม PUT ถึงเป็น Idempotent? เมื่อส่ง PUT request คุณกำลังบอกเซิร์ฟเวอร์ว่า "นี่คือสถานะที่ต้องการสำหรับ resource นี้" ไม่ว่าจะส่ง PUT request ครั้งเดียวหรือหลายครั้ง resource ที่ได้จะเหมือนกันเสมอ
ตัวอย่างเช่น สมมติว่าคุณต้องการอัปเดตอีเมลของผู้ใช้ หากส่ง PUT request เดิมซ้ำหลายครั้ง ผลลัพธ์จะไม่เปลี่ยนแปลง เพราะ resource ถูกแทนที่ด้วยข้อมูลเดิมทุกครั้ง
ตัวอย่าง:
| PUT /users/1{"username": "john_doe","email": "[email protected]"} |
ไม่ว่าจะส่ง request นี้กี่ครั้ง ผลลัพธ์จะเหมือนกันเสมอ:
| {"username": "john_doe","email": "[email protected]"} |
แม้ข้อมูลของผู้ใช้จะเป็นแบบนี้อยู่แล้ว การส่ง request ซ้ำก็ไม่เปลี่ยนแปลงอะไร เพราะเป็นการแทนที่ข้อมูลด้วยข้อมูลเดิม ผลของ request จึงเหมือนกันไม่ว่าจะทำซ้ำกี่ครั้ง นี่คือสิ่งที่ทำให้ PUT เป็น idempotent
PATCH Method กับ Idempotence
เมธอด PATCH ใน REST API นั้น โดยทั่วไปก็เป็น idempotent เช่นกัน แต่มีความยืดหยุ่นมากกว่า เมื่อสร้าง patch ควรออกแบบ operation ให้เป็น idempotent เช่น การกำหนดค่าตรงๆ แทนการเพิ่มค่า เพื่อหลีกเลี่ยงผลข้างเคียงที่ไม่ต้องการจากการส่ง request ซ้ำ ทั้งนี้ ความเป็น idempotent ของ PATCH ขึ้นอยู่กับ operation และข้อมูลที่แก้ไข
ทำไม PATCH ถึงเป็น Idempotent? สำหรับ PATCH request นั้น idempotence หมายความว่าการนำ patch เดิมไปใช้ซ้ำหลายครั้งจะให้ผลลัพธ์เหมือนกัน ซึ่งเป็นจริงตราบใดที่ patch นั้นไม่ก่อให้เกิดผลข้างเคียงหรือการเปลี่ยนแปลงเพิ่มเติมเมื่อนำไปใช้ซ้ำ หากส่ง patch เดิมด้วยข้อมูลเดิมซ้ำๆ ผลลัพธ์หลังจากครั้งแรกจะไม่เปลี่ยนแปลง
ตัวอย่างเช่น ถ้าคุณอัปเดตเฉพาะอีเมลของผู้ใช้ การส่ง PATCH request เดิมซ้ำหลายครั้งจะไม่เปลี่ยนผลลัพธ์หลังจากครั้งแรก อีเมลของผู้ใช้จะคงเดิม และสถานะของ resource จะไม่เปลี่ยนแปลง
ตัวอย่าง PATCH API:
| PATCH /users/1{"email": "[email protected]"} |
หากอีเมลเป็น [email protected] อยู่แล้ว การนำ PATCH นี้ไปใช้ซ้ำจะไม่เกิดการเปลี่ยนแปลง ถือว่าเป็น idempotent
อย่างไรก็ตาม PATCH อาจไม่เป็น idempotent ในบางกรณี ตัวอย่างเช่น ถ้า PATCH operation แก้ไขตัวนับหรือเพิ่มรายการในลิสต์ เช่น การเพิ่มค่าตัวเลขหรือการต่อท้าย array การนำ PATCH เดิมไปใช้ซ้ำหลายครั้งอาจให้ผลลัพธ์ที่ต่างกัน ซึ่งจะละเมิดคุณสมบัติ idempotence
ตัวอย่าง PATCH แบบ Non-idempotent API REST:
| PATCH /counter/1{"increment": 1} |
หากส่ง PATCH นี้ซ้ำหลายครั้ง ค่าของ counter จะเพิ่มขึ้นเรื่อยๆ และได้ผลลัพธ์ที่ต่างกันในแต่ละครั้ง นี่คือลักษณะของการทำงานแบบ non-idempotent เพราะผลลัพธ์เปลี่ยนไปทุกครั้งที่ใช้งาน
เมื่อเข้าใจพื้นฐานแล้ว เราจะมาดูตัวอย่างสถานการณ์จริงเพื่อให้เห็นความแตกต่างระหว่าง PUT กับ PATCH ใน REST API ได้ชัดขึ้น
ตัวอย่างสถานการณ์: PUT กับ PATCH ใน REST API
ทฤษฎีเพียงอย่างเดียวไม่เพียงพอ มาดูความแตกต่างระหว่าง PUT และ PATCH ผ่านตัวอย่างจริง ทั้งแบบ idempotent และ non-idempotent
สถานการณ์ที่ 1: PUT Request – การแทนที่ Resource ทั้งหมด
สมมติว่ามี API endpoint สำหรับจัดการสินค้าในระบบ e-commerce คุณต้องการอัปเดตข้อมูลสินค้าทั้งหมด ทั้งชื่อ ราคา และรายละเอียด นี่คือตัวอย่างทั่วไปของ HTTP method PUT vs PATCH โดย PUT ใช้สำหรับแทนที่ resource สินค้าทั้งหมด
สินค้าเริ่มต้น
| GET /products/1001{"id": 1001,"name": "Laptop","price": 999.99,"description": "A powerful laptop."} |
คุณต้องการอัปเดตราคาและรายละเอียดของสินค้า โดยส่ง PUT request พร้อม resource ทั้งหมด ดังนี้:
PUT Request:
| PUT /products/1001{"id": 1001,"name": "Laptop","price": 899.99,"description": "A discounted powerful laptop."} |
ไม่ว่าจะส่ง PUT request นี้หนึ่งครั้งหรือหลายครั้ง ผลลัพธ์จะเหมือนเดิมทุกครั้ง ข้อมูลสินค้าจะถูกอัปเดตเป็นราคาและรายละเอียดใหม่เสมอ นี่คือคุณสมบัติ idempotent ของ PUT
ผลลัพธ์ (หลัง PUT Request):
| {"id": 1001,"name": "Laptop","price": 899.99,"description": "A discounted powerful laptop."} |
สถานการณ์ที่ 2: PATCH Request – การอัปเดต Resource บางส่วน
มาดูการใช้ PATCH request สำหรับอัปเดตข้อมูลสินค้าเพียงบางส่วน เช่น รายละเอียดสินค้า ตัวอย่าง PATCH API: หากต้องการเปลี่ยนรายละเอียดสินค้าโดยไม่แตะต้องราคา PATCH คือตัวเลือกที่เหมาะกว่า วิธีนี้คือการสร้าง patch ที่ระบุเฉพาะ field ที่ต้องการเปลี่ยน เช่น description ในตัวอย่าง API REST PATCH นี้
สินค้าเริ่มต้น
| GET /products/1001{"id": 1001,"name": "Laptop","price": 999.99,"description": "A powerful laptop."} |
PATCH คำขอ:
| PATCH /products/1001{"description": "A lightweight, powerful laptop."} |
เมื่อส่ง PATCH request นี้ จะมีเพียง field description เท่านั้นที่ถูกอัปเดต และหากส่ง PATCH request เดิมซ้ำหลายครั้ง รายละเอียดจะไม่เปลี่ยนแปลงหลังจากการอัปเดตครั้งแรก ทำให้ request นี้มีคุณสมบัติ idempotent
ผลลัพธ์ (หลัง PATCH Request):
| {"id": 1001,"name": "Laptop","price": 999.99,"description": "A lightweight, powerful laptop."} |
หากส่ง PATCH เดิมซ้ำอีกครั้ง รายละเอียดสินค้าจะยังคงเหมือนกับหลังการ PATCH ครั้งแรก ผลลัพธ์สม่ำเสมอ นี่คือสิ่งที่ทำให้ PATCH มีคุณสมบัติ idempotent ในสถานการณ์นี้
สถานการณ์ที่ 3: PATCH Request – การทำงานแบบ Non-idempotent
มาดูตัวอย่างการใช้ PATCH แบบ non-idempotent สมมติว่ามี endpoint สำหรับจัดการยอดเงินในกระเป๋าของผู้ใช้ และคุณต้องการเพิ่มยอดเงิน ตัวอย่างนี้แสดงให้เห็นความแตกต่างระหว่าง PUT และ PATCH ได้ชัดเจน: PATCH จะเพิ่มค่าลงในยอดเงินทุกครั้งที่เรียกใช้
ยอดเงินเริ่มต้น:
| GET /users/1/wallet{"id": 1,"balance": 100.00} |
PATCH คำขอ:
| PATCH /users/1/wallet{"increment": 50.00} |
PATCH request นี้จะเพิ่มยอดเงินในกระเป๋า $50 ทุกครั้งที่ส่ง หากส่ง PATCH request เดิมซ้ำหลายครั้ง ยอดเงินจะเพิ่มขึ้นเรื่อยๆ และได้ผลลัพธ์ที่ต่างกันในแต่ละครั้ง นี่คือการทำงานแบบ non-idempotent เพราะการส่ง PATCH เดิมซ้ำๆ จะทำให้ผลลัพธ์เปลี่ยนไปทุกครั้ง
ผลลัพธ์ (หลังคำขอ PATCH ครั้งแรก):
| {"id": 1,"balance": 150.00} |
ผลลัพธ์ (หลังคำขอ PATCH ครั้งที่สอง):
| {"id": 1,"balance": 200.00} |
ในกรณีนี้ PATCH ไม่ใช่ idempotent เพราะการส่งคำขอซ้ำด้วยข้อมูลเดิมให้ผลลัพธ์ที่ต่างกัน
สรุป: ความแตกต่างสำคัญระหว่าง PUT กับ PATCH ใน REST API
ความแตกต่างหลักระหว่าง PUT กับ PATCH ใน REST API อยู่ที่วิธีจัดการกับการอัปเดต PUT จะแทนที่ทรัพยากรทั้งหมด ทำให้ฟิลด์ที่ไม่ได้ส่งมาถูกลบออก ซึ่งอาจทำให้ข้อมูลสูญหายได้ นี่คือเหตุผลที่นักพัฒนาใช้ PATCH สำหรับการอัปเดตเฉพาะบางส่วน เพื่อหลีกเลี่ยงการเขียนทับฟิลด์ที่ไม่ได้เปลี่ยนแปลงและรักษาความสมบูรณ์ของข้อมูล
ทำให้ PATCH มีประสิทธิภาพมากกว่าสำหรับการอัปเดตบางส่วน ตัวอย่างเช่น หากต้องการอัปเดตเพียงแค่อีเมลของผู้ใช้ PATCH API จะส่งเฉพาะฟิลด์อีเมล ต่างจากคำขอ PUT ที่ต้องส่งข้อมูลผู้ใช้ทั้งหมด
PUT ต้องการข้อมูลครบทุกฟิลด์ ฟิลด์ใดที่ไม่ได้ส่งมาจะถูกลบออก ส่วน PATCH ส่งเฉพาะฟิลด์ที่ต้องการเปลี่ยนแปลง ทำให้มีประสิทธิภาพมากกว่า โดยเฉพาะกับทรัพยากรขนาดใหญ่ที่มีการเปลี่ยนแปลงเพียงเล็กน้อย PATCH method ใน REST API ช่วยให้คำขอมีขนาดเล็กและเจาะจงมากขึ้น ลดปริมาณข้อมูลที่ต้องส่ง
ทั้ง PUT และ PATCH เป็น idempotent ซึ่งหมายความว่าการส่งคำขอเดิมซ้ำหลายครั้งจะให้ผลลัพธ์เหมือนกัน อย่างไรก็ตาม PUT คาดเดาได้ง่ายกว่า เพราะแทนที่ทรัพยากรทั้งหมดทุกครั้ง ส่วน PATCH ที่ใช้แก้ไขเฉพาะบางฟิลด์อาจให้ผลลัพธ์ต่างกัน ขึ้นอยู่กับวิธีที่ server จัดการกับการอัปเดต
ตัวอย่างเช่น ถ้า PATCH เพิ่มค่า counter ทุกครั้ง การส่งคำขอซ้ำอาจให้ผลลัพธ์ที่ต่างกัน อย่างไรก็ตาม PATCH API operations สามารถออกแบบให้เป็น idempotent ได้เช่นกัน
สรุปแล้ว ความแตกต่างระหว่าง PUT กับ PATCH ใน REST API อยู่ที่ลักษณะของการอัปเดต: PATCH ใช้สำหรับการเปลี่ยนแปลงบางส่วน ส่วน PUT ใช้สำหรับแทนที่ทรัพยากรทั้งหมด ทั้งคู่เป็น idempotent แต่ PATCH มีความซับซ้อนกว่า
สรุป
ทั้ง PUT และ PATCH เป็น HTTP methods พื้นฐานในการออกแบบ REST API แต่มีวัตถุประสงค์ต่างกัน การเข้าใจความแตกต่างระหว่างทั้งสองผ่านตัวอย่างที่นำเสนอในบทความนี้จะช่วยให้ API ของคุณมีประสิทธิภาพ ชัดเจน และใช้งานได้ดียิ่งขึ้น การเลือก method ที่เหมาะสม (PATCH กับ REST) ตามการใช้งานจริงจะทำให้ API ของคุณดูแลรักษาง่ายและใช้งานสะดวกขึ้น ควรพิจารณาทุกครั้งว่าการอัปเดตนั้นเป็นแบบเต็มหรือบางส่วน รวมถึงผลกระทบต่อประสิทธิภาพและความสมบูรณ์ของข้อมูล แล้วเลือก method ที่ตรงกับความต้องการที่สุด