Bisakah REST API mengembalikan banyak sumber daya sebagai satu sumber daya tunggal?

10

Saya sedang dalam proses membuat API REST dan saat ini, saya menghadapi masalah berikut:

  • Fooadalah sumber pertama. Operasi CRUD dapat diterapkan melalui /foo/URI.
  • Baradalah sumber kedua. Operasi CRUD dapat diterapkan melalui /bar/URI.
  • Setiap Foodikaitkan dengan nol atau satu Bar. Alasan mengapa saya tidak memperlakukan Barsebagai sub-sumber daya Fooadalah karena Barcontoh yang sama dapat dibagi antara mutiple Foos. Jadi saya pikir lebih baik untuk mengaksesnya melalui URI independen /foo/[id]/bar.

Masalah saya adalah bahwa dalam banyak kasus, klien yang meminta Foocontoh juga tertarik pada Barcontoh terkait . Saat ini, ini berarti bahwa mereka harus melakukan dua kueri alih-alih satu. Saya ingin memperkenalkan cara yang memungkinkan untuk mendapatkan kedua objek dengan satu permintaan tunggal, tapi saya tidak tahu bagaimana memodelkan API untuk melakukan itu. Apa yang saya dapatkan sejauh ini:

  • Aku bisa memperkenalkan parameter permintaan seperti ini: /foo/[id]?include_bar=true. Masalah dengan pendekatan ini adalah bahwa representasi sumber daya (misalnya struktur JSON) dari respons perlu terlihat berbeda (misalnya wadah seperti { foo: ..., bar: ... }bukan hanya serial Foo), yang membuat Footitik akhir sumber daya "heterogen". Saya pikir itu bukan hal yang baik. Saat bertanya /foo, klien harus selalu mendapatkan representasi (struktur) sumber daya yang sama, terlepas dari parameter kueri.
  • Gagasan lain adalah untuk memperkenalkan titik akhir baca-saja yang baru, misalnya /fooandbar/[foo-id]. Dalam hal ini, tidak ada masalah untuk mengembalikan representasi seperti { foo: ..., bar: ... }, karena dengan demikian hanya representasi "resmi" dari fooandbarsumber daya. Namun, saya tidak tahu apakah titik akhir pembantu seperti itu benar-benar tenang (ini sebabnya saya menulis "bisa" di judul pertanyaan. Tentu saja secara teknis memungkinkan, tetapi saya tidak tahu apakah itu ide yang bagus).

Bagaimana menurut anda? Apakah ada kemungkinan lain?

Ceran
sumber
Apa istilah untuk hubungan antara Foo dan Bar? Bisakah Anda mengatakan bahwa Bar adalah induk dari Foo?
Nathan Merrill
A Bartidak dapat ada tanpa dikaitkan dengan a Foo. Namun, seperti yang saya tulis di atas, mungkin saja beberapa Foos berbagi sama Bar. Seharusnya dimungkinkan untuk membuat Footanpa Barterkait, jadi saya tidak berpikir Barharus diperlakukan sebagai orang tua.
Ceran
1
Saya pikir Anda mengalami beberapa masalah yang saya miliki dengan menerjemahkan langsung hubungan model domain ke dalam URI dan menyamakan sumber daya dengan entitas domain . Mungkin menarik REST API harus digerakkan oleh hypertext . Perhatian khusus pada poin ke-4
Laiv

Jawaban:

6

Sebuah level 3 SISA API akan kembali Anda Foodan juga link yang menunjukkan terkait Bar.

GET /foo/123
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456"/>
</foo>

Anda kemudian dapat menambahkan fitur "menelusuri" ke API Anda yang memungkinkan navigasi tautan;

GET /foo/123?drilldown=bar
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456">
    <bar id="456">
      ..bar stuff...
    </bar>
  </link>
</foo>

Fitur drill down akan duduk di depan API dan mencegat respons. Itu akan membuat panggilan bor dan mengisi rincian sebelum menyerahkan respon kembali ke penelepon.

Ini adalah hal yang cukup umum di REST level 3 karena banyak mengurangi keresahan klien / server melalui http lambat. Perusahaan tempat saya bekerja menghasilkan API REST level 3 dengan fitur yang tepat ini.

Pembaruan: Untuk apa nilainya, berikut ini tampilannya di JSON. Ini adalah bagaimana API kami akan menyusunnya. Perhatikan bahwa Anda dapat membuat sarang bor untuk menarik tautan tautan, dll.

GET /foo/123?drilldown=bar

{
  "self": {
    "type": "thing.foo",
    "uri": "/foo/123=?drilldown=bar",
    "href": "http://localhost/api/foo/123?drilldown=bar"
  },
  "links": [
    {
      "rel": "bar",
      "rev": "foo",
      "type": "thing.bar",
      "uri": "/bar/456",
      "href": "http://localhost/api/bar/456"
    }
  ],
  "_bar": [
    {
      "self": {
        "type": "thing.bar",
        "uri": "/bar/456",
        "href": "http://localhost/api/bar/456"
      },
      "links": [
        {
          ..other link..
        },
        {
          ..other link..
        }
      ]
    }
  ]
}
Qwerky
sumber
Menarik, saya sudah menggunakan hypermedia link / kontrol untuk menghapus kopling ketat ke URI, tapi saya belum memikirkan ide "menelusuri" yang tampaknya sangat menjanjikan. Bagaimana representasi JSON terlihat? Saat ini, setiap representasi JSON dari sumber daya saya berisi linkslarik, setiap entri adalah objek tautan dengan bidang rela dan a uri(mirip dengan contoh xml Anda). Haruskah saya menambahkan bidang ketiga ke setiap objek tautan (mis. data)? Apakah ada standar?
Ceran
Drill down sebenarnya bukan fitur istirahat, jadi tidak ada standar (setidaknya yang saya tahu).
Qwerky
Ada beberapa standar yang diusulkan, seperti stateless.co/hal_specification.html yang saya gunakan dalam aplikasi kami. Sangat dekat dengan contoh Anda.
Pete Kirkham
4

Jika 95% dari semua pertanyaan inginkan Fooserta Bar, maka cukup mengembalikannya dalam dari Fooobjek saat Anda meminta Foo. Cukup tambahkan properti bar(atau istilah lain untuk hubungan), dan letakkan Barobjek di sana. Jika hubungannya tidak ada, gunakan null.

Saya pikir Anda terlalu memikirkan ini :)

Nathan Merrill
sumber
Saya seharusnya tidak membuat angka itu (95%), itu adalah kesalahan, maaf. Yang ingin saya katakan adalah bahwa sebagian besar permintaan tertarik pada kedua sumber sekaligus. Tetapi masih ada sejumlah permintaan yang relevan yang hanya tertarik Foo, dan karena masing Bar- masing cukup besar dalam memori (sekitar 3x-4x ukuran Foo), saya tidak ingin mengembalikan a Barjika klien tidak meminta secara eksplisit.
Ceran
Seberapa besar kita berbicara? Saya ragu bahwa itu akan membuat yang banyak perbedaan di waktu transfer, dan saya lebih memilih API bersih atas kecepatan
Nathan Merrill