Apakah ini praktik yang baik untuk membuat daftar nilai tanggapan API sebagai kamus?

9

Saya memiliki titik akhir API yang mengembalikan beberapa statistik. Saat ini responsnya seperti:

Pilihan 1:

{
    "stats": [
                {
                    "name": "some-stats-key1",
                    "value": 10
                },
                {
                    "name": "some-stats-key2",
                    "value": 20
                }
            ],
    ... other keys
}

Tapi ini terlihat agak rumit dan saya harus membuatnya seperti apa:

Pilihan 2:

{
    "stats": {
                "some-stats-key1": 10,
                "some-stats-key2": 20
            }
    ... other keys
}

Saya mengerti bahwa Opsi 1 lebih mudah diperpanjang, tetapi kurang nyaman bagi pengguna. Apa masalah lain yang bisa saya hadapi menggunakan salah satu opsi ini? Atau haruskah saya membuat solusi hybrid seperti:

Opsi 3:

{
    "stats": {
                "some-stats-key1": {
                                        "name": "some-stats-key1",
                                        "value": 10
                                    },
                "some-stats-key2": {
                                        "name": "some-stats-key2",
                                        "value": 20
                                    },
            },
    ... other keys
}

Kunci "some-stats-key1" dan "some-stats-key2" hanyalah nilai internal dan diharapkan pengguna API akan memetakannya menjadi nama yang dapat dibaca menggunakan dokumentasi. Semua kunci unik.

Urutan "statistik" tidak penting.

Kasus penggunaan yang umum adalah hanya untuk mendapatkan semua statistik, mencocokkan kunci dengan nama yang dapat dibaca dan ditampilkan sebagai tabel di halaman web. Tetapi saat ini saya tidak bisa mengatakan jika tidak ada yang akan membutuhkan hanya sebagian dari statistik nanti.

Apakah ada praktik terbaik untuk masalah ini?

Yann
sumber
1
Mengapa Anda memiliki nama "stats" yang secara eksplisit disebutkan di dalam respons? Jika Anda tidak merespons dengan selain "statistik", lepaskan pembungkus luar dan kembalikan array pasangan nilai kunci. Itu mungkin membuat Anda lebih dekat dengan kebersihan yang Anda cari.
K. Alan Bates
5
Pertimbangkan bagaimana klien Anda akan deserialise JSON Anda menjadi suatu struktur. Misalnya, jika Anda menggunakan API ini dari halaman web di atas AJAX, maka opsi 1 memungkinkan Anda untuk dengan mudah beralih melalui pasangan nilai kunci dengan Array.forEachdan Arrayfungsi lainnya . Contoh Anda yang lain akan menambah kompleksitas tambahan untuk operasi mirip array, yang bisa membuat hidup Anda lebih sulit bagi klien Anda
Ben Cottrell
@ K.AlanBates bukan satu-satunya kunci dalam respons. Diperbarui. Terima kasih.
Yann
1
Apakah urutan entri penting? Opsi 1 mempertahankan pesanan.
Roman Susi
2
Tanpa memberi petunjuk pada kasus penggunaan API yang paling sering, tidak ada jawaban praktik terbaik di sini.
Roman Susi

Jawaban:

8

Saya akan memilih opsi 2. Jika konsumen API akan mengonversi some-stats-key1menjadi sesuatu yang dapat dibaca, itu mungkin berarti ia memiliki daftar nilai yang ia minati (katakan, some-stats-key1dan some-stats-key3), dan akan beralih ke daftar itu. Dengan memilih objek JSON, itu akan dideserialisasi sebagai kamus / peta yang menyediakan pencarian yang nyaman bagi konsumen API.

Ini akan lebih rumit dengan opsi 1, di mana konsumen perlu untuk mengulangi lebih dari array JSON, atau pra-buat kamus mereka sendiri dengan kunci yang menarik.

Opsi 3 agak terlalu bertele-tele bagi saya, duplikasi nama-nama kunci tidak menarik bagi saya.

Jika ekstensibilitas menjadi perhatian, Anda selalu dapat menerbitkan v2 API Anda yang mengembalikan sesuatu seperti

"stats": {
    "some-stats-key1": { "value": 10, "error-margin": 0.1 },
    "some-stats-key2": { "value": 20, "error-margin": 0.2 }
}

dan simpan v1 untuk kompatibilitas ke belakang. Mempertahankan kompatibilitas mundur dalam satu versi API dapat menjadi PITA nyata jika Anda tidak memiliki kontrol penuh atas bagaimana API dikonsumsi. Saya telah melihat konsumsi API saya 'break' ketika saya baru saja menambahkan pasangan nilai kunci tambahan (opsional) (yaitu tidak mengubah struktur).

Glorfindel
sumber
3
-1 untuk "Anda selalu dapat menerbitkan v2 API Anda".
Eric Stein
@EricStein terima kasih telah meluangkan waktu untuk menjelaskan downvote Anda. Saya mengedit posting saya untuk menunjukkan mengapa saya pikir ini adalah pilihan terbaik. Jika Anda masih tidak setuju, baiklah dengan saya.
Glorfindel
1
Versi API yang menghadap publik tidak sepele atau harus dilakukan dengan ringan. Saya pikir jawaban Anda mengesampingkannya sebagai argumen yang mendukung pendekatan pilihan Anda.
Eric Stein
IMHO, ini (jauh) lebih mudah daripada mempertahankan kompatibilitas dengan satu versi.
Glorfindel
Mengembalikan dua versi dari jenis sumber daya yang sama dalam respons yang sama mungkin merupakan ide terburuk yang dapat digunakan seseorang dengan API REST: - /. Apakah itu yang Anda sarankan dalam contoh Anda?
Laiv
7

Kedua opsi memiliki keunggulan Daftar vs. Peta klasik.

1) Daftar memungkinkan entri duplikat dan mempertahankan ketertiban. Jika fitur-fitur ini penting, gunakan Daftar, meskipun itu clunkier.

2) Peta tidak memungkinkan duplikat. Mempertahankan pesanan dimungkinkan dengan sedikit kerja ekstra. Keuntungan besar adalah kesederhanaan dalam format data, dan mencari elemen tertentu sepele.

Pilihan default saya selalu adalah Peta yang lebih sederhana, tetapi YMMV.

pengguna949300
sumber
3

Ketika saya mendapatkan data dari API, saya selalu memeriksa bahwa semuanya seperti yang saya harapkan. Jadi upaya saya untuk memproses data Anda terdiri dari verifikasi, dan pemrosesan yang sebenarnya.

Dalam kasus 1 saya harus memeriksa: a. Ada sebuah array. b. Semua item dalam array adalah kamus. c. Setiap kamus memiliki "nama" kunci. d. Semua nilai untuk kunci "nama" unik.

Dalam kasus 3 saya harus memeriksa: a. Ada kamus. b. Semua nilai dalam kamus adalah kamus. c. Setiap kamus memiliki "nama" kunci dengan nilai yang cocok dengan kunci di kamus luar. Sedikit lebih baik.

Dalam kasus 2 saya harus memeriksa: a. Ada kamus.

(Tentu saja saya harus memeriksa nilainya juga). Jadi kasing 2 Anda membutuhkan paling sedikit pemeriksaan di pihak saya. Saya benar-benar mendapatkan struktur data yang langsung dapat digunakan.

Satu-satunya masalah dengan 2 adalah tidak dapat diperpanjang. Jadi, alih-alih mengirim nilai sebagai angka, Anda dapat mengirim {value: 10} yang kemudian dapat diperluas dengan cara yang kompatibel ke belakang.

Redundansi itu buruk. Satu-satunya hal yang redundansi capai adalah membuat saya menulis lebih banyak kode, dan memaksa saya untuk berpikir tentang apa yang harus saya lakukan jika bit yang berlebihan tidak setuju. Versi 2 tidak memiliki redundansi.

gnasher729
sumber
1

Karena Anda meminta praktik yang baik untuk desain API:

  • Saya tidak pernah mengembalikan respons api yang berisi objek di tingkat atas. Semua panggilan layanan mengembalikan set (sebagai array), dan set itu berisi elemen (sebagai instance objek.) Jumlah objek yang dikembalikan dalam array tidak relevan dengan server. Jika klien perlu menentukan dari jumlah barang yang dikembalikan dalam respons, beban itu adalah tanggung jawab klien. Jika satu item diharapkan, itu akan dikembalikan sebagai satu set unit
  • Ketika saya merancang api, saya tidak berasumsi untuk mengetahui teknologi spesifik apa yang akan digunakan klien api saya untuk mengonsumsi api tersebut, bahkan ketika saya tahu teknologi spesifik apa yang paling mungkin mereka gunakan. Tanggung jawab saya adalah untuk mengkomunikasikan representasi domain saya secara konsisten ke semua konsumen, tidak nyaman untuk konsumen tertentu.
  • Jika ada opsi struktural untuk memungkinkan tanggapan dikomposisi, struktur ini mengambil prioritas di atas opsi yang tidak
  • Saya berusaha keras untuk menghindari membuat representasi yang memiliki struktur tak terduga.
  • Jika struktur representasi dapat diprediksi, maka semua contoh di dalam rangkaian respons harus dari representasi yang sama dan rangkaian respons harus konsisten secara internal.

Jadi, mengingat struktur yang Anda usulkan, struktur yang akan saya terapkan akan terlihat mirip dengan ini

[
   { /* returns only the 'common' metrics */
      "stats": [
                  {"key":"some-metric1","value":10},
                  {"key":"some-metric2","value":20}
               ]
   },
   { /* returns an optional metric in addition to the "common" metrics */
      "stats": [
                  {"key":"some-metric1","value":15},
                  {"key":"some-metric2","value":5},
                  {"key":"some-optional-metric", "value":42}
               ]
   },
   { /*returns the 'common' metrics as well as 2 candidates for "foo-bar" */
      "stats": [
                  {"key":"some-metric1", "value": 5},
                  {"key":"some-metric2", "value": 10},
                  {"key":"foo-bar-candidate", "value": 7},
                  {"key":"foo-bar-candidate", "value": 11}
               ]
   }
]
K. Alan Bates
sumber
Bisakah Anda menguraikan mengapa Anda mengikuti poin 1, mungkin mengutip referensi atau contoh dari kerangka kerja atau beberapa API web terkenal? Secara keseluruhan jawaban Anda terlihat terlalu rumit, setidaknya pada pandangan pertama.
user949300
@ user949300 ... hmmm. re:overly complexterlihat sangat sederhana bagiku. Saya mengikuti poin # 1 karena menyebabkan semua logika serialisasi mempertahankan konvensi yang konsisten. Jumlah item dalam set respons adalah detail implementasi antarmuka layanan. Untuk mengkomunikasikan "3" item dalam satu set, ketiga item tersebut paling mudah dibungkus dalam sebuah array. "1" adalah angka.
K. Alan Bates
@ user94900 re: example from a well known web APIgoogle.com
K. Alan Bates
@ user94900 re: example from a frameworkapa pun yang berbicara ANSI SQL
K. Alan Bates