Desain API yang tenang. Apa yang harus saya kembalikan jika tidak ada baris?

50

Saat ini saya sedang mengkode API untuk jejaring sosial dengan Slim Framework. Pertanyaan saya adalah: Apa praktik terbaik ketika tidak ada baris untuk kembali dalam struktur json?

Katakanlah panggilan / v1 / get / film ini mengembalikan 2 baris dari nama film tabel:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

Tapi, kemudian saya panggil / v1 / get / books dan tidak ada baris di tabel itu. Haruskah saya mengembalikan struktur kosong?

[
]

... atau lebih baik pesan dan kode kesalahan?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

Yang merupakan praktik yang lebih baik? (API akan digunakan di aplikasi iOS dan Android) Terima kasih!

Andres SK
sumber
3
Bagi saya ini terasa seperti pertanyaan apakah nol sebenarnya jumlah.
scarfridge
16
Contoh Anda rusak. Anda tidak dapat memiliki objek json dengan kunci duplikat. Apa yang Anda cari adalah sebuah array, yaitu[{"name": "..."}, {"name":"..."}]
Martin Wickman
@ MartinWickman Maaf untuk itu, saya baru saja memperbaikinya.
Andres SK
8
@andufo, sebenarnya, Anda tidak ...
avakar
25
Jika aplikasi Anda dimaksudkan untuk TETAP, lalu mengapa kata kerja / metode "mendapatkan" bagian dari URI titik akhir Anda?
user50849

Jawaban:

46

Biasanya saya akan mengembalikan jumlah rekaman sebagai metadata. Saya tidak yakin apakah itu praktik REST yang normal, tetapi tidak banyak data tambahan, dan sangat tepat. Biasanya ada pagination untuk banyak layanan, tidak praktis untuk mengembalikan resultset besar sekaligus. Secara pribadi saya kesal ketika ada pagination untuk set hasil kecil .. Jika kosong, kembalikan number_of_records : 0dan buku sebagai daftar / array kosong books : [].

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

EDIT (beberapa tahun kemudian): Jawaban dari Martin Wickman jauh lebih baik, inilah "penjelasan singkat" mengapa.

Ketika berhadapan dengan pagination selalu ingat kemungkinan konten atau pemesanan berubah. Seperti, permintaan pertama datang, 24 hasil, Anda kembali pertama 10. Setelah itu, "buku baru" dimasukkan dan sekarang Anda memiliki 25 hasil, tetapi dengan permintaan asli itu akan datang dipesan di tempat ke-10. Ketika pengguna pertama meminta halaman ke-2, ia tidak akan mendapatkan "buku baru". Ada beberapa cara untuk mengatasi masalah seperti itu, seperti menyediakan "id permintaan" yang harus dikirim dengan panggilan API berikut, kemudian mengembalikan halaman berikutnya dari set hasil "lama", yang harus disimpan entah bagaimana dan terikat dengan "permintaan id". Alternatifnya adalah menambahkan bidang seperti "daftar hasil diubah sejak permintaan pertama".

Secara umum, jika Anda bisa, cobalah untuk melakukan upaya ekstra dan menghindari pagination. Pagination adalah status tambahan yang dapat dimutasi dan melacak perubahan seperti itu rawan kesalahan, terlebih lagi karena server dan klien perlu menanganinya.

Jika Anda memiliki terlalu banyak data untuk diproses sekaligus , pertimbangkan untuk mengembalikan "daftar id" dengan semua hasil dan detail untuk sebagian daftar itu, dan berikan panggilan API untuk sumber daya multi_get / get_by_id_list.

grizwako
sumber
1
Huh, saya bertanya-tanya mengapa yang satu ini tidak dinilai setinggi yang lain. Saya lebih suka ini karena memberikan kedua daftar kosong (yang seharusnya menjadi daftar, kan?) Yang Anda dapat beralih secara membuta tanpa syarat khusus, tetapi juga metadata dihitung sebagai cara untuk mengatakan, "Tidak, kami tidak t mengabaikan kesalahan untuk Anda, sebenarnya ada 0 hasil ".
Izkata
1
-1 karena booksparameternya adalah objek tetapi 'buku' menyiratkan lebih dari satu dan lebih dari satu menyiratkan array. Data meta itu keren dan pada akhirnya saya berharap koleksi buku menjadi array objek buku; jika tidak ada buku, beri saya array kosong
Charles Sprayberry
9
Masalah dengan ini adalah bahwa menambahkan "number_of_records" tidak memberikan informasi lebih lanjut, itu hanya menambah redundansi dan meningkatkan kompleksitas. Untuk memberi sinyal kesalahan, kembalikan kode http yang sesuai + sesuatu di badan.
Martin Wickman
1
@cspray books adalah daftar, seperti yang ditunjukkan Izkata, salah ketik saya.
grizwako
2
@ MartinWickman Saya tidak ingin mencemari jawaban asli dengan metadata tambahan, tetapi dalam pengalaman saya, banyak layanan tidak langsung mengembalikan semua data, tetapi dengan cara "paginated".
grizwako
105

Contoh Anda rusak. Anda seharusnya tidak memiliki objek json dengan kunci duplikat. Apa yang Anda cari adalah array dengan objek film, seperti ini:

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

Pendekatan ini juga menjawab pertanyaan Anda. Anda harus mengembalikan array kosong ketika kueri tidak cocok:

[]

Di sisi lain, jika Anda mencoba untuk mendapatkan sumber daya film tertentu dengan GET api/movie/34dan film itu tidak ada, maka kembalikan 404 dengan pesan kesalahan yang sesuai (json disandikan) di dalam tubuh

Martin Wickman
sumber
1
+1 Ini adalah JSON yang valid menurut json_xs.
l0b0
15

Jika ini JSON, Anda harus benar-benar mempertimbangkan mengembalikan Array objek. Ini memiliki banyak keuntungan termasuk bahwa ketika Anda tidak memiliki catatan itu adalah array kosong.

Jadi, ketika Anda memiliki catatan, Anda akan kembali:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

Dan ketika Anda tidak memiliki catatan, Anda akan kembali:

    [

    ]
Devdatta Tengshe
sumber
14

Jika Anda berhasil menjalankan operasi, tetapi tidak memiliki apa pun untuk dikembalikan, seperti peta {}kosong atau array kosong []saya lebih suka untuk menjawab dengan 204 kode respons, berikut adalah kutipan dari spesifikasi HTTP Status Code Definition :

Server telah memenuhi permintaan tetapi tidak perlu mengembalikan entitas-badan, dan mungkin ingin mengembalikan metainformation yang diperbarui. Respons MUNGKIN mencakup metainformation baru atau yang diperbarui dalam bentuk entitas-header, yang jika hadir HARUS dikaitkan dengan varian yang diminta.

Jika klien adalah agen pengguna, itu TIDAK HARUS mengubah tampilan dokumen dari yang menyebabkan permintaan untuk dikirim. Respons ini terutama dimaksudkan untuk memungkinkan input untuk tindakan terjadi tanpa menyebabkan perubahan pada tampilan dokumen aktif agen pengguna, meskipun setiap metainformasi baru atau yang diperbarui HARUS diterapkan pada dokumen yang saat ini dalam tampilan aktif agen pengguna.

Respons 204 HARUS TIDAK menyertakan badan pesan, dan karenanya selalu diakhiri oleh baris kosong pertama setelah bidang header.

Intinya, saya sarankan menggunakan 204 di aplikasi RESTful melalui HTTP ketika tidak ada yang kembali.

David Sergey
sumber
4
Saya setuju dengan komentar @ avakar pada jawaban lain di sini. Jika klien mencoba mengakses / v1 / get / bioskop / 1 maka itu harus mengembalikan 404 jika tidak ada film yang dapat diidentifikasi oleh 1. Just / v1 / get / film harus mengembalikan 200 bahkan jika tidak ada film. Tetapi 204 tidak cocok karena ditujukan untuk tindakan masukan.
imel96
7
Masalah lain dengan solusi ini adalah bahwa ia biasanya memerlukan kode khusus di klien: Jika responsnya adalah daftar kosong, ia dapat diuraikan sebagai JSON seperti halnya respons normal. Jika responsnya adalah badan kosong, parser JSON kemungkinan akan mengeluh (karena dokumen emtpy tidak valid JSON), sehingga klien memerlukan kode tambahan untuk memeriksa HTTP 204 dan melewatkan penguraian.
sleske
7
Saya percaya ini adalah salah membaca maksud dari 204. 204 tampaknya dimaksudkan bukan untuk operasi yang mengharapkan konten dan gagal menemukan apa pun, tetapi untuk operasi yang berhasil dan tidak memiliki pengembalian yang diinginkan . Dari Wikipedia: "Server berhasil memproses permintaan, tetapi tidak mengembalikan konten apa pun. Biasanya digunakan sebagai respons terhadap permintaan penghapusan yang berhasil."
XML
10

Ada cukup banyak pekerjaan yang dilakukan untuk membuat format API JSON standar .

Mengikuti prinsip-prinsip dalam spesifikasi itu berarti bahwa semua sumber daya yang dikembalikan harus secara efektif menjadi "koleksi" (bahkan ketika hanya satu sumber daya dimasukkan). Mengikuti ini berarti bahwa panggilan Anda untuk /v1/get/moviesakan kembali:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

Panggilan Anda ke /v1/get/books(yang mengembalikan nol sumber daya) akan kembali:

{
    "books": []
}
Tim Blair
sumber
5

Untuk contoh spesifik Anda, saya akan merekomendasikan bahwa / v1 / get / books harus mengembalikan HTTP 200 dengan array kosong.

Jika saya membaca posting Anda dengan benar, API Anda bermaksud mengumpulkan buku. Secara metaforis, Anda memiliki rak buku untuk buku, rak DVD untuk film, dan mungkin wadah lain yang belum Anda sebutkan di sini. Karena Anda berniat mengumpulkan buku, / v1 / get / books adalah rak buku Anda. Ini berarti ada sumber daya yang valid di sana - daftar buku - yang kebetulan kosong dalam contoh spesifik Anda.

Alasan saya tidak menyarankan mengembalikan HTTP 404 dalam kasus ini adalah bahwa rak buku masih ada. Saat ini tidak ada buku di situ, tetapi masih ada rak buku. Jika itu bukan rak buku - jika API tidak bermaksud mengumpulkan buku, misalnya - maka HTTP 404 akan sesuai. Tetapi karena ada sumber daya di sana, Anda seharusnya tidak memberi sinyal bahwa tidak ada satu pun, yang dilakukan HTTP 404. Oleh karena itu, saya berpendapat bahwa 200 dengan array kosong (menandakan koleksi) lebih tepat.

Alasan saya tidak menyarankan mengembalikan HTTP 204 adalah karena ini akan menyarankan bahwa "Tidak Ada Konten" adalah keadaan umum: melakukan tindakan ini pada sumber daya ini biasanya tidak akan mengembalikan apa pun. Itu sebabnya biasanya digunakan sebagai respons terhadap permintaan DELETE, misalnya: sifat penghapusan umumnya berarti tidak ada yang tersisa untuk dikembalikan. Kasingnya mirip ketika digunakan untuk menanggapi permintaan dengan keluarga header If-Modified: Anda hanya ingin konten jika sumber daya telah berubah, tetapi tidak, jadi saya tidak akan memberikan konten apa pun kepada Anda.

Tapi saya berpendapat bahwa untuk MENDAPAT koleksi kosong tapi valid, HTTP 204 tidak masuk akal. Jika ada item dalam koleksi, maka representasi yang tepat akan menjadi array dari data itu. Oleh karena itu, ketika tidak ada data di sana (tetapi koleksi tersebut valid), representasi yang tepat adalah array kosong.

Spooniest
sumber
5

Anda benar-benar harus melakukan hanya satu dari dua hal

Entah Kembalikan 200 (OK)kode status, dan larik kosong di badan.

Atau Kembalikan 204 (NO CONTENT)kode status dan TIDAK ada badan tanggapan.

Bagi saya, opsi 2 tampaknya lebih benar secara teknis dan sejalan dengan prinsip REST dan HTTP.

Namun, opsi 1 tampaknya lebih efisien untuk klien - karena klien tidak memerlukan logika tambahan untuk membedakan antara dua kode status (sukses). Karena ia tahu bahwa ia akan selalu menerima sebuah array, ia hanya perlu memeriksa apakah tidak ada, satu, atau banyak item dan memprosesnya dengan tepat.

Vihung
sumber
3

Saya telah melihat kedua kasus di lingkungan produksi. Yang mana yang Anda pilih tergantung pada siapa yang akan menggunakan API. Jika mereka ingin tahu mengapa daftar itu kosong atau untuk memastikan bahwa daftar itu benar-benar kosong dan tidak ada kesalahan terjadi saat mengambilnya, maka Anda harus melampirkan objek "kesalahan". Jika mereka tidak peduli, lanjutkan dengan mengembalikan daftar kosong. Saya akan menggunakan pendekatan kedua karena mencakup lebih banyak kebutuhan daripada yang pertama.

devnull
sumber
3

Hal pertama yang harus dipertimbangkan, karena Anda sedang membangun API RESTful, adalah mengembalikan kode respons yang sesuai. Dan kode respons yang lebih tepat untuk mengomunikasikan bahwa permintaan melalui normal, tetapi sumber daya yang diminta tidak tersedia saat ini adalah 404 terhormat.

Jika Anda mendesain API Anda sedemikian rupa sehingga selalu mengembalikan kode respons yang masuk akal, Anda bahkan mungkin tidak perlu mengembalikan tubuh ketika sumber daya tidak ditemukan. Yang mengatakan, mengembalikan tubuh, terutama yang dapat dibaca secara manusia, tidak ada salahnya.

Tidak ada "praktik terbaik" di sini, kedua contoh Anda sewenang-wenang, cukup pilih satu dan konsisten . Pengembang benci kejutan, jika /v1/get/movieskembali {}ketika tidak ada film maka kami juga berharap /v1/get/actorsuntuk kembali {}ketika tidak ada aktor.

yannis
sumber
1
Mengembalikan 404 benar-benar adalah hal yang tepat untuk dilakukan, tetapi sayangnya tidak ada yang benar-benar melakukannya - termasuk saya.
RibaldEddie
1
jika Anda memiliki respons kompleks, dan hanya sebagian saja yang kosong, mengembalikan 404 akan membingungkan pengguna.
devnull
5
Saya tidak akan setuju dengan pesan 404. A 404 saya akan menafsirkan sebagai "sumber daya tidak ada" dan khawatir jika saya mendapatkan sesuatu yang salah dengan URL saya atau apa pun. Jika saya meminta daftar film dan mendapatkan 404 saya akan berpikir bahwa tidak ada sumber daya film sama sekali. "204 Tidak Ada Konten" mungkin lebih tepat.
thorsten müller
8
Ok, benda "tidak ada tubuh" akan membunuhnya. Tetapi: "Kelas kode status 4xx dimaksudkan untuk kasus-kasus di mana klien keliru." Tetapi tidak ada kesalahan di sisi klien. Jadi 404 memberikan informasi yang salah. Entah mengirim 204 tanpa badan atau mengatakan tidak apa-apa dan mengirim daftar kosong.
thorsten müller
9
Anda meminta daftar buku, mengembalikan 404 berarti daftar itu tidak ada, bukan kosong. Mengembalikan 200 beserta daftar kosong sepertinya satu-satunya pilihan yang masuk akal bagi saya.
avakar
1

Saya tidak berpikir jawaban yang tepat adalah yang ditandai.

Jawaban yang diberikan oleh nirth harus yang terbaik, dalam skenario REST yang sebenarnya. Respons tubuh harus kosong dan kode status http: 204; sumber daya memang ada tetapi tidak memiliki konten saat itu: kosong.

REST HTTP_Status_Codes

jmmtcarvalho
sumber
1

Saya merekomendasikan 200+ array kosong, karena menyederhanakan penanganan oleh semua klien API. 200 + array berarti "Saya mengembalikan semua data yang ada di sana". Baik untuk kode yang mengirimkan data dan kode yang memprosesnya, jumlah item tidak akan relevan.

Setiap kode status lainnya perlu didokumentasikan dengan baik dan dikirimkan dengan benar oleh server dan diproses dengan baik oleh klien, dan kita semua tahu bagaimana kemungkinan hal ini terjadi.

Ada saran untuk mengembalikan status 204+ badan kosong. Itu berarti Anda memaksa setiap satu klien status proses 204 dengan benar. Selain itu Anda memaksa mereka untuk menangani balasan non-JSON! Saya harap semua orang menyadari bahwa hanya karena permintaan mendapat jawaban, itu tidak berarti jawaban datang dari server ketika http digunakan, dan hanya memeriksa bahwa responsnya adalah JSON menangani banyak kasus tersebut.

gnasher729
sumber
0

Saya akan "Itu tergantung".

Jika nol adalah hasil yang masuk akal, maka kembalikan daftar kosong. Misalnya jika Anda ingin mendapatkan semua karyawan yang disebut "bob" di mana "tidak ada" adalah hasil yang cukup masuk akal. Jika bukan hasil yang diharapkan, kembalikan kesalahan. Misalnya mendapatkan daftar historis alamat jalan untuk orang yang Anda pekerjakan .. Mereka harus tinggal di suatu tempat sehingga tidak ada hasil yang mungkin merupakan kesalahan, bukan hanya kondisi normal.

Saya yakin Anda dapat berdebat dengan spesifik contoh saya, tetapi Anda mendapatkan ide ...

JohnB
sumber
0
  • Pertama-tama, memiliki getURL Anda tidak tenang, GET tersirat oleh metode HTTP.
  • Jika Anda meminta koleksi seperti GET api/movieskembalikan 200 OKdengan array kosong [].
  • Jika Anda meminta film tertentu seperti GET api/movies/1(di mana 1id) dan tidak ada, kembalikan a 404 Not Found.

Mengapa? Anda meminta sumber daya . Saat Anda meminta koleksi, sumber daya itu sendiri (koleksi) ada. Karenanya, a 404salah. Tetapi jika Anda meminta film tertentu dan tidak ada, sumber daya yang diminta tidak ada, dan Anda harus mengembalikan a 404.

felixfbecker
sumber
-2

Jika Anda mengembalikan JSON, lebih baik untuk selalu mengembalikan hitungan dan pesan kesalahan dan mungkin Boolean yang mengindikasikan jika ada kesalahan atau tidak, itu adalah tiga nilai meta standar saya yang dikembalikan dengan setiap daftar baris.

Tiongkok
sumber