การใช้วิธี PUT กับ PATCH ในสถานการณ์จริงของ REST API


681

ก่อนอื่นคำจำกัดความบางอย่าง:

PUT ถูกกำหนดในส่วน 9.6 RFC 2616 :

วิธี PUT ร้องขอให้เก็บเอนทิตีที่ถูกล้อมไว้ภายใต้ Request-URI ที่ให้มา ถ้าขอ URI หมายถึงทรัพยากรที่มีอยู่แล้วนิติบุคคลที่แนบมาควรจะถือว่าเป็นรุ่นที่ปรับเปลี่ยนคนที่อาศัยอยู่บนเซิร์ฟเวอร์ต้นทาง หาก Request-URI ไม่ได้ชี้ไปที่ทรัพยากรที่มีอยู่และ URI นั้นสามารถกำหนดเป็นทรัพยากรใหม่โดยตัวแทนผู้ใช้ที่ร้องขอเซิร์ฟเวอร์ต้นทางสามารถสร้างทรัพยากรด้วย URI นั้น

PATCH ถูกกำหนดในRFC 5789 :

วิธีการ PATCH ขอให้ชุดของการเปลี่ยนแปลงที่อธิบายไว้ในเอนทิตีคำขอจะนำไปใช้กับทรัพยากรที่ระบุโดย Request- URI

นอกจากนี้ตามRFC 2616 มาตรา 9.1.2 PUT นั้นเป็น Idempotent ในขณะที่ PATCH นั้นไม่ได้เป็น

ตอนนี้ให้เราดูตัวอย่างจริง เมื่อฉันจะโพสต์ไป/usersกับข้อมูล{username: 'skwee357', email: 'skwee357@domain.com'}และเซิร์ฟเวอร์ที่มีความสามารถในการสร้างทรัพยากรก็จะตอบสนองกับ 201 สถานที่ตั้งทรัพยากร (สมมติ/users/1) และโทรไปใด ๆ ที่จะได้รับจะกลับมา/users/1{id: 1, username: 'skwee357', email: 'skwee357@domain.com'}

ตอนนี้ให้เราบอกว่าฉันต้องการแก้ไขอีเมลของฉัน การปรับเปลี่ยนอีเมลถือเป็น "ชุดของการเปลี่ยนแปลง" ดังนั้นฉันควร PATCH /users/1ด้วย " เอกสารแก้ไข " ในกรณีของฉันมันจะเป็นเอกสาร JSON {email: 'skwee357@newdomain.com'}นี้: เซิร์ฟเวอร์จะคืนค่า 200 (สมมติว่าได้รับอนุญาต) สิ่งนี้ทำให้ฉันถึงคำถามแรก:

  • PATCH ไม่ใช่ idempotent มันกล่าวอย่างนั้นใน RFC 2616 และ RFC 5789 อย่างไรก็ตามถ้าฉันออกคำขอ PATCH เดียวกัน (ด้วยอีเมลใหม่ของฉัน) ฉันจะได้รับสถานะทรัพยากรเดียวกัน (อีเมลของฉันจะถูกปรับเปลี่ยนเป็นค่าที่ร้องขอ) ทำไม PATCH ถึงไม่เป็น idempotent?

PATCH เป็นคำกริยาที่ค่อนข้างใหม่ (RFC ที่นำมาใช้ในเดือนมีนาคม 2010) และมาเพื่อแก้ไขปัญหาของ "การแพตช์" หรือแก้ไขชุดของฟิลด์ ก่อนที่จะมีการนำ PATCH ทุกคนใช้ PUT เพื่ออัปเดตทรัพยากร แต่หลังจากแนะนำ PATCH มันทำให้ฉันสับสนเกี่ยวกับสิ่งที่ PUT ใช้ และนี่นำฉันไปสู่คำถามที่สอง (และหลัก):

  • ความแตกต่างที่แท้จริงระหว่าง PUT และ PATCH คืออะไร? ฉันได้อ่านบางที่อาจใช้ PUT เพื่อแทนที่เอนทิตีทั้งหมดภายใต้ทรัพยากรเฉพาะดังนั้นหนึ่งควรส่งเอนทิตีแบบเต็ม (แทนที่จะเป็นชุดของคุณลักษณะเช่นเดียวกับ PATCH) การใช้งานจริงสำหรับกรณีดังกล่าวคืออะไร? เมื่อใดที่คุณต้องการแทนที่ / เขียนทับเอนทิตีที่ URI ทรัพยากรเฉพาะและเหตุใดการดำเนินการดังกล่าวจึงไม่ถือว่าเป็นการอัปเดต / แก้ไขเอนทิตี กรณีการใช้งานจริงที่ฉันเห็นสำหรับ PUT คือการออก PUT ในคอลเล็กชันคือ/usersเพื่อแทนที่คอลเลกชันทั้งหมด การออก PUT บนเอนทิตีที่ระบุไม่เหมาะสมหลังจาก PATCH ถูกนำมาใช้ ฉันผิดหรือเปล่า?

1
ก) เป็น RFC 2616 ไม่ใช่ 2612 ข) RFC 2616 ล้าสมัยแล้วข้อกำหนดปัจจุบันของ PUT อยู่ในgreenbytes.de/tech/webdav/rfc7231.html#PUT , c) ฉันไม่ได้รับคำถามของคุณ ไม่ชัดเจนใช่ไหมว่า PUT สามารถใช้เพื่อแทนที่ทรัพยากรใด ๆ ไม่เพียง แต่เป็นคอลเลกชัน d) ก่อนที่จะมีการแนะนำ PATCH ผู้คนมักใช้ POST, e) ในที่สุดใช่คำขอ PATCH เฉพาะ (ขึ้นอยู่กับรูปแบบแพทช์) สามารถ idempotent; มันเป็นเพียงแค่ว่ามันไม่ได้โดยทั่วไป
Julian Reschke

ถ้ามันช่วยฉันได้เขียนบทความเกี่ยวกับ PATCH กับ PUT eq8.eu/blogs/36-patch-vs-put-and-the-patch-json-syntax-war
เทียบเท่า

5
ง่าย: POST สร้างรายการในคอลเลกชัน PUT แทนที่รายการ PATCH แก้ไขรายการ เมื่อทำการ POST URL สำหรับไอเท็มใหม่จะถูกคำนวณและส่งคืนในการตอบสนองขณะที่ PUT และ PATCH ต้องการ URL ในคำขอ ขวา?
Tom Russell

โพสต์นี้อาจมีประโยชน์: POST เทียบกับ PUT เทียบกับ PATCH: mscharhag.com/api-design/http-post-put-patch
micha

คำตอบ:


943

หมายเหตุ : เมื่อฉันใช้เวลาอ่านเกี่ยวกับ REST เป็นครั้งแรก idempotence เป็นแนวคิดที่สับสนที่จะพยายามทำให้ถูกต้อง ฉันยังไม่เข้าใจในคำตอบดั้งเดิมของฉันเนื่องจากความคิดเห็นเพิ่มเติม (และคำตอบของ Jason Hoetger ) ได้แสดงขึ้น ในขณะที่ฉันได้ต่อต้านการปรับปรุงคำตอบนี้อย่างกว้างขวางเพื่อหลีกเลี่ยงการขโมยความคิดอย่างมีประสิทธิภาพเจสัน แต่ตอนนี้ฉันกำลังแก้ไขเพราะเพราะฉันถูกขอให้ (ในความคิดเห็น)

หลังจากอ่านคำตอบของฉันฉันขอแนะนำให้คุณอ่านคำตอบที่ยอดเยี่ยมของ Jason Hoetgerและฉันจะพยายามทำให้คำตอบของฉันดีขึ้นโดยไม่ขโมยจาก Jason

ทำไมต้องใส่ idempotent?

ดังที่คุณบันทึกไว้ในการอ้างอิง RFC 2616 ของคุณ PUT ถือว่าเป็น idempotent เมื่อคุณใส่ทรัพยากรข้อสันนิษฐานสองข้อนี้อยู่ในระหว่างเล่น:

  1. คุณกำลังอ้างถึงเอนทิตีไม่ใช่การรวบรวม

  2. เอนทิตีที่คุณกำลังจัดหาเสร็จสมบูรณ์ ( เอนทิตีทั้งหมด )

ลองดูตัวอย่างหนึ่งของคุณ

{ "username": "skwee357", "email": "skwee357@domain.com" }

หากคุณโพสต์เอกสารนี้/usersตามที่คุณแนะนำคุณอาจได้รับเอนทิตีกลับเช่น

## /users/1

{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}

หากคุณต้องการแก้ไขเอนทิตีนี้ในภายหลังคุณเลือกระหว่าง PUT และ PATCH PUT อาจมีลักษณะเช่นนี้:

PUT /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // new email address
}

คุณสามารถทำได้เหมือนกันโดยใช้ PATCH ที่อาจมีลักษณะเช่นนี้:

PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

คุณจะสังเกตเห็นความแตกต่างได้ทันทีระหว่างสองสิ่งนี้ PUT รวมพารามิเตอร์ทั้งหมดในผู้ใช้รายนี้ แต่ PATCH รวมเฉพาะพารามิเตอร์ที่กำลังแก้ไข ( email)

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

เนื่องจากคำขอ PUT รวมถึงเอนทิตีทั้งหมดหากคุณออกคำขอเดียวกันซ้ำแล้วซ้ำอีกจึงควรมีผลลัพธ์เดียวกันเสมอ (ข้อมูลที่คุณส่งเป็นข้อมูลทั้งหมดของเอนทิตีในขณะนี้) ดังนั้น PUT จึงเป็น idempotent

ใช้ PUT ผิด

จะเกิดอะไรขึ้นถ้าคุณใช้ข้อมูล PATCH ข้างต้นในคำขอ PUT

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}
PUT /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

GET /users/1
{
    "email": "skwee357@gmail.com"      // new email address... and nothing else!
}

(ฉันสมมติว่าเพื่อจุดประสงค์ของคำถามนี้ว่าเซิร์ฟเวอร์ไม่มีฟิลด์ที่ต้องระบุและจะอนุญาตให้สิ่งนี้เกิดขึ้น ... ซึ่งอาจไม่เป็นจริงในกรณีนี้)

เนื่องจากเราใช้ PUT แต่ให้มาเท่านั้นemailตอนนี้เป็นสิ่งเดียวในเอนทิตีนี้ ส่งผลให้ข้อมูลสูญหาย

ตัวอย่างนี้มีไว้เพื่อเป็นตัวอย่าง - ไม่เคยทำเช่นนี้ คำขอ PUT นี้เป็น idempotent ทางเทคนิค แต่นั่นไม่ได้หมายความว่ามันไม่ใช่ความคิดที่แย่มาก

PATCH จะเป็น idempotent ได้อย่างไร?

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

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}
PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // email address was changed
}
PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address... again
}

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // nothing changed since last GET
}

ตัวอย่างดั้งเดิมของฉันได้รับการแก้ไขเพื่อความถูกต้อง

ตอนแรกฉันมีตัวอย่างที่ฉันคิดว่าแสดงให้เห็นว่าไม่ใช่ idempotency แต่พวกเขาทำให้เข้าใจผิด / ไม่ถูกต้อง ฉันจะเก็บตัวอย่าง แต่ใช้พวกเขาเพื่อแสดงสิ่งที่แตกต่าง: ที่เอกสาร PATCH หลายตัวกับเอนทิตีเดียวกันปรับเปลี่ยนคุณสมบัติที่แตกต่างกันอย่าทำให้ PATCHes ไม่ใช่ idempotent

สมมติว่าในช่วงเวลาที่ผ่านมามีการเพิ่มผู้ใช้ นี่คือสถานะที่คุณเริ่มต้น

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@olddomain.com",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

หลังจาก PATCH คุณมีเอนทิตีที่แก้ไข:

PATCH /users/1
{"email": "skwee357@newdomain.com"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",    // the email changed, yay!
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

หากคุณใช้ PATCH ซ้ำหลายครั้งคุณจะได้รับผลลัพธ์เดิมต่อไป: อีเมลถูกเปลี่ยนเป็นค่าใหม่ A เข้า, ออกมา, ดังนั้นนี่คือ idempotent

อีกหนึ่งชั่วโมงต่อมาหลังจากที่คุณไปทำกาแฟและพักสมองคนอื่นมาพร้อมกับแพทช์ของตัวเอง ดูเหมือนว่าที่ทำการไปรษณีย์ได้ทำการเปลี่ยนแปลงบางอย่าง

PATCH /users/1
{"zip": "12345"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",  // still the new email you set
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"                      // and this change as well
}

เนื่องจาก PATCH นี้จากที่ทำการไปรษณีย์ไม่เกี่ยวข้องกับอีเมลจึงมีเพียงรหัสไปรษณีย์เท่านั้นหากมีการใช้ซ้ำหลายครั้งจึงจะได้รับผลลัพธ์เดียวกัน: รหัสไปรษณีย์ถูกตั้งค่าเป็นค่าใหม่ ไปในออกมาดังนั้นนี้เป็นยัง idempotent

ในวันถัดไปคุณตัดสินใจที่จะส่งแพตช์ของคุณอีกครั้ง

PATCH /users/1
{"email": "skwee357@newdomain.com"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"
}

แพทช์ของคุณมีผลเช่นเดียวกันกับเมื่อวาน: ตั้งค่าที่อยู่อีเมล เข้าไปข้างใน, A ออกมา, ดังนั้นนี่คือ idempotent เช่นกัน.

สิ่งที่ฉันทำผิดในคำตอบเดิมของฉัน

ฉันต้องการวาดความแตกต่างที่สำคัญ (สิ่งที่ฉันผิดในคำตอบเดิมของฉัน) เซิร์ฟเวอร์จำนวนมากจะตอบสนองต่อคำขอ REST ของคุณโดยส่งสถานะเอนทิตีใหม่พร้อมการแก้ไขของคุณ (ถ้ามี) ดังนั้นเมื่อคุณได้รับการตอบกลับนี้มันแตกต่างจากที่คุณได้รับเมื่อวานนี้เนื่องจากรหัสไปรษณีย์ไม่ใช่ที่คุณได้รับครั้งล่าสุด อย่างไรก็ตามคำขอของคุณไม่เกี่ยวข้องกับรหัสไปรษณีย์เฉพาะกับอีเมลเท่านั้น ดังนั้นเอกสาร PATCH ของคุณยังคงเป็น idempotent - อีเมลที่คุณส่งเป็น PATCH ในขณะนี้คือที่อยู่อีเมลในเอนทิตี

ดังนั้นเมื่อ PATCH ไม่ใช่ idempotent แล้ว

สำหรับการรักษาเต็มรูปแบบของคำถามนี้ผมอีกครั้งดูคุณคำตอบของเจสัน Hoetger ฉันจะทิ้งมันไว้ที่นั้นเพราะฉันคิดว่าฉันไม่สามารถตอบส่วนนี้ได้ดีกว่าเขา


2
ประโยคนี้ไม่ถูกต้อง: "แต่มันเป็น idempotent: เมื่อใดก็ตามที่ A เข้า B จะออกมาเสมอ" ตัวอย่างเช่นหากคุณทำGET /users/1ก่อนที่ที่ทำการไปรษณีย์จะอัปเดตรหัสไปรษณีย์จากนั้นทำการGET /users/1ร้องขอเดียวกันอีกครั้งหลังจากการอัปเดตของที่ทำการไปรษณีย์คุณจะได้รับการตอบกลับสองแบบที่แตกต่างกัน (รหัสไปรษณีย์ที่แตกต่างกัน) "A" (คำขอ GET) เดียวกันกำลังดำเนินการอยู่ แต่คุณได้รับผลลัพธ์ที่แตกต่างกัน ถึงกระนั้น GET ก็ยังเป็นคนบ้าคลั่ง
Jason Hoetger

@JasonHoetger GET นั้นปลอดภัย (สันนิษฐานว่าไม่ทำให้เกิดการเปลี่ยนแปลง) แต่ไม่ได้เป็น idempotent เสมอไป มีความแตกต่าง ดูRFC 2616 วินาที 9.1 .
Dan Lowe

1
@DanLowe: รับประกันได้แน่นอนที่สุดว่า idempotent มีการระบุอย่างชัดเจนว่าในส่วน 9.1.2 ของ RFC 2616 และในข้อมูลจำเพาะที่อัปเดตRFC 7231 ส่วน 4.2.2นั้น "วิธีการร้องขอที่กำหนดโดยข้อกำหนดนี้ PUT, DELETE และวิธีการร้องขอที่ปลอดภัยนั้นเป็น idempotent" Idempotence ไม่ได้หมายความว่า "คุณจะได้รับการตอบสนองแบบเดียวกันทุกครั้งที่คุณทำการร้องขอเดียวกัน" 7231 4.2.2 กล่าวต่อไปว่า: "การทำซ้ำการร้องขอจะมีผลเหมือนกันแม้ว่าการร้องขอดั้งเดิมจะสำเร็จแม้ว่าการตอบกลับอาจแตกต่างกัน "
Jason Hoetger

1
@ JasonHoetger ฉันจะยอมรับว่า แต่ฉันไม่เห็นสิ่งที่จะทำอย่างไรกับคำตอบนี้ซึ่งกล่าวถึง PUT และ PATCH และไม่เคยกล่าวถึง GET ...
Dan Lowe

1
อ่าความคิดเห็นจาก @JasonHoetger ลบมันออก: มีเพียงสถานะที่เป็นผลลัพธ์มากกว่าการตอบสนองของการร้องขอเมธอด idempotent หลายวิธีที่ต้องเหมือนกัน
Tom Russell

329

ถึงแม้ว่าคำตอบที่ยอดเยี่ยมของแดนโลว์จะตอบคำถามของ OP อย่างละเอียดเกี่ยวกับความแตกต่างระหว่าง PUT และ PATCH แต่คำตอบสำหรับคำถามที่ว่าทำไม PATCH ไม่ใช่ idempotent นั้นไม่ถูกต้องนัก

เพื่อแสดงว่าทำไม PATCH ไม่ใช่ idempotent มันจะช่วยให้เริ่มต้นด้วยนิยามของ idempotence (จากWikipedia ):

คำว่า idempotent ถูกใช้อย่างละเอียดเพื่ออธิบายการดำเนินการที่จะให้ผลลัพธ์เดียวกันหากดำเนินการครั้งเดียวหรือหลายครั้ง [... ] ฟังก์ชั่น idempotent เป็นฟังก์ชันที่มีคุณสมบัติ f (f (x)) = f (x) สำหรับ ค่าใด ๆ x

ในภาษาที่สามารถเข้าถึงได้มากขึ้น PAD idempotent สามารถกำหนดเป็น: หลังจากการจับทรัพยากรด้วยเอกสารปะแก้ PATCH ที่ตามมาทั้งหมดจะเรียกใช้ทรัพยากรเดียวกันด้วยเอกสารแก้ไขที่เหมือนกันจะไม่เปลี่ยนทรัพยากร

ในทางกลับกันการดำเนินการที่ไม่ใช่ idempotent คือการดำเนินการที่ f (f (x))! = f (x) ซึ่งสำหรับ PATCH อาจกล่าวได้ว่า: หลังจากการจับทรัพยากรด้วยเอกสารแพทช์ PATCH ที่ตามมาจะเรียกทรัพยากรเดียวกันกับ เอกสารแก้ไขเดียวกันจะเปลี่ยนทรัพยากร

ในการแสดง PATCH ที่ไม่ใช่ idempotent สมมติว่ามีทรัพยากร / users และสมมติว่าการโทรGET /usersส่งคืนรายการผู้ใช้ในปัจจุบัน:

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" }]

แทนที่จะเป็น PATCHing / users / {id} ดังเช่นในตัวอย่างของ OP สมมติว่าเซิร์ฟเวอร์อนุญาตให้ใช้ PATCHing / users มาออกคำขอ PATCH นี้กัน:

PATCH /users
[{ "op": "add", "username": "newuser", "email": "newuser@example.org" }]

เอกสารแก้ไขของเราแนะนำให้เซิร์ฟเวอร์เพิ่มผู้ใช้ใหม่ที่เรียกว่าnewuserลงในรายการผู้ใช้ หลังจากเรียกสิ่งนี้เป็นครั้งแรกGET /usersจะกลับมา:

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },
 { "id": 2, "username": "newuser", "email": "newuser@example.org" }]

ตอนนี้ถ้าเราออกคำขอแพทช์เดียวกันตามที่กล่าวมาแล้วจะเกิดอะไรขึ้น (สำหรับตัวอย่างนี้สมมติว่าทรัพยากร / users อนุญาตให้ชื่อผู้ใช้ซ้ำกัน) "op" คือ "เพิ่ม" ดังนั้นผู้ใช้ใหม่จะถูกเพิ่มในรายการและGET /usersผลตอบแทนที่ตามมา:

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },
 { "id": 2, "username": "newuser", "email": "newuser@example.org" },
 { "id": 3, "username": "newuser", "email": "newuser@example.org" }]

ทรัพยากร / users มีการเปลี่ยนแปลงอีกครั้งแม้ว่าเราจะออกPATCH เดียวกันกับปลายทางเดียวกัน หาก PATCH ของเราคือ f (x), f (f (x)) ไม่ได้เช่นเดียวกับ f (x) และดังนั้นแพทช์นี้โดยเฉพาะอย่างยิ่งไม่ idempotent

แม้ว่า PATCH จะไม่รับประกันว่าจะเป็น idempotent แต่ก็ไม่มีสิ่งใดในข้อกำหนด PATCH ที่จะป้องกันไม่ให้คุณทำการ PATCH ทั้งหมดบน idempotent เซิร์ฟเวอร์ของคุณ RFC 5789 ยังคาดหวังข้อได้เปรียบจากคำขอแพทช์ idempotent:

คำขอ PATCH สามารถออกในลักษณะที่เป็น idempotent ซึ่งช่วยป้องกันผลลัพธ์ที่ไม่ดีจากการชนระหว่างคำขอ PATCH สองครั้งในทรัพยากรเดียวกันในกรอบเวลาที่คล้ายกัน

ในตัวอย่างของแดนการดำเนินการแพทช์ของเขาในความเป็นจริง idempotent ในตัวอย่างนั้นเอนทิตี / users / 1 เปลี่ยนไประหว่างคำขอ PATCH ของเรา แต่ไม่ใช่เพราะคำขอ PATCH ของเรา มันเป็นจริงสำนักงานของโพสต์ที่แตกต่างกันเอกสารแพทช์ที่ทำให้เกิดรหัสไปรษณีย์เพื่อการเปลี่ยนแปลง PATCH ที่แตกต่างกันของที่ทำการไปรษณีย์นั้นเป็นการดำเนินการที่แตกต่างกัน ถ้าแพทช์ของเราคือ f (x) แพทช์ของที่ทำการไปรษณีย์คือ g (x) idempotence กล่าวว่าf(f(f(x))) = f(x)แต่ทำให้ guarantes f(g(f(x)))ไม่เกี่ยวกับ


11
สมมติว่าเซิร์ฟเวอร์อนุญาตให้ออก PUT ที่/usersนี่จะทำให้ PUT ไม่ใช่ idempotent เช่นกัน ทั้งหมดนี้เกิดขึ้นกับวิธีที่เซิร์ฟเวอร์ออกแบบมาเพื่อจัดการกับคำขอ
Uzair Sajid

13
ดังนั้นเราสามารถสร้าง API ด้วยการดำเนินการ PATCH เท่านั้น จากนั้นอะไรคือหลักการส่วนที่เหลือของการใช้ http VERBS เพื่อทำการกระทำ CRUD กับทรัพยากร เราไม่ได้ทำให้สุภาพบุรุษแพทช์ซับซ้อนเกินไปที่นี่หรือ
bohr

6
หากมีการนำ PUT ไปใช้กับคอลเลกชัน (เช่น/users) คำขอ PUT ใด ๆ ควรแทนที่เนื้อหาของคอลเล็กชันนั้น ดังนั้น PUT ที่/usersควรคาดหวังการรวบรวมผู้ใช้และลบผู้อื่นทั้งหมด นี่คือ idempotent ไม่น่าเป็นไปได้ที่คุณจะทำสิ่งนี้ใน / a users endpoint แต่สิ่งที่คล้ายกัน/users/1/emailsอาจเป็นคอลเล็กชันและอาจใช้ได้อย่างสมบูรณ์เพื่ออนุญาตให้แทนที่คอลเล็กชันทั้งหมดด้วยคอลเล็กชันใหม่
Vectorjohn

5
แม้ว่าคำตอบนี้จะให้ตัวอย่างที่ดีเกี่ยวกับ idempotence แต่ฉันเชื่อว่านี่อาจทำให้โคลนในสถานการณ์ปกติทั่วไป ในกรณีนี้คุณมีคำขอ PATCH พร้อมการopดำเนินการเพิ่มเติมที่เรียกใช้ตรรกะฝั่งเซิร์ฟเวอร์เฉพาะ สิ่งนี้จะทำให้เซิร์ฟเวอร์และไคลเอนต์ต้องรับรู้ถึงค่าเฉพาะที่จะส่งผ่านสำหรับopฟิลด์เพื่อทริกเกอร์เวิร์กโฟลว์ฝั่งเซิร์ฟเวอร์ ในสถานการณ์ REST ที่ตรงไปตรงมามากขึ้นการใช้งานประเภทนี้opเป็นแนวปฏิบัติที่ไม่ดีและควรได้รับการจัดการโดยตรงผ่านคำกริยา HTTP
ivandov

7
ฉันจะไม่พิจารณาออกแพทช์เพียงโพสต์และลบกับคอลเลกชัน มันเคยทำจริงเหรอ? ดังนั้น PATCH จึงถือได้ว่าเป็น idempotent สำหรับการใช้งานจริงทั้งหมดหรือไม่?
Tom Russell

72

ฉันอยากรู้เกี่ยวกับเรื่องนี้เช่นกันและพบบทความที่น่าสนใจไม่กี่ ฉันอาจไม่ตอบคำถามของคุณอย่างเต็มที่ แต่อย่างน้อยก็ให้ข้อมูลเพิ่มเติมบางอย่าง

http://restful-api-design.readthedocs.org/en/latest/methods.html

HTTP RFC ระบุว่า PUT ต้องทำการแสดงทรัพยากรใหม่แบบเต็มเป็นเอนทิตีที่ร้องขอ ซึ่งหมายความว่าหากมีการจัดเตรียมเฉพาะบางแอตทริบิวต์เท่านั้นควรจะลบออก (เช่นตั้งค่าเป็นโมฆะ)

ระบุว่าแล้ว PUT ควรส่งวัตถุทั้งหมด ตัวอย่างเช่น

/users/1
PUT {id: 1, username: 'skwee357', email: 'newemail@domain.com'}

นี่จะปรับปรุงอีเมลอย่างมีประสิทธิภาพ เหตุผลที่ PUT อาจไม่มีประสิทธิภาพมากเกินไปก็คือการแก้ไขช่องเดียวและรวมถึงชื่อผู้ใช้นั้นไร้ประโยชน์ ตัวอย่างถัดไปแสดงความแตกต่าง

/users/1
PUT {id: 1, email: 'newemail@domain.com'}

ตอนนี้ถ้า PUT ได้รับการออกแบบตามสเป็คแล้ว PUT จะตั้งชื่อผู้ใช้เป็นโมฆะและคุณจะได้รับกลับดังต่อไปนี้

{id: 1, username: null, email: 'newemail@domain.com'}

เมื่อคุณใช้ PATCH คุณจะอัปเดตเฉพาะฟิลด์ที่คุณระบุและปล่อยให้ส่วนที่เหลืออยู่ตามลำพังในตัวอย่างของคุณ

สิ่งต่อไปนี้บนแพทช์แตกต่างจากที่ฉันไม่เคยเห็นมาก่อน

http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/

ความแตกต่างระหว่างคำขอ PUT และ PATCH จะสะท้อนให้เห็นในวิธีที่เซิร์ฟเวอร์ประมวลผลเอนทิตีที่ปิดล้อมเพื่อแก้ไขทรัพยากรที่ระบุโดย Request-URI ในคำขอ PUT เอนทิตีที่ปิดล้อมจะถือเป็นเวอร์ชันดัดแปลงของทรัพยากรที่เก็บไว้ในเซิร์ฟเวอร์ต้นทางและไคลเอนต์ร้องขอให้แทนที่เวอร์ชันที่เก็บไว้ อย่างไรก็ตามด้วย PATCH เอนทิตีที่ล้อมรอบจะมีชุดคำสั่งที่อธิบายถึงวิธีที่ทรัพยากรที่อยู่บนเซิร์ฟเวอร์ต้นทางควรได้รับการแก้ไขเพื่อสร้างเวอร์ชันใหม่ วิธีการ PATCH ส่งผลกระทบต่อทรัพยากรที่ระบุโดย Request-URI และอาจมีผลข้างเคียงต่อทรัพยากรอื่น ๆ กล่าวคืออาจมีการสร้างทรัพยากรใหม่หรือสิ่งที่มีอยู่เดิมโดยการประยุกต์ใช้ PATCH

PATCH /users/123

[
    { "op": "replace", "path": "/email", "value": "new.email@example.org" }
]

คุณกำลังปฏิบัติต่อ PATCH มากขึ้นหรือน้อยลงเป็นวิธีการอัปเดตฟิลด์ ดังนั้นแทนที่จะส่งผ่านวัตถุบางส่วนคุณกำลังส่งผ่านการดำเนินการ เช่นแทนที่อีเมลด้วยค่า

บทความลงท้ายด้วยสิ่งนี้

เป็นมูลค่าการกล่าวขวัญว่า PATCH ไม่ได้ออกแบบมาเพื่อ REST APIs อย่างแท้จริงเนื่องจากการทำวิทยานิพนธ์ของ Fielding ไม่ได้กำหนดวิธีการใด ๆ ในการปรับเปลี่ยนทรัพยากรบางส่วน แต่ Roy Fielding เองบอกว่า PATCH เป็นสิ่งที่ [เขา] สร้างขึ้นสำหรับข้อเสนอ HTTP / 1.1 เริ่มต้นเนื่องจาก PUT บางส่วนไม่เคยสงบ แน่นอนว่าคุณไม่ได้ถ่ายโอนการเป็นตัวแทนที่สมบูรณ์ แต่ REST ไม่ต้องการการรับรองเพื่อให้สมบูรณ์

ตอนนี้ฉันไม่รู้ว่าฉันเห็นด้วยอย่างยิ่งกับบทความหรือไม่ การส่งผ่านการเป็นตัวแทนบางส่วนสามารถเป็นคำอธิบายของการเปลี่ยนแปลงได้อย่างง่ายดาย

สำหรับฉันฉันผสมกับการใช้แพทช์ ส่วนใหญ่ฉันจะถือว่า PUT เป็นแพทช์เนื่องจากความแตกต่างที่แท้จริงที่ฉันสังเกตเห็นคือ PUT "ควร" ตั้งค่าที่หายไปเป็นโมฆะ มันอาจไม่ใช่วิธีที่ 'ถูกต้องที่สุด' แต่โชคดีในการเขียนโค้ดที่สมบูรณ์แบบ


7
อาจเป็นการเพิ่มมูลค่า: ในบทความของ William Durand (และ rfc 6902) มีตัวอย่างที่ "op" คือ "เพิ่ม" เห็นได้ชัดว่านี่ไม่ใช่ idempotent
Johannes Brodwall

2
หรือคุณสามารถทำให้ง่ายขึ้นและใช้ RFC 7396 Merge Patch แทนและหลีกเลี่ยงการสร้าง JSON Patch
Piotr Kula

สำหรับตาราง nosql ความแตกต่างระหว่างการแก้ไขและการวางเป็นสิ่งสำคัญเนื่องจาก nosql ไม่มีคอลัมน์
stackdave

18

ความแตกต่างระหว่าง PUT และ PATCH คือ:

  1. PUT จะต้องเป็น idempotent เพื่อให้บรรลุตามนั้นคุณจะต้องใส่ทรัพยากรทั้งหมดลงในส่วนของคำขอ
  2. PATCH อาจไม่ใช่ idempotent ซึ่งหมายความว่ามันอาจเป็น idempotent ในบางกรณีเช่นกรณีที่คุณอธิบาย

PATCH ต้องการ "ภาษาของแพตช์" เพื่อบอกเซิร์ฟเวอร์ถึงวิธีแก้ไขทรัพยากร ผู้เรียกและเซิร์ฟเวอร์จำเป็นต้องกำหนด "การดำเนินการ" บางอย่างเช่น "เพิ่ม", "แทนที่", "ลบ" ตัวอย่างเช่น:

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@olddomain.com",
  "state": "NY",
  "zip": "10001"
}

PATCH /contacts/1
{
 [{"operation": "add", "field": "address", "value": "123 main street"},
  {"operation": "replace", "field": "email", "value": "abc@myemail.com"},
  {"operation": "delete", "field": "zip"}]
}

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "abc@myemail.com",
  "state": "NY",
  "address": "123 main street",
}

แทนที่จะใช้ฟิลด์ "การดำเนินการ" อย่างชัดเจนภาษาของแพตช์สามารถทำให้เป็นนัยโดยการกำหนดการประชุมเช่น:

ในเนื้อหาคำขอ PATCH:

  1. การมีอยู่ของเขตข้อมูลหมายถึง "แทนที่" หรือ "เพิ่ม" เขตข้อมูลนั้น
  2. หากค่าของฟิลด์เป็นโมฆะก็หมายความว่าลบฟิลด์นั้น

ด้วยการประชุมข้างต้น PATCH ในตัวอย่างสามารถใช้แบบฟอร์มต่อไปนี้:

PATCH /contacts/1
{
  "address": "123 main street",
  "email": "abc@myemail.com",
  "zip":
}

ซึ่งดูกระชับและใช้งานง่ายขึ้น แต่ผู้ใช้จำเป็นต้องตระหนักถึงหลักการพื้นฐาน

จากการดำเนินการที่ฉันได้กล่าวถึงข้างต้น PATCH ยังคงเป็น idempotent แต่ถ้าคุณกำหนดการดำเนินการเช่น: "การเพิ่ม" หรือ "ผนวก" คุณสามารถเห็นได้อย่างง่ายดายว่ามันจะไม่เป็น idempotent อีกต่อไป


7

TLDR - รุ่นที่เป็นใบ้

PUT => ตั้งค่าคุณสมบัติใหม่ทั้งหมดสำหรับทรัพยากรที่มีอยู่

PATCH => อัปเดตทรัพยากรที่มีอยู่บางส่วน (ไม่ใช่แอตทริบิวต์ที่จำเป็นทั้งหมด)


3

ให้ฉันพูดและแสดงความคิดเห็นอย่างใกล้ชิดยิ่งขึ้นRFC 7231 ส่วน 4.2.2 ที่อ้างถึงในความคิดเห็นก่อนหน้านี้:

วิธีการร้องขอนั้นถูกพิจารณาว่าเป็น "idempotent" หากผลกระทบที่ตั้งใจไว้บนเซิร์ฟเวอร์ของการร้องขอที่เหมือนกันหลายครั้งด้วยวิธีการนั้นจะเหมือนกับผลกระทบสำหรับการร้องขอดังกล่าวเพียงครั้งเดียว ของวิธีการร้องขอที่กำหนดโดยสเปคนี้ PUT, DELETE และวิธีการร้องขอที่ปลอดภัยนั้นเป็น idempotent

( ... )

เมธอด Idempotent แตกต่างเพราะคำขอสามารถทำซ้ำได้โดยอัตโนมัติหากความล้มเหลวในการสื่อสารเกิดขึ้นก่อนที่ลูกค้าจะสามารถอ่านการตอบสนองของเซิร์ฟเวอร์ ตัวอย่างเช่นหากลูกค้าส่งคำขอ PUT และการเชื่อมต่อพื้นฐานถูกปิดก่อนที่จะได้รับการตอบสนองใด ๆ ลูกค้าสามารถสร้างการเชื่อมต่อใหม่และลองคำขอ idempotent อีกครั้ง มันรู้ว่าการทำซ้ำการร้องขอจะมีผลเหมือนกันแม้ว่าคำขอเดิมจะสำเร็จแม้ว่าการตอบกลับอาจแตกต่างกัน

ดังนั้นสิ่งที่ควร "เหมือนกัน" หลังจากมีการร้องขอวิธีการ idempotent ซ้ำ ๆ ไม่ได้สถานะของเซิร์ฟเวอร์หรือการตอบสนองเซิร์ฟเวอร์ แต่ผลกระทบที่ตั้งใจไว้ โดยเฉพาะอย่างยิ่งวิธีการที่ควรจะ idempotent "จากมุมมองของลูกค้า" ตอนนี้ฉันคิดว่ามุมมองนี้แสดงให้เห็นว่าตัวอย่างสุดท้ายในคำตอบของ Dan Loweซึ่งฉันไม่ต้องการลอกเลียนแบบที่นี่แน่นอนแสดงให้เห็นว่าคำขอ PATCH อาจไม่ใช่ idempotent (ในลักษณะที่เป็นธรรมชาติมากกว่าตัวอย่างในคำตอบของ Jason Hoetger )

อันที่จริงเราทำให้เป็นตัวอย่างเล็กน้อยที่แม่นยำยิ่งขึ้นโดยการทำอย่างชัดเจนอย่างใดอย่างหนึ่งที่เป็นไปได้ตั้งใจสำหรับลูกค้ารายแรก สมมติว่าไคลเอนต์นี้ต้องผ่านรายการผู้ใช้ที่มีโครงการเพื่อตรวจสอบอีเมลและรหัสไปรษณีย์ของพวกเขา เขาเริ่มต้นด้วยผู้ใช้ 1 สังเกตว่ารหัสไปรษณีย์นั้นถูกต้อง แต่อีเมลผิด เขาตัดสินใจที่จะแก้ไขสิ่งนี้ด้วยคำขอ PATCH ซึ่งถูกต้องตามกฎหมายอย่างสมบูรณ์และส่งเท่านั้น

PATCH /users/1
{"email": "skwee357@newdomain.com"}

เนื่องจากนี่เป็นเพียงการแก้ไขเท่านั้น ตอนนี้คำขอล้มเหลวเนื่องจากปัญหาเครือข่ายบางส่วนและถูกส่งอีกครั้งโดยอัตโนมัติภายในสองชั่วโมง ในขณะเดียวกันไคลเอนต์อื่นได้ทำการแก้ไข zip ของผู้ใช้ 1 (อย่างผิดพลาด) จากนั้นการส่งคำขอ PATCH เดียวกันครั้งที่สองจะไม่บรรลุผลตามที่ตั้งใจไว้ของไคลเอนต์เนื่องจากเราลงท้ายด้วย zip ไม่ถูกต้อง ดังนั้นวิธีการนี้ไม่ได้เป็น idempotent ในแง่ของ RFC

หากลูกค้าใช้คำขอ PUT เพื่อแก้ไขอีเมลส่งไปยังเซิร์ฟเวอร์คุณสมบัติทั้งหมดของผู้ใช้ 1 พร้อมกับอีเมลผลลัพธ์ที่ตั้งใจของเขาจะสำเร็จแม้ว่าจะต้องส่งคำขออีกครั้งในภายหลังและผู้ใช้ 1 ได้รับการแก้ไข ในขณะเดียวกัน --- เนื่องจากคำขอ PUT ที่สองจะเขียนทับการเปลี่ยนแปลงทั้งหมดตั้งแต่คำขอแรก


2

ในความเห็นที่ต่ำต้อยของฉัน idempotence หมายถึง:

  • PUT:

ฉันส่งคำจำกัดความทรัพยากรการแข่งขันดังนั้น - สถานะของทรัพยากรที่เกิดขึ้นนั้นเป็นไปตามที่กำหนดโดยพารามิเตอร์ PUT ทุกครั้งที่ฉันอัปเดตทรัพยากรด้วยพารามิเตอร์ PUT เดียวกัน - สถานะผลลัพธ์จะเหมือนกันทุกประการ

  • ปะ:

ฉันส่งส่วนหนึ่งของคำจำกัดความของทรัพยากรเท่านั้นดังนั้นผู้ใช้รายอื่นอาจกำลังอัปเดตพารามิเตอร์ OTHER ของทรัพยากรนี้ในเวลาเดียวกัน ดังนั้น - แพตช์ต่อเนื่องที่มีพารามิเตอร์เดียวกันและค่าเหล่านั้นอาจส่งผลให้สถานะทรัพยากรที่แตกต่างกัน ตัวอย่างเช่น

เข้าใจวัตถุที่กำหนดดังนี้:

รถยนต์: - สี: ดำ, - ประเภท: ซีดาน, - ที่นั่ง: 5

ฉันแก้ไขด้วย:

{color: 'red'}

วัตถุที่เกิดคือ:

รถยนต์: - สี: แดง, - ประเภท: ซีดาน, - ที่นั่ง: 5

จากนั้นผู้ใช้รายอื่น ๆ ก็ได้ทำการติดตั้งรถยนต์คันนี้ด้วย:

{type: 'hatchback'}

ดังนั้นวัตถุที่เกิดคือ:

รถยนต์: - สี: แดง, - ประเภท: รถยนต์, - ที่นั่ง: 5

ตอนนี้ถ้าฉันแก้ไขวัตถุนี้อีกครั้งด้วย:

{color: 'red'}

วัตถุที่เกิดคือ:

รถยนต์: - สี: แดง, - ประเภท: รถยนต์, - ที่นั่ง: 5

อะไรคือสิ่งที่แตกต่างจากที่ฉันเคยมีมาก่อน!

นี่คือเหตุผลที่ PATCH ไม่ใช่ idempotent ในขณะที่ PUT นั้นเป็น idempotent


1

เพื่อสรุปการอภิปรายเกี่ยวกับ idempotency ฉันควรทราบว่าหนึ่งสามารถกำหนด idempotency ในบริบท REST ได้สองวิธี ก่อนอื่นให้ทำบางสิ่งอย่างเป็นทางการ:

ทรัพยากรเป็นฟังก์ชั่นที่มีโคโดเมนที่ถูกระดับของสตริง ในคำอื่น ๆ ทรัพยากรเป็นส่วนย่อยของString × Anyที่คีย์ทั้งหมดไม่ซ้ำกัน Resขอเรียกชั้นเรียนของทรัพยากร

f(x: Res, y: Res): Resการดำเนินการส่วนที่เหลือเกี่ยวกับทรัพยากรเป็นฟังก์ชั่น สองตัวอย่างของการดำเนินการ REST คือ:

  • PUT(x: Res, y: Res): Res = xและ
  • PATCH(x: Res, y: Res): ResPATCH({a: 2}, {a: 1, b: 3}) == {a: 2, b: 3}ซึ่งการทำงานเช่น

(คำจำกัดความนี้ได้รับการออกแบบมาโดยเฉพาะเพื่อให้เหตุผลเกี่ยวกับPUTและPOSTและเช่นไม่มีความหมายมากGETและPOSTในขณะที่มันไม่สนใจเกี่ยวกับการคงอยู่)

ตอนนี้ด้วยการแก้ไขx: Res(พูดอย่างไม่เป็นทางการโดยใช้การแกง) PUT(x: Res)และPATCH(x: Res)เป็นฟังก์ชันประเภทที่Res → Resไม่แปรเปลี่ยน

  1. ฟังก์ชั่นg: Res → Resที่เรียกว่าidempotent ทั่วโลกเมื่อg ○ g == gคือสำหรับการใด ๆ,y: Resg(g(y)) = g(y)

  2. ให้ทรัพยากรและx: Res k = x.keysฟังก์ชั่นg = f(x)ที่เรียกว่าidempotent ซ้ายเมื่อแต่ละเรามีy: Res g(g(y))|ₖ == g(y)|ₖโดยทั่วไปหมายความว่าผลลัพธ์ควรเหมือนกันถ้าเราดูที่ปุ่มที่ใช้

ดังนั้นPATCH(x)ไม่ใช่ idempotent ทั่วโลก แต่เป็น idempotent ที่เหลืออยู่ และ idempotency ที่เหลือคือสิ่งที่สำคัญที่นี่: ถ้าเราทำการแก้ไขบางส่วนของทรัพยากรเราต้องการให้กุญแจเหล่านั้นเหมือนกันถ้าเราทำการแก้ไขอีกครั้งและเราไม่สนใจทรัพยากรที่เหลือ

และเมื่อ RFC กำลังพูดถึง PATCH ไม่ใช่ idempotent มันกำลังพูดถึง idempotency ทั่วโลก มันดีที่มันไม่ใช่ idempotent ทั่วโลกไม่อย่างนั้นมันจะเป็นการใช้งานไม่ได้


ตอนนี้คำตอบของ Jason Hoetgerพยายามแสดงให้เห็นว่า PATCH ไม่ได้แม้แต่ปล่อยไอเทมโมเทน แต่มันก็ทำหลายสิ่งเกินไป

  • ก่อนอื่น PATCH จะถูกใช้ในชุดแม้ว่า PATCH จะถูกกำหนดให้ทำงานบนแผนที่ / พจนานุกรม / วัตถุคีย์ - ค่า
  • ถ้ามีคนต้องการจริงๆที่จะใช้โปรแกรมปรับปรุงชุดนั้นมีการแปลเป็นธรรมชาติที่ควรจะใช้: ที่กำหนดไว้ด้วยt: Set<T> → Map<T, Boolean> x in A iff t(A)(x) == Trueการใช้คำจำกัดความนี้จะทำให้การแก้ไขเป็น idempotent
  • ในตัวอย่างการแปลนี้ไม่ได้ใช้แทนแพทช์ทำงานเหมือน POST ก่อนอื่นทำไมรหัสถูกสร้างขึ้นสำหรับวัตถุ? และเมื่อไรที่มันถูกสร้างขึ้น? หากวัตถุถูกเปรียบเทียบกับองค์ประกอบของชุดแรกและหากไม่พบวัตถุที่ตรงกันแล้ว ID จะถูกสร้างขึ้นจากนั้นอีกครั้งโปรแกรมควรทำงานแตกต่างกัน ( {id: 1, email: "me@site.com"}ต้องตรงกับ{email: "me@site.com"}มิฉะนั้นโปรแกรมจะเสียเสมอและ PATCH อาจไม่สามารถ ปะ). หาก ID ถูกสร้างขึ้นก่อนที่จะตรวจสอบกับชุดอีกครั้งโปรแกรมจะเสีย

เราสามารถสร้างตัวอย่างของ PUT ที่ไม่ใช่ idempotent โดยแบ่งครึ่งของสิ่งต่าง ๆ ที่แตกในตัวอย่างนี้:

  • ตัวอย่างที่มีคุณสมบัติเพิ่มเติมที่สร้างขึ้นจะเป็นการกำหนดเวอร์ชัน หนึ่งอาจเก็บบันทึกจำนวนการเปลี่ยนแปลงในวัตถุเดียว ในกรณีนี้ PUT ไม่ใช่ idempotent: PUT /user/12 {email: "me@site.com"}ผลลัพธ์ใน{email: "...", version: 1}ครั้งแรกและ{email: "...", version: 2}ครั้งที่สอง
  • ล้อเล่นกับ IDs หนึ่งอาจสร้าง ID ใหม่ทุกครั้งที่มีการปรับปรุงวัตถุทำให้เกิด PUT ที่ไม่ใช่ idempotent

ตัวอย่างข้างต้นทั้งหมดเป็นตัวอย่างตามธรรมชาติที่อาจพบ


ประเด็นสุดท้ายของฉันคือ PATCH ไม่ควรเป็นidempotent ทั่วโลกมิฉะนั้นจะไม่ให้ผลตามที่ต้องการ คุณต้องการเปลี่ยนที่อยู่อีเมลของผู้ใช้โดยไม่ต้องแตะข้อมูลที่เหลือและคุณไม่ต้องการเขียนทับการเปลี่ยนแปลงของบุคคลอื่นที่เข้าถึงทรัพยากรเดียวกัน


-1

ข้อมูลเพิ่มเติมหนึ่งที่ฉันเพิ่มเพียงอย่างเดียวคือคำขอ PATCH ใช้แบนด์วิดท์น้อยกว่าเมื่อเปรียบเทียบกับคำขอ PUT เนื่องจากมีเพียงส่วนหนึ่งของข้อมูลที่ส่งไม่ใช่เอนทิตีทั้งหมด ดังนั้นเพียงแค่ใช้คำขอ PATCH เพื่ออัปเดตระเบียนที่เฉพาะเจาะจงเช่น (1-3 ระเบียน) ในขณะที่ PUT ขอให้อัปเดตข้อมูลจำนวนมากขึ้น นั่นคือมันไม่คิดมากหรือกังวลมากเกินไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.