Saya sedang mengembangkan layanan REST API untuk situs web jejaring sosial besar tempat saya terlibat. Sejauh ini, ini berfungsi dengan baik. Aku bisa mengeluarkan GET
, POST
, PUT
dan DELETE
permintaan untuk URL objek dan mempengaruhi data saya. Namun, data ini disimpan dalam halaman (dibatasi hingga 30 hasil pada satu waktu).
Namun, apa cara RESTful terbaik untuk mendapatkan jumlah total anggota, melalui API saya?
Saat ini, saya mengeluarkan permintaan ke struktur URL seperti berikut:
- / api / members —Mengembalikan daftar anggota (30 sekaligus seperti yang disebutkan di atas)
- / api / members / 1 —Mempengaruhi satu anggota, tergantung pada metode permintaan yang digunakan
Pertanyaan saya adalah: bagaimana saya kemudian menggunakan struktur URL yang serupa untuk mendapatkan jumlah total anggota dalam aplikasi saya? Jelas meminta hanya id
bidang (mirip dengan API Grafik Facebook) dan menghitung hasil tidak akan efektif karena hanya potongan dari 30 hasil yang hanya akan dikembalikan.
sumber
Jawaban:
Sementara respon ke / API / users dihalaman dan mengembalikan hanya 30, catatan, tidak ada yang mencegah Anda dari termasuk dalam tanggapan juga jumlah catatan, dan info relevan lainnya, seperti ukuran halaman, nomor halaman / offset, dll .
StackOverflow API adalah contoh bagus dari desain yang sama. Berikut dokumentasi untuk metode Pengguna - https://api.stackexchange.com/docs/users
sumber
Saya telah melakukan beberapa penelitian ekstensif tentang ini dan pertanyaan terkait halaman REST lainnya akhir-akhir ini dan berpikir itu konstruktif untuk menambahkan beberapa temuan saya di sini. Saya memperluas pertanyaan sedikit untuk memasukkan pemikiran tentang paging serta hitungan yang terkait erat.
Header
Metadata halaman disertakan dalam tanggapan dalam bentuk header tanggapan. Manfaat besar dari pendekatan ini adalah bahwa payload respons itu sendiri hanyalah permintaan data sebenarnya yang diminta. Membuat pemrosesan respons lebih mudah untuk klien yang tidak tertarik dengan informasi halaman.
Ada banyak header (standar dan kustom) yang digunakan di alam liar untuk mengembalikan informasi terkait halaman, termasuk jumlah total.
X-Jumlah-Hitung
Ini digunakan di beberapa API yang saya temukan di alam liar. Ada juga paket NPM untuk menambahkan dukungan untuk header ini, misalnya Loopback. Beberapa artikel merekomendasikan pengaturan tajuk ini juga.
Ini sering digunakan dalam kombinasi dengan
Link
tajuk, yang merupakan solusi yang cukup bagus untuk halaman, tetapi kekurangan informasi jumlah total.Tautan
Saya merasa, dari banyak membaca tentang subjek ini, bahwa konsensus umum adalah menggunakan
Link
tajuk untuk menyediakan tautan paging ke klien yang menggunakanrel=next
,rel=previous
dll. Masalahnya adalah kurangnya informasi tentang berapa banyak total catatan yang ada, yaitu mengapa banyak API menggabungkan ini denganX-Total-Count
tajuk.Sebagai alternatif, beberapa API dan misalnya standar JsonApi , menggunakan
Link
format tersebut, tetapi menambahkan informasi dalam amplop tanggapan alih-alih ke header. Ini menyederhanakan akses ke metadata (dan menciptakan tempat untuk menambahkan informasi jumlah total) dengan mengorbankan kerumitan pengaksesan data aktual itu sendiri (dengan menambahkan amplop).Rentang Konten
Dipromosikan oleh artikel blog bernama Range header, saya memilih Anda (untuk pagination)! . Penulis membuat alasan kuat untuk menggunakan
Range
danContent-Range
header untuk penomoran halaman. Ketika kita hati-hati membaca yang RFC pada header ini, kami menemukan bahwa memperluas maknanya luar rentang byte sebenarnya diantisipasi oleh RFC dan secara eksplisit diperbolehkan. Saat digunakan dalam konteksitems
alih - alihbytes
, header Rentang sebenarnya memberi kita cara untuk meminta rentang item tertentu dan menunjukkan kisaran hasil total yang terkait dengan item respons. Header ini juga memberikan cara yang bagus untuk menampilkan jumlah total. Dan itu adalah standar sejati yang sebagian besar memetakan satu-ke-satu ke paging. Itu juga digunakan di alam liar .Amplop
Banyak API, termasuk yang dari situs web Tanya Jawab favorit kami menggunakan amplop , pembungkus di sekitar data yang digunakan untuk menambahkan informasi meta tentang data. Juga, standar OData dan JsonApi keduanya menggunakan amplop tanggapan.
Kelemahan besar dari ini (imho) adalah bahwa pemrosesan data respons menjadi lebih kompleks karena data aktual harus ditemukan di suatu tempat di dalam amplop. Juga ada banyak format berbeda untuk amplop itu dan Anda harus menggunakan yang benar. Dikatakan bahwa amplop respons dari OData dan JsonApi sangat berbeda, dengan OData mencampurkan metadata di beberapa titik dalam respons.
Pisahkan titik akhir
Saya pikir ini sudah cukup tercakup dalam jawaban lain. Saya tidak menyelidiki sebanyak ini karena saya setuju dengan komentar yang membingungkan karena Anda sekarang memiliki beberapa jenis titik akhir. Saya pikir paling baik jika setiap titik akhir mewakili (kumpulan) sumber daya.
Pikiran lebih lanjut
Kami tidak hanya harus mengkomunikasikan informasi meta halaman yang terkait dengan respons, tetapi juga mengizinkan klien untuk meminta halaman / rentang tertentu. Menarik juga untuk melihat aspek ini untuk mendapatkan solusi yang koheren. Di sini juga kita dapat menggunakan header (
Range
header tampaknya sangat cocok), atau mekanisme lain seperti parameter kueri. Beberapa orang menganjurkan memperlakukan halaman hasil sebagai sumber daya terpisah, yang mungkin masuk akal dalam beberapa kasus penggunaan (mis/books/231/pages/52
. Saya akhirnya memilih kisaran liar parameter permintaan yang sering digunakan sepertipagesize
,page[size]
danlimit
lain - lain selain mendukungRange
header (dan sebagai parameter permintaan demikian juga).sumber
Range
tajuk, namun saya tidak dapat menemukan cukup bukti bahwa menggunakan apa pun selainbytes
sebagai jenis rentang, adalah valid.acceptable-ranges = 1#range-unit | "none"
Saya pikir formulasi ini secara eksplisit menyisakan ruang untuk unit jangkauan lain selainbytes
, meskipun spesifikasi itu sendiri hanya mendefinisikanbytes
.Saya lebih suka menggunakan HTTP Headers untuk jenis informasi kontekstual ini.
Untuk jumlah total elemen saya menggunakan
X-total-count
header.Untuk link ke halaman berikutnya, sebelumnya, dll. Saya menggunakan http
Link
header:http://www.w3.org/wiki/LinkHeader
Github melakukannya dengan cara yang sama: https://developer.github.com/v3/#pagination
Menurut pendapat saya, ini lebih bersih karena dapat digunakan juga saat Anda mengembalikan konten yang tidak mendukung hyperlink (yaitu binari, gambar).
sumber
X-
.Alternatif saat Anda tidak membutuhkan barang yang sebenarnya
Jawaban Franci Penov tentunya merupakan cara terbaik untuk pergi sehingga Anda selalu mengembalikan item bersama dengan semua metadata tambahan tentang entitas Anda yang diminta. Itu cara yang harus dilakukan.
tetapi terkadang mengembalikan semua data tidak masuk akal, karena Anda mungkin tidak membutuhkannya sama sekali. Mungkin yang Anda butuhkan hanyalah metadata tentang sumber daya yang Anda minta. Seperti jumlah total atau jumlah halaman atau yang lainnya. Dalam kasus seperti itu, Anda selalu dapat meminta kueri URL memberi tahu layanan Anda untuk tidak mengembalikan item melainkan hanya metadata seperti:
atau sesuatu yang serupa ...
sumber
metaonly
atauincludeitems
tidak.Anda dapat mengembalikan hitungan tersebut sebagai header HTTP khusus sebagai tanggapan atas permintaan HEAD. Dengan cara ini, jika klien hanya menginginkan hitungan, Anda tidak perlu mengembalikan daftar sebenarnya, dan tidak perlu URL tambahan.
(Atau, jika Anda berada dalam lingkungan yang terkontrol dari titik akhir ke titik akhir, Anda dapat menggunakan kata kerja HTTP khusus seperti COUNT.)
sumber
Saya akan merekomendasikan menambahkan header untuk hal yang sama, seperti:
Untuk detailnya, lihat:
https://github.com/adnan-kamili/rest-api-response-format
Untuk file swagger:
https://github.com/adnan-kamili/swagger-response-template
sumber
Sejak "X -" - Awalan sudah tidak digunakan lagi. (lihat: https://tools.ietf.org/html/rfc6648 )
Kami menemukan "Accept-Ranges" sebagai taruhan terbaik untuk memetakan rentang pagination: https://tools.ietf.org/html/rfc7233#section-2.3 Karena "Unit Jangkauan" bisa berupa "byte" atau " token". Keduanya tidak mewakili tipe data khusus. (lihat: https://tools.ietf.org/html/rfc7233#section-4.2 ) Namun, dinyatakan bahwa
Yang menunjukkan: menggunakan Unit Rentang kustom tidak bertentangan dengan protokol, tetapi MUNGKIN diabaikan.
Dengan cara ini, kita harus menyetel Rentang Terima ke "anggota" atau jenis unit jarak apa pun, yang kita harapkan. Dan sebagai tambahan, atur juga Content-Range ke range saat ini. (lihat: https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.12 )
Bagaimanapun, saya akan tetap berpegang pada rekomendasi RFC7233 ( https://tools.ietf.org/html/rfc7233#page-8 ) untuk mengirim 206 alih-alih 200:
Jadi, sebagai hasilnya, kita akan memiliki field header HTTP berikut:
Untuk Konten Parsial:
Untuk Konten lengkap:
sumber
Tampaknya paling mudah hanya menambahkan file
dan mengembalikan jumlah total anggota
sumber
Bagaimana dengan titik akhir baru> / api / members / count yang hanya memanggil Anggota.Count () dan mengembalikan hasilnya
sumber
members
koleksi dapat dibuat dengan permintaan POST ke/api
, akan/api/members/count
dibuat sebagai efek samping juga, atau apakah saya harus melakukan permintaan POST eksplisit untuk membuatnya sebelum memintanya? :-)Terkadang kerangka kerja (seperti $ resource / AngularJS) memerlukan sebuah array sebagai hasil kueri, dan Anda tidak dapat benar-benar memiliki respons seperti
{count:10,items:[...]}
dalam kasus ini saya menyimpan "count" di responseHeaders.PS Sebenarnya Anda dapat melakukannya dengan $ resource / AngularJS, tetapi perlu beberapa penyesuaian.
sumber
isArray: false|true
Anda bisa mempertimbangkan
counts
sebagai sumber daya. URL selanjutnya akan menjadi:sumber
Diskusi menarik tentang Mendesain REST API untuk mengembalikan hitungan beberapa objek: https://groups.google.com/g/api-craft/c/qbI2QRrpFew/m/h30DYnrqEwAJ?pli=1
sumber
Saat meminta data paginasi, Anda tahu (dengan nilai parameter ukuran halaman eksplisit atau nilai ukuran halaman default) ukuran halaman, jadi Anda tahu apakah Anda mendapatkan semua data sebagai tanggapan atau tidak. Ketika ada lebih sedikit data sebagai tanggapan daripada ukuran halaman, maka Anda mendapatkan seluruh data. Ketika sebuah halaman penuh dikembalikan, Anda harus meminta halaman lain lagi.
Saya lebih suka memiliki titik akhir terpisah untuk hitungan (atau titik akhir yang sama dengan parameter countOnly). Karena Anda dapat mempersiapkan pengguna akhir untuk proses yang memakan waktu / waktu dengan menampilkan progressbar yang dimulai dengan benar.
Jika Anda ingin mengembalikan datasize di setiap respons, harus ada pageSize, juga disebutkan offset. Sejujurnya, cara terbaik adalah dengan mengulangi filter permintaan juga. Tetapi tanggapannya menjadi sangat kompleks. Jadi, saya lebih suka titik akhir khusus untuk mengembalikan hitungan.
Couleage saya, lebih suka parameter countOnly ke titik akhir yang ada. Jadi, ketika ditentukan, respons hanya berisi metadata.
titik akhir? filter = nilai
endpoint? filter = value & countOnly = true
sumber