RESTful API แสดงถึงการไม่มีสิ่งใด


18

ลองนึกภาพ API เพื่อระบุว่าบุคคลได้เลือกสัตว์วิญญาณของพวกเขาหรือไม่ พวกมันมีสัตว์วิญญาณเป็นศูนย์หรือหนึ่งตัวเท่านั้น

ขณะนี้:

/person/{id}/selectedSpiritAnimal

เมื่อเลือกสัตว์แล้วจะคืนค่า http 200 และ {selectedAnimal:mole}

แต่เมื่อไม่มีสิ่งที่เลือกก็จะส่งคืน http 404

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

นอกจากนี้ในฐานะธุรกิจ - erm Sprit-Animal-Hampers-R-us - เราต้องการทราบเมื่อมีคนไม่มีตัวเลือกดังนั้นเราจึงสามารถแจ้งให้พวกเขาได้

การตอบสนองที่ดีกว่าคืออะไรที่นี่:

HTTP 200 และ {selectedAnimal:null}

หรือชัดเจนยิ่งขึ้น

HTTP 200 และ {selectedAnimal:null, spiritAnimalSelected: false}

หรือมันจะดีกว่าที่จะกลับ 404? เนื่องจากชอบมากthis image has not yet been uploadedเมื่อดูภาพออนไลน์จะเป็น 404 this person has not selected a spirit animalอาจเป็น 404


คำถามนี้ได้รับการเสนอเป็นคำถามซ้ำ แต่คำถามดังกล่าวตอบ URL ที่ถูกต้องเป็นอย่างอื่นเมื่อมีการกำหนดค่าแอปพลิเคชันให้ไม่อนุญาตให้มีการเปลี่ยนแปลง URL นั้น

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

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


เลือกคำตอบได้ยากมาก ฉันเปลี่ยนใจในการสนทนาหลายครั้งที่นี่และที่ทำงานต่อเนื่อง

สิ่งที่ settles สำหรับฉันที่นี่คือสเปคบอกว่า 4xx คือเมื่อลูกค้าได้ผิดพลาด ในกรณีนี้ไคลเอนต์ได้รับการบอกให้คาดหวังการตอบสนองจาก URL ที่เลือกSpiritAnimalดังนั้นจึงไม่ผิดพลาด

ฉันทามติในหมู่เพื่อนร่วมงานของฉันคือนี่เป็นอาการของการออกแบบ API ที่ไม่ดี

น่าจะดีกว่าที่เราเพียงแค่ขอ / person / {id} และส่งคืนชุดของความสัมพันธ์ลิงก์สำหรับบุคคล ... ถ้าคุณไม่ได้รับลิงค์ / selectSpiritAnimal (เมื่อบุคคลไม่มีตัวเลือก) แต่คุณ เรียกมันว่าต่อไปแล้ว 404 ก็สมเหตุสมผลแล้ว หรือว่าคุณใช้การตอบสนองบางส่วนและให้ / person / {id} ส่งคืนเอกสารที่สมบูรณ์ยิ่งขึ้นเว้นแต่ลูกค้าร้องขอชุดย่อยของข้อมูล


5
คุณไม่ได้อธิบายว่าทำไมคุณจึงเชื่อว่ามันเป็นปัญหาที่จะส่งคืน 404 จากมุมมองของโดเมนคุณไม่ทราบว่าคุณได้รับ 404 หรือ 200 ซึ่งเป็นนามธรรมที่เลเยอร์ลูกค้า
Vincent Savard

14
หรืออาจจะดีกว่าถ้าไม่คืน 204 เนื้อหา?
Paul D'Ambra

6
ฉันคิดว่าความกังวลของฉันที่มี 404 คือการเปลี่ยนแปลงการกำหนดค่าที่แนะนำเทมเพลต URL ที่ไม่ดีจากคนที่ไม่มีสัตว์วิญญาณ
Paul D'Ambra

2
@ PaulD'Ambra สำหรับสิ่งที่คุ้มค่าฉันจะไม่ใช้เนื้อหาใด ฉันไม่เห็นรหัส HTTP จัดการกับ front-end ใน Javascript ตั้งแต่ XmlHttpRequest วัน แต่มันก็ใช้ได้อย่างแน่นอน
Brandon Arnold

คำตอบ:


24

รหัส HTTP 4xx อาจไม่ใช่ตัวเลือกที่เหมาะสมสำหรับสถานการณ์นี้ คุณระบุว่าการมีสัตว์วิญญาณศูนย์เป็นรัฐที่ถูกต้องและเส้นทาง API person/{id}/selectedSpiritAnimalจะพิจารณาว่าบุคคลนั้นเป็นใครidนั้นมีหรือไม่มี

การตอบสนอง HTTP 4xx ถูกสงวนไว้สำหรับสถานการณ์เมื่อไคลเอนต์ทำสิ่งที่ไม่ถูกต้องในคำขอ (ดูที่การเก็บถาวรข้อมูลจำเพาะดั้งเดิมของ w3 ) แต่ลูกค้ากำลังทำคำขอที่ถูกต้องไม่ว่าบุคคลนั้นidจะมีสัตว์วิญญาณหรือไม่ก็ตาม

ดังนั้นฉันจึงเอนไปยังโซลูชันที่สองโดยใช้เนื้อความ JSON ที่จัดรูปแบบอย่างถูกต้องในการตอบสนองและรหัส HTTP 2xx

ตอนนี้ถ้าคุณได้รับการร้องขอดังกล่าวและปรากฎว่าidไม่มีคนอยู่รหัส 4xx นั้นเหมาะสมกว่า


17
"การตอบกลับ HTTP 4xx ถูกสงวนไว้สำหรับสถานการณ์เมื่อไคลเอนต์ทำสิ่งที่ไม่ถูกต้องในคำขอ" เมื่อสร้างข้อความสั่งอย่างเป็นทางการเกี่ยวกับข้อมูลจำเพาะโปรดอ้างอิงข้อมูลจำเพาะ HTTP จริงและไม่ใช่ (a) เฟรมเวิร์กที่สร้างไว้ด้านบนหรือ (b) โพสต์บล็อกแบบสุ่ม
Eric Stein

5
@EricStein ฉันรู้สึกขี้เกียจนิดหน่อยเกี่ยวกับเรื่องนี้; ขอบคุณสำหรับคำติชม Updated
Brandon Arnold

1
ฉันรู้สึกว่าลิงก์ RFC ที่นี่เป็นสิ่งที่ขัดแย้งกัน ในมือข้างหนึ่งส่วน 4xx กล่าวว่าcases in which the client seems to have erredแต่ที่อื่น ๆ 404 The server has not found anything matching the Request-URIโดยตรงกล่าวว่า คุณสามารถพิจารณาขอสิ่งที่ไม่มีข้อผิดพลาดของลูกค้า ฉันเข้าใจบุคคลที่ไม่ได้มีอยู่เทียบกับเสาย่อยไม่ได้มีอยู่ แต่นั่นอาจระบุได้ว่าเป็นข้อความตอบกลับ 204 ยังดูเหมือนว่ามีความเกี่ยวข้องเนื่องจากมีเอนทิตีอยู่ แต่ไม่มีเนื้อหาสำหรับพร็อพเพอร์ตี้ย่อย
shortstuffsushi

1
ลูกค้าทำสิ่งผิดปกติ มันร้องขอสัตว์วิญญาณที่เลือกไว้สำหรับผู้ใช้เมื่อไม่มีอยู่ นั่นคือสิ่งที่ 404 หมายถึง ... คุณขอสิ่งที่ไม่มี
Andy

5
เมื่อเบราว์เซอร์ของฉันส่งคำขอไปยังsoftwareengineering.stackexchange.com/questions/unicorn มันเป็นคำขอที่ถูกต้องและฉันยังคงได้รับ 404 (มีเพียงว่าไม่มีคำถามใด ๆ กับ ID "ยูนิคอร์น")
253751

24

ผมขอแนะนำให้คุณริชาร์ด Maturity Model

ปัญหาของคุณคือคุณเป็นตัวแทนของสองทรัพยากรเป็นหนึ่งเดียวที่คุณควรมีสองทรัพยากรที่มีความสัมพันธ์ที่ระบุโดยสื่อสิ่งพิมพ์ การใช้ไฮเปอร์มีเดียเพื่ออธิบายความสัมพันธ์คือระดับที่ 3 อันทรงเกียรติ

บุคคลของคุณควรอยู่ภายใต้ URI /person/{id}และสัตว์ควรอยู่ภายใต้/spiritanimal/{id}และสัตว์ควรอยู่ภายใต้บุคคลควรระบุว่ามีสัตว์วิญญาณโดยใช้ลิงก์ไปยังสัตว์

ให้จินตนาการถึงบุคคลที่ชื่อว่าบ็อบซึ่งมีรหัส 123 และสัตว์วิญญาณยูนิคอร์น

GET /person/123

จะกลับมา;

{
  "name": "Bob",
  "links": [
    {
      "rel": "spiritanimal",
      "uri": "/spiritanimals/789"
    }
  ]
}

ตอนนี้ใครก็ตามที่อ่านคน 123 จะรู้ว่าพวกเขามีสัตว์วิญญาณและมี URI ที่พวกเขาสามารถรับข้อมูลเพิ่มเติมได้

GET /spitiranimal/789

อาจกลับมา

{
  "type": "Unicorn"
}

ตอนนี้ลองนึกภาพคนที่เรียกว่าเฟร็ดที่มีรหัส 456 และไม่มีสัตว์วิญญาณ

GET /person/456

จะกลับมา;

{
  "name": "Fred",
  "links": [
  ]
}

ตอนนี้ใครก็ตามที่อ่านคน 456 จะรู้ว่าพวกเขาไม่มีสัตว์วิญญาณเนื่องจากไม่มีการเชื่อมโยง ไม่จำเป็นต้องใช้รหัสสถานะ HTTP ใด ๆ เพื่อแสดงถึงการขาดความสัมพันธ์


1
เป็นเพียงการเพิ่มคำถามที่ให้ความสามารถในการเปลี่ยน api ระดับ HATEOAS อาจจะเป็นทางออกที่เหมาะสม นั่นเป็นตัวอย่างที่ดีของสิ่งนั้น
Paul D'Ambra

1

นี่คือ URL ที่เหมาะสมสำหรับการรับสัตว์วิญญาณ ดังนั้นข้อผิดพลาด 404 จึงไม่เหมาะสม 404 ใช้สำหรับแสดงปัญหาทางเทคนิคไม่ใช่ปัญหาเชิงตรรกะ

ทางออกที่เหมาะสมคือส่งคืน http 200 และ {"selectedAnimal": null}

คุณควรจะมีแยก WebMethod ซึ่งผลตอบแทน/person/{id}/hasSelectedSpiritAnimal {"isSpiritAnimalSelected": false}เบื้องหลังอาจเป็นหรือไม่เรียกวิธีเดียวกันเพียงแค่ส่งคืนค่าเท็จหากเป็นโมฆะ แต่ก็ขึ้นอยู่กับการตัดสินใจไม่ใช่รหัสบริโภค

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


1
คุณช่วยอธิบายได้หรือไม่ว่าทำไมคุณถึงเชื่อว่านี่เป็นทางออกที่เหมาะสม ฉันไม่สามารถรับคืนข้อมูลได้เมื่อไม่มีข้อมูลที่จะส่งคืน ฉันเห็นด้วยกับคุณว่า 404 ไม่สมเหตุสมผลเนื่องจาก URL ใช้ได้ดังนั้น 204 ดูเหมือนจะเหมาะสมกับฉันมากที่สุด
Vincent Savard

2
@VincentSavard สถานะรหัสนั้นยากต่อการทำงานมากกว่าการตอบ json และเหมาะสมกว่าสำหรับปัญหาทางเทคนิคมากกว่าการสื่อสารข้อมูลโดเมน
TheCatWhisperer

2
204: ไม่มีเนื้อหาที่มีร่างกายที่ว่างเปล่า มันคือทั้งหมดที่ชัดเจนและอธิบายตนเอง ไม่จำเป็นต้องเถียงต่อไป โดยรวมเมื่อไม่มีรูปแบบการออกแบบที่ชัดเจน SE ควรเลือกหนึ่งโค้งงอให้ตรงกับความต้องการและจัดเตรียมเอกสาร การส่งคืนเนื้อหาที่ตอบสนอง 204 ครั้งไม่เป็นผล
formixian

2
@formixian ... หากคุณกำลังสร้าง bjson / tcp api แทนที่จะเป็น json / http คุณจะกลับไปหากรณีนี้อย่างไร การใช้รหัส http นั้นทำให้ฉันต้องผูกผลลัพธ์ของ API กับการใช้ http ของมันโดยไม่จำเป็น
TheCatWhisperer

2
@VincentSavard When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"ไม่มีเนื้อหาหมายความว่าไม่มีเนื้อหา ie: มันส่งคืน "" ทั้งสองนี้ไม่เหมือนกันเลย "สัตว์วิญญาณไม่ได้ในขณะนี้ในไฟล์" จะมากแตกต่างจาก ""
เชน

1

จุดสิ้นสุดของคุณแสดงให้เห็นว่าไม่ใช่แค่สัตว์ มันเป็นสัตว์หรือขาดมัน เป็นค่าที่ดีที่สุดที่แสดงโดยOptional/ Maybe/Nullable / ฯลฯ

ดังนั้นค่าที่ถูกต้อง (เช่นใน 200 OK) อาจเป็น:

  • {'animal': <some animal>, 'selected': true}
  • {'animal': null, 'selected': false}

ฉันจะคิดว่าDELETEวิธีการที่เมื่อนำไปใช้ปลายทางที่สามารถตั้งค่า'selected'เพื่อfalseอีกครั้งนั่นคือล้างค่าสัตว์ที่เลือก

แน่นอนว่าคุณสามารถวาง'selected'กุญแจได้ที่นี่มันจะปรากฏขึ้นเพื่อความชัดเจนเท่านั้น string vs nullก็เพียงพอแล้วสำหรับความแตกต่าง


0

คุณควรใช้ 404

รหัสสถานะ 404 (ไม่พบ) บ่งชี้ว่าเซิร์ฟเวอร์ต้นทางไม่พบการแสดงปัจจุบันสำหรับทรัพยากรเป้าหมาย

RFC7231

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Mon, 25 Sep 2017 00:00:00 GMT

this person has not selected a spirit animal

เนื่องจากคุณกำลังสร้างอินเตอร์เฟสการเขียนโปรแกรมไม่ใช่อินเตอร์เฟสแบบมนุษย์ข้อความ 404 จึงเป็นทางเลือก

ฉันชอบสิ่งนี้เพราะฉันชอบโปรโตคอลมาตรฐานมากที่สุด HTTP มีวิธีในการแสดงสิ่งที่ไม่มีอยู่จริงและนั่นคือสิ่งที่ฉันจะใช้

แก้ไข: สมมติว่าคุณเพิ่มคุณสมบัติที่ผู้ใช้สามารถเลือกได้ว่าจะแบ่งปันสัตว์วิญญาณของพวกเขาหรือไม่และมีคนไม่แบ่งปัน คุณจะกลับมา 200 ตกลงnullหรือ 200 OK "Unauthorized? หรือคุณจะใช้มาตรฐาน 401 Unauthorized / 403 Forbidden? ดูเหมือนจะคล้ายกันโดยตรงกับการไม่เลือกตั้งแต่แรก


หรือถ้าคุณต้องการสินค้า 200 + ตกลง JSON nullคุณควรกลับ

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

null

รักษาความสะอาด สร้างการห่อเพิ่มเติมในกรณีที่จำเป็นเท่านั้น


2
แม้ว่าข้อมูลจะถูกค้นพบ มันเพิ่งเกิดขึ้นว่าข้อมูลนั้นnull(ไม่มีค่า) สิ่งนี้แตกต่างจากไคลเอนต์ที่ขอบางสิ่งซึ่งไม่มีสล็อตที่จะเก็บค่าไว้ คุณจะไม่ขอแนะนำการขว้างปาAttributeErrorในหลามเมื่อมีค่าที่จะเกิดขึ้นNone; ซึ่งจะทำให้อินเทอร์เฟซใช้งานไม่ได้และยากต่อการใช้งานโดยไม่จำเป็น ในทางปฏิบัติแล้วไคลเอนต์ HTTP APIs จำนวนมากอาจแปลง 404 เป็นกลไกการจัดการข้อผิดพลาดมาตรฐานของภาษา (รหัสข้อผิดพลาดข้อยกเว้นประเภทข้อผิดพลาด) ซึ่งหมายความว่าคุณจะต้องระงับข้อผิดพลาดภายนอก
jpmc26

@Paul Draper เลื่อนขึ้นเล็กน้อยในสเปคคุณจะเห็นว่ามันสร้างคำสั่งแบบครอบคลุมเกี่ยวกับ HTTP 4xx: "รหัสสถานะ 4xx คลาสมีไว้สำหรับกรณีที่ไคลเอนต์ดูเหมือนจะผิดพลาด" op ได้ระบุไว้อย่างชัดเจนว่าการไม่มีสัตว์วิญญาณเป็นสถานะที่ถูกต้องซึ่ง API ควรใช้บัญชี tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold

ดังนั้นคุณจะแยกแยะระหว่างการบ่งชี้ว่าไม่มีทรัพยากรที่ร้องขอ (เช่นไม่มีการเลือกสัตว์) และลูกค้าที่ขอเส้นทางที่ไม่ถูกต้อง (เช่น/person/{id}/selectedSpritAnimalสังเกตการพิมพ์ผิดSprit)
sampathsris

1
โดยไม่คำนึงถึงเจตนา 404 หมายถึงไม่พบทรัพยากรอย่างเคร่งครัด หาก SelectedSpiritAnimal เป็นทรัพยากรและไม่มีอยู่แสดงว่าไม่มีสิ่งใดต่อ GET และ 404 นั้นเหมาะสม อย่างไรก็ตามหากลูกค้าต้องการที่จะรู้ว่าวิญญาณสัตว์ถูกเลือกแล้วเซิร์ฟเวอร์ควรเปิดเผยทรัพยากรอื่น/person/{id}/isSpiritAnimalSelectedซึ่งจะบอกลูกค้าว่ามีการเลือกหนึ่ง ดูเหมือนว่าฉันเป็นตัวอย่างคลาสสิกที่เหมือนกันของการทดสอบว่ามีไฟล์อยู่ก่อนอ่านหรือไม่ เพียงแค่อ่านไฟล์และจัดการกับข้อผิดพลาด ENOENT หากมันถูกโยนทิ้ง
aaaaaa

1
@PaulDraper จุดไม่ใช่ว่าทรัพยากรมีอยู่จริงหรือไม่ จุดคือรหัส HTTP 4xx มีไว้สำหรับเมื่อผู้โทรใช้ API ไม่ถูกต้อง แย้มยิ้มรัฐที่/person/{id}/selectedSpiritAnimalมีวัตถุประสงค์เพื่อใช้แม้ว่าสัตว์วิญญาณไม่อยู่ ซึ่งหมายความว่า HTTP 4xx ไม่ถูกต้องเมื่อใช้ในกรณีดังกล่าว Op ยังระบุอย่างถูกต้องว่านี่อาจเป็นกลิ่นของการออกแบบ API ที่ไม่ดี
Brandon Arnold
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.