REST API - Haruskah API Mengembalikan Objek JSON Bersarang?

38

Ketika datang ke API JSON apakah itu praktik yang baik untuk meratakan respons dan menghindari objek JSON bersarang?

Sebagai contoh katakanlah kita memiliki API yang mirip dengan IMDb tetapi untuk video game. Ada beberapa entitas, Game, Platform, ESRBRating, dan GamePlatformMap yang memetakan Game dan Platform.

Katakanlah Anda meminta / game / 1 yang mengambil game dengan ID 1 dan mengembalikan objek game dengan platform dan menghindari sarang.

{
  "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"
  }
}

Jika Anda menggunakan sesuatu seperti JPA / Hibernate, ini dapat secara otomatis melakukan ini untuk Anda jika diatur ke FETCH.EAGER.

Opsi lainnya adalah cukup dengan API dan menambahkan lebih banyak titik akhir.

Dalam hal ini ketika / game / 1 diminta hanya objek game dikembalikan.

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

Jika Anda ingin platform dan / atau ESRBRating, Anda harus memanggil yang berikut ini:

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

Metode ini sepertinya berpotensi menambah beberapa panggilan lagi ke server tergantung pada data apa yang dibutuhkan klien dan kapan mereka membutuhkannya.

Ada satu pikiran terakhir yang saya miliki di mana Anda akan mendapatkan sesuatu seperti ini kembali.

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

Namun ini mengasumsikan mereka tidak memerlukan ID atau informasi apa pun lainnya yang terkait dengan objek platform tersebut.

Saya bertanya secara umum apa cara terbaik untuk menyusun objek JSON Anda yang dikembalikan dari API Anda. Haruskah Anda mencoba untuk tetap sedekat mungkin dengan entitas Anda, atau apakah boleh menggunakan Objek Domain atau Objek Transfer Data? Saya mengerti metode ini akan memiliki pertukaran, baik lebih banyak pekerjaan pada lapisan akses data atau lebih banyak pekerjaan untuk klien.

Saya juga ingin mendengar jawaban terkait menggunakan Spring MVC sebagai teknologi backend untuk API, dengan JPA / Hibernate atau MyBatis untuk kegigihan.

greyfox
sumber
6
Keberatan apa, jika ada, apakah Anda telah mengembalikan objek yang disematkan? Mengembalikan objek yang disematkan secara individual dari titik akhir yang berbeda akan sangat mengganggu (belum lagi lambat).
Robert Harvey
1
Secara pribadi saya tidak keberatan. Saya tidak tahu apa yang dianggap praktik terbaik. Seorang kolega mengklaim bekerja dengan objek yang disematkan di AngularJS tidak lurus ke depan dan akhirnya saya ingin salah satu aplikasi Ember dari AngularJS untuk menggunakan API. Saya tidak cukup tahu tentang Angular atau Ember untuk mengetahui apakah itu akan berdampak atau tidak.
greyfox
3
Jawabannya akan tergantung pada apakah Anda ingin mengembalikan objek domain, objek DTO, objek ViewModel, atau objek KitchenSink. Objek mana yang Anda kembalikan kemungkinan besar akan ditentukan oleh apa yang dibutuhkan aplikasi Anda, dan bagaimana perilaku objek tersebut melalui Internet. Contoh: jika Anda mencoba mengisi halaman web dengan data dari faktur, sangat mungkin Anda akan mengembalikan objek yang berisi semua yang Anda butuhkan (kecuali jika Anda berencana AJAXing di item baris, atau sesuatu seperti itu).
Robert Harvey
Jika demikian, saat Anda meminta game, Anda mungkin ingin mengetahui genre, platform, dan ESRBRating. Itu masuk akal. Dalam hal desain dari perspektif Java apakah Anda akan merekomendasikan memiliki paket Entity yang memiliki hak JPA, dan kemudian paket domain yang merupakan objek bisnis / DTO yang dikembalikan ke pengguna?
greyfox
1
Panggilan ke server itu mahal. API yang mengharuskan Anda mengirim data menggunakan banyak panggilan akan lebih lambat daripada API yang memungkinkan Anda mendapatkan semuanya dalam satu panggilan, seringkali bahkan ketika yang terakhir mengembalikan informasi yang tidak dibutuhkan.
Gort the Robot

Jawaban:

11

Alternatif lain (menggunakan HATEOAS). Ini sederhana, sebagian besar dalam praktiknya Anda menambahkan tag tautan di json tergantung pada penggunaan HATEOAS Anda.

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: [] },
  ]
}

Tentu saja Anda dapat menyematkan semua data dalam semua cantuman, tetapi kemungkinan besar terlalu banyak data. Dengan cara ini Anda dapat menyematkan data yang diperlukan dan memuat lebih banyak jika Anda benar-benar ingin bekerja dengannya.

Implementasi teknis dapat berisi caching. Anda dapat men-cache link platform dan nama dalam objek game dan mengirimkannya langsung tanpa harus memuat api platform sama sekali. Kemudian saat dibutuhkan Anda bisa memuatnya.

Anda lihat misalnya bahwa saya menambahkan beberapa informasi formulir. Saya melakukan itu untuk menunjukkan kepada Anda bahwa ada lebih banyak informasi dalam objek json terperinci daripada yang ingin Anda muat dalam daftar permainan.

Luc Franken
sumber
Saya tidak berpikir itu secara teknis HATEOS karena tidak ada keadaan.
RibaldEddie
Ya, tidak yakin kata yang tepat untuk proses ini. HATEOS secara umum digunakan untuk menautkan API yang lain, tetapi saya setuju juga ada hubungannya dengan keadaan. Padahal ide implementasi akan sama. Di sini Anda melihat sedikit lebih banyak tentang bagaimana hal itu dapat digunakan oleh sebuah contoh: stormpath.com/blog/linking-and-resource-expansion-rest-api-tips
Luc Franken
Tapi itu ide yang bagus!
RibaldEddie
1
Jika Anda mengembangkan API di mana ada kohesi antara klien dan api itu sendiri (katakanlah api internal), mungkin lebih masuk akal untuk mengembalikan respons yang bersarang (atau diratakan) daripada memberikan tautan ke sumber daya lain, yang berarti lebih banyak permintaan API yang mungkin tidak diinginkan.
Bruno
@bruno ya tetapi dengan batas: Pada sistem yang lebih besar Anda tidak dapat atau tidak ingin memasok semua objek terkait secara penuh. Bidang yang Anda sertakan secara default adalah arbitrer, Anda dapat memilihnya berdasarkan penggunaan api Anda. Jadi dalam hal ini Anda mungkin memiliki platform dengan ratusan bidang, use case menunjukkan kotak pilih untuk memilih platform. Maka masuk akal untuk memasukkan nama platform tetapi tidak perlu rincian keuangan platform misalnya.
Luc Franken
16

Ini adalah salah satu pertanyaan dasar ketika datang ke desain REST API. Setiap desainer bertanya pada diri sendiri pertanyaan ini pada hari pertama. Maaf tapi jawabannya "tergantung". Setiap pendekatan memiliki pro dan kontra dan Anda hanya perlu membuat keputusan dan mengikutinya.

RibaldEddie
sumber
11
Ini sama sekali tidak membantu. OP sendiri tahu "itu tergantung dan setiap pendekatan memiliki pro dan kontra". Anda harus menjelaskan tentang hal-hal apa yang bergantung atau paling tidak memberikan beberapa contoh.
Pratik Singhal
5

Saya kedua pendekatan yang disajikan di sini https://www.slideshare.net/stormpath/rest-jsonapis

Singkatnya, sertakan sumber daya bersarang sebagai tautan di sumber daya induk, sementara itu, berikan parameter ekspansi di titik akhir induk.

Menurut pendapat saya, ini adalah cara yang efisien dan fleksibel dalam banyak kasus.

Wei Qiu
sumber
2
Saya suka pendekatan ini. Bagi siapa pun yang bertanya-tanya, ini dimulai pada SLIDE 57 di tayangan slide terkait.
Adam Plocher