ทำไม PATCH ถึงไม่เป็น idempotent?


48

ฉันสงสัยเกี่ยวกับเรื่องนี้

สมมติว่าฉันมีuserทรัพยากรด้วยidและnameสาขา ถ้าฉันต้องการอัปเดตฟิลด์ฉันสามารถทำคำขอแพทช์กับทรัพยากรเช่นนี้ได้

PATCH /users/42
{"name": "john doe"} 

จากนั้นแอปพลิเคชันจะอัปเดตชื่อผู้ใช้ 42

แต่ทำไมถ้าฉันทำซ้ำคำขอนี้ผลลัพธ์จะแตกต่างกันอย่างไร

อ้างอิงจากRFC 5789

PATCH นั้นไม่ปลอดภัยหรือ idempotent


จะเกิดอะไรขึ้นหากมีการร้องขอให้บุคคลอื่นอัปเดตผู้ใช้ 42{"name": "bendjamin franklin"}
gnat

@gnat ไม่ได้ถืออาร์กิวเมนต์ที่คล้ายกันสำหรับวิธีการ PUT ซึ่งถือเป็น idempotent แทน? (ดูgoo.gl/t24ZSJ )
mattecapu

"PUT มีความหมาย idempotent และสามารถนำไปใช้อย่างปลอดภัยสำหรับการอัพเดทแบบสมบูรณ์ (เช่นเราส่งสถานะทั้งหมดของทรัพยากรไปยังเซิร์ฟเวอร์) แต่ไม่ใช่สำหรับการปรับปรุงแบบสัมพัทธ์ (เช่นเราส่งการเปลี่ยนแปลงไปยังสถานะทรัพยากร)เท่านั้น ความหมายของ ..."( POST และ PUT ร้องขอ - มันเป็นเพียงการประชุม? )
ริ้น

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

2
ฉันใช้เสรีภาพในการเพิ่มการอ้างอิงถึงข้อกำหนดที่เกี่ยวข้องเนื่องจากฉันเชื่อว่ามีความเกี่ยวข้องสูงในบริบทของคำถามนี้
Pete

คำตอบ:


34

คำขอ PATCH อาจเป็น idempotent แต่ไม่จำเป็นต้องเป็น นั่นคือเหตุผลว่าทำไมจึงมีลักษณะที่ไม่ใช่ idempotent

PATCH สามารถเป็น idempotent หรือไม่นั้นขึ้นอยู่กับว่ามีการสื่อสารการเปลี่ยนแปลงที่จำเป็นอย่างไร
ตัวอย่างเช่นหากรูปแบบแพตช์อยู่ในรูปแบบของ{change: 'Name' from: 'benjamin franklin' to: 'john doe'}ดังนั้นคำขอ PATCH ใด ๆ หลังจากรูปแรกจะมีผลที่แตกต่างกัน (การตอบสนองความล้มเหลว) กว่าคำขอแรก
อีกเหตุผลหนึ่งที่ไม่ใช่ idempotency อาจเป็นได้ว่าการใช้การปรับเปลี่ยนกับสิ่งอื่นที่ไม่ใช่ทรัพยากรดั้งเดิมสามารถทำให้ทรัพยากรไม่ถูกต้อง นี่จะเป็นกรณีนี้หากคุณใช้การเปลี่ยนแปลงหลายครั้ง


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

3
@RobinGreen: สมมติว่ามีการแสดงทรัพยากรใน XML ด้วยความต้องการที่มี<name>องค์ประกอบอย่างน้อยหนึ่งรายการ หาก PATCH เพิ่ม<name>องค์ประกอบให้กับทรัพยากรที่เดิมไม่ได้มีหนึ่งแล้วใช้แพทช์สองครั้ง (หรือนำไปใช้กับทรัพยากรที่มีอยู่แล้ว<name>) ทำให้ทรัพยากรไม่ถูกต้องเพราะมันจะมีสอง<name>องค์ประกอบที่ไม่ได้รับอนุญาต สำหรับทรัพยากรดังกล่าว
Bart van Ingen Schenau

13
ตัวอย่างแรกที่คุณให้ไม่มีความเกี่ยวข้องกับ IMHO เพราะมันคือ idempotent ตัวอย่างกับ DELETE ซึ่งเป็น idempotent การร้องขอแรก: ทรัพยากรมีอยู่ แต่ถูกลบ (ส่งคืน 2xx) คำขอที่สอง: ทรัพยากรไม่มีอยู่และยังคงไม่มีอยู่หลังจากคำขอส่งคืน 4xx สถานะเซิร์ฟเวอร์ไม่เปลี่ยนแปลงดังนั้น idempotency ในตัวอย่างของคุณคำขอแรก: PATCH จาก BenFra ถึง JohDoe ชื่อทรัพยากรคือ BenFra แต่ตอนนี้คือ JohDoe (ส่งคืน 2xx) คำขอที่สอง: PATCH จาก BenFra ถึง JohDoe ชื่อทรัพยากรคือ JohDoe และยังคง JohDoe (ส่งคืน 4xx) ดังนั้นสิ่งนี้ไม่แสดงให้เห็นว่า PATCH สามารถเป็น nonidempotent ได้
sp00m

รายละเอียดเพิ่มเติมได้ที่นี่: stackoverflow.com/q/4088350/1225328
sp00m

8

ฉันคิดว่าคำตอบที่ชัดเจนเมื่อ PATCH ไม่ใช่ idempotent ย่อหน้านี้จาก RFC 5789:

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

เนื่องจาก RFC ระบุว่าแพทช์นั้นมี "การเปลี่ยนแปลงทั่วไป" กับทรัพยากรบางอย่างเราจึงควรมองข้ามการเปลี่ยนฟิลด์ทั่วไป หากทรัพยากรนั้นมีไว้สำหรับตัวนับดังนั้นแพทช์สามารถร้องขอการเพิ่มขึ้นซึ่งไม่ได้เป็น idempotet


2

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

โปรดจำไว้ว่าPATCHสามารถใช้คำขอสำหรับการแพตช์ทรัพยากรในหลาย ๆ รูปแบบไม่ใช่แค่ JSON

ดังนั้นPATCHคำขอสามารถ idempotent ถ้าคุณกำหนดกฎการควบรวมที่จะ idempotent

ตัวอย่าง Idempotent:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

ตัวอย่างที่ไม่ใช่ idempotent:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

ในตัวอย่างที่สองฉันใช้ไวยากรณ์ "Mongo like" ฉันสร้างขึ้นเพื่อเพิ่มคุณสมบัติ เห็นได้ชัดว่านี่ไม่ใช่ idempotent เนื่องจากการส่งคำร้องขอซ้ำหลายครั้งจะทำให้ได้ผลลัพธ์ที่แตกต่างกันในแต่ละครั้ง

ตอนนี้คุณอาจสงสัยว่าการใช้ไวยากรณ์ที่ถูกสร้างขึ้นนั้นถูกต้องหรือไม่ ตามมาตรฐานมันคือ:

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

และคุณอาจจะสงสัยว่ามันเป็นการพักผ่อนที่จะใช้PATCHวิธีนี้หรือไม่และหลายคนคิดว่าไม่ใช่นี่เป็นคำตอบที่ดีพร้อมความคิดเห็นมากมายเกี่ยวกับปัญหา

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