REST API - API ควรส่งคืนอ็อบเจ็กต์ JSON ที่ซ้อนกันหรือไม่


37

เมื่อพูดถึง API ของ JSON เป็นวิธีปฏิบัติที่ดีในการแผ่การตอบสนองออกและหลีกเลี่ยงวัตถุ JSON ที่ซ้อนกันหรือไม่

ตัวอย่างเช่นสมมติว่าเรามี API คล้ายกับ IMDb แต่สำหรับวิดีโอเกม มีหน่วยงานคู่เกมแพลตฟอร์ม ESRBRating และ GamePlatformMap ซึ่งทำแผนที่เกมและแพลตฟอร์ม

สมมติว่าคุณร้องขอ / เกม / 1 ซึ่งดึงข้อมูลเกมด้วย ID 1 และส่งคืนออบเจ็กต์เกมด้วยแพลตฟอร์มและการซ้อนทับซ้อน

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"id":1,"name":"Xbox"},
    {"id":2,"name":"Playstation"}
  ],
  "esrbRating": {
    "id": 1,
    "code": "E",
    "name": "Everyone"
  }
}

หากคุณกำลังใช้งาน JPA / Hibernate ระบบอาจทำสิ่งนี้ให้คุณโดยอัตโนมัติหากตั้งค่าเป็น FETCH.EAGER

อีกตัวเลือกหนึ่งคือเพียงแค่ API และเพิ่มจุดสิ้นสุดเพิ่มเติม

ในกรณีนั้นเมื่อมีการร้องขอ / game / 1 เพียงแค่ส่งคืนวัตถุเกม

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
}

หากคุณต้องการแพลตฟอร์มและ / หรือ ESRBRating คุณจะต้องเรียกสิ่งต่อไปนี้:

/ game / 1 / platform / game / 1 / esrb

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

มีความคิดครั้งสุดท้ายที่ฉันมีที่ที่คุณจะมีอะไรเช่นนี้กลับมา

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": ["Xbox","Playstation"]
}

อย่างไรก็ตามสิ่งนี้ถือว่าพวกเขาไม่ต้องการ ID หรือข้อมูลอื่นใดที่อาจเกี่ยวข้องกับออบเจ็กต์ของแพลตฟอร์มเหล่านั้น

ฉันถามโดยทั่วไปว่าวิธีใดที่ดีที่สุดในการจัดโครงสร้างออบเจ็กต์ JSON ของคุณที่ส่งคืนจาก API ของคุณ คุณควรพยายามอยู่ใกล้กับเอนทิตีของคุณมากที่สุดหรือไม่ก็ควรใช้ Domain Objects หรือ Data Transfer Objects ฉันเข้าใจวิธีการที่จะมีการแลกเปลี่ยนไม่ว่าจะทำงานบนชั้นการเข้าถึงข้อมูลหรือทำงานให้กับลูกค้ามากขึ้น

ฉันอยากได้ยินคำตอบที่เกี่ยวข้องกับการใช้ Spring MVC เป็นเทคโนโลยีแบ็กเอนด์สำหรับ API ด้วย JPA / Hibernate หรือ MyBatis สำหรับการคงอยู่


6
คุณมีการคัดค้านอะไรบ้างหากส่งคืนวัตถุฝังตัว การส่งคืนวัตถุฝังตัวแยกจากปลายทางที่แตกต่างกันจะทำให้น่ารำคาญน่ารำคาญ (ไม่พูดถึงช้า)
Robert Harvey

1
โดยส่วนตัวฉันไม่มีข้อคัดค้าน ฉันแค่ไม่ได้ตระหนักถึงสิ่งที่ถือเป็นแนวทางปฏิบัติที่ดีที่สุด เพื่อนร่วมงานอ้างว่าทำงานกับวัตถุฝังตัวใน AngularJS ไม่ได้ส่งตรงไปข้างหน้าและในที่สุดฉันก็อยากให้ Ember of AngularJS แอปใช้ API ฉันไม่รู้เกี่ยวกับ Angular หรือ Ember เพียงพอที่จะทราบว่าจะมีผลกระทบหรือไม่
greyfox

3
คำตอบนั้นขึ้นอยู่กับว่าคุณต้องการส่งคืนวัตถุโดเมน, วัตถุ DTO, ViewModel หรือวัตถุ KitchenSink วัตถุใดที่คุณส่งคืนมีแนวโน้มที่จะถูกกำหนดโดยความต้องการของแอปพลิเคชันของคุณและวัตถุดังกล่าวทำงานอย่างไรในอินเทอร์เน็ต ตัวอย่าง:หากคุณพยายามกรอกข้อมูลหน้าเว็บด้วยใบแจ้งหนี้มีโอกาสมากที่คุณจะส่งคืนวัตถุที่มีทุกสิ่งที่คุณต้องการ (เว้นแต่คุณวางแผนที่จะ AJAXing ในรายการโฆษณาหรืออะไรทำนองนั้น)
Robert Harvey

ซึ่งเป็นกรณีนี้เมื่อคุณขอเกมคุณอาจต้องการทราบประเภทแพลตฟอร์มและ ESRBRating นั่นทำให้รู้สึก ในแง่ของการออกแบบจากมุมมองของ Java คุณจะแนะนำให้มีชุดเอนทิตีที่มี JPA เข้ามาแล้วแพคเกจโดเมนซึ่งเป็นวัตถุธุรกิจ / DTO จะกลับไปที่ผู้ใช้?
greyfox

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

คำตอบ:


11

ทางเลือกอื่น (โดยใช้ HATEOAS) นี่เป็นเรื่องง่ายส่วนใหญ่ในทางปฏิบัติคุณเพิ่มแท็กลิงก์ใน json ขึ้นอยู่กับการใช้งาน HATEOAS ของคุณ

http://api.example.com/games/1:

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"_self": "http://api.example.com/games/1/platforms/53", "name": "Playstation"},
    {"_self": "http://api.example.com/games/1/platforms/34", "name": "Xbox"},
  ]
}

http://api.example.com/games/1/platforms/34:

{
  "id": 34,
  "title": "Xbox",
  "publisher": "Microsoft",
  "releaseDate": "2015-01-01",
  "testReport": "http://api.example.com/games/1/platforms/34/reports/84848.pdf",
  "forms": [
    {"type": "edit", "fields: [] },
  ]
}

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

การใช้งานด้านเทคนิคสามารถมีแคช คุณสามารถแคชลิงค์แพลตฟอร์มและชื่อในวัตถุเกมและส่งทันทีโดยไม่ต้องโหลดแพลตฟอร์ม API เลย จากนั้นเมื่อต้องการคุณสามารถโหลดได้

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


ฉันไม่คิดว่านั่นเป็นเทคนิค HATEOS เนื่องจากไม่มีรัฐ
RibaldEddie

ใช่ไม่แน่ใจคำที่แน่นอนในกระบวนการนี้ โดยทั่วไปจะมีการใช้ HATEOS เพื่อเชื่อมโยง API ที่เหลือ แต่ฉันยอมรับว่ามันเกี่ยวข้องกับสถานะ แม้ว่าแนวคิดของการนำไปใช้จะเหมือนกัน ที่นี่คุณจะเห็นอีกเล็กน้อยเกี่ยวกับวิธีการใช้งานตัวอย่าง: stormpath.com/blog/linking-and-resource-expansion-rest-api-tips
Luc Franken

มันเป็นความคิดที่ดี!
RibaldEddie

1
หากคุณกำลังพัฒนา API ที่มีการทำงานร่วมกันระหว่างไคลเอนต์และ API ตัวเอง (พูดว่า API ภายใน) มันอาจเหมาะสมกว่าที่จะส่งคืนการตอบกลับแบบซ้อน (หรือแบน) แทนที่จะให้ลิงก์ไปยังทรัพยากรอื่นซึ่งหมายถึงคำขอ API เพิ่มเติม ซึ่งอาจไม่พึงประสงค์
บรูโน่

@bruno ใช่ แต่มีข้อ จำกัด : ในระบบที่ใหญ่กว่าคุณไม่สามารถหรือไม่ต้องการส่งมอบวัตถุที่เกี่ยวข้องทั้งหมด เขตข้อมูลที่คุณรวมไว้โดยค่าเริ่มต้นจะเป็นเขตอำนาจศาลคุณสามารถเลือกเขตข้อมูลตามการใช้ API ของคุณ ดังนั้นในกรณีนี้คุณอาจมีแพลตฟอร์มที่มีหลายร้อยฟิลด์กรณีใช้งานจะแสดงกล่องเลือกเพื่อเลือกแพลตฟอร์ม ถ้าอย่างนั้นมันก็สมเหตุสมผลที่จะรวมชื่อของแพลตฟอร์ม แต่ไม่ต้องการรายละเอียดทางการเงินของแพลตฟอร์ม
Luc Franken

16

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


10
สิ่งนี้ไม่เป็นประโยชน์เลย OP เองรู้ว่า "มันขึ้นอยู่กับแต่ละแนวทางมีข้อดีข้อเสีย" คุณควรอธิบายว่ามันขึ้นอยู่กับสิ่งใดหรืออย่างน้อยก็ให้ตัวอย่าง
Pratik Singhal

5

ฉันขอแนะนำวิธีที่สองที่นี่https://www.slideshare.net/stormpath/rest-jsonapis

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

ในความคิดของฉันนี่เป็นวิธีที่มีประสิทธิภาพและยืดหยุ่นในกรณีส่วนใหญ่


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