Ist es eine gute Praxis, eine API-Antwortliste mit Werten als Wörterbuch zu erstellen?

9

Ich habe einen API-Endpunkt, der einige Statistiken zurückgibt. Derzeit sieht die Antwort so aus:

Option 1:

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

Aber das sieht ein bisschen komplex aus und ich weiß, wie ich es machen soll:

Option 2:

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

Ich verstehe, dass Option 1 einfacher zu erweitern ist, aber für Benutzer weniger komfortabel. Welche anderen Probleme kann ich mit einer dieser Optionen haben? Oder sollte ich eine Hybridlösung machen wie:

Option 3:

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

Die Schlüssel "some-stats-key1" und "some-stats-key2" sind nur interne Werte, und es wird erwartet, dass der API-Benutzer sie mithilfe der Dokumentation in lesbare Namen abbildet. Alle Schlüssel sind einzigartig.

Die Reihenfolge der "Statistiken" ist nicht wichtig.

Der typische Anwendungsfall besteht darin, alle Statistiken abzurufen, Schlüssel mit lesbaren Namen abzugleichen und als Tabelle auf einer Webseite anzuzeigen. Aber momentan kann ich nicht sagen, ob niemand später nur einen Teil der Statistiken benötigt.

Gibt es eine bewährte Methode für dieses Problem?

Yann
quelle
1
Warum genau haben Sie den Namen "stats" explizit in der Antwort genannt? Wenn Sie nur mit "stats" antworten, löschen Sie den äußeren Wrapper und geben Sie einfach das Array der Schlüssel-Wert-Paare zurück. Das könnte Sie näher an die Sauberkeit bringen, die Sie suchen.
K. Alan Bates
5
Überlegen Sie, wie Ihre Clients Ihren JSON in eine Struktur deserialisieren. Wenn Sie diese API beispielsweise von einer Webseite über AJAX verwenden, können Sie mit Option 1 die Schlüssel-Wert-Paare mit Array.forEachund anderen ArrayFunktionen problemlos durchlaufen . Ihre anderen Beispiele werden Array-ähnlichen Vorgängen zusätzliche Komplexität verleihen, was Ihren Kunden das Leben schwer machen könnte
Ben Cottrell,
@ K.AlanBates-Statistiken sind nicht der einzige Schlüssel in einer Antwort. Aktualisiert. Vielen Dank.
Yann
1
Ist die Reihenfolge der Einträge wichtig? Option 1 behält die Reihenfolge bei.
Roman Susi
2
Ohne Hinweise auf die häufigsten API-Anwendungsfälle könnte hier keine Best-Practice-Antwort gefunden werden.
Roman Susi

Antworten:

8

Ich würde mich für Option 2 entscheiden. Wenn der API-Konsument some-stats-key1in etwas Lesbares konvertiert , bedeutet dies wahrscheinlich, dass er / sie eine Liste von Werten hat, an denen er / sie interessiert ist (z. B. some-stats-key1und some-stats-key3), und diese Liste durchläuft. Durch Auswahl eines JSON-Objekts wird es als Wörterbuch / Map deserialisiert, das dem Benutzer der API eine bequeme Suche bietet.

Dies ist mit Option 1 umständlicher, bei der der Verbraucher das JSON-Array durchlaufen oder ein eigenes Wörterbuch mit interessanten Schlüsseln vorab erstellen muss.

Option 3 ist mir etwas zu ausführlich, die Vervielfältigung der Schlüsselnamen gefällt mir einfach nicht.

Wenn die Erweiterbarkeit ein Problem darstellt, können Sie jederzeit eine Version 2 Ihrer API veröffentlichen, die so etwas wie zurückgibt

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

und behalten Sie die v1 für Abwärtskompatibilität. Die Aufrechterhaltung der Abwärtskompatibilität innerhalb einer einzelnen Version der API kann eine echte PITA sein, wenn Sie nicht die vollständige Kontrolle darüber haben, wie die API verwendet wird. Ich habe einen Verbrauch einer API von mir "break" gesehen, als ich gerade ein zusätzliches (optionales) Schlüssel-Wert-Paar hinzugefügt habe (dh die Struktur nicht geändert habe).

Glorfindel
quelle
3
-1 für "Sie können immer eine Version 2 Ihrer API veröffentlichen".
Eric Stein
@EricStein, danke, dass du dir die Zeit genommen hast, deine Ablehnung zu erklären. Ich habe meinen Beitrag bearbeitet, um anzugeben, warum ich dies für die beste Option halte. Wenn Sie immer noch nicht einverstanden sind, gut mit mir.
Glorfindel
1
Die Versionierung einer öffentlich zugänglichen API ist nicht trivial oder leichtfertig. Ich denke, Ihre Antwort weht dies als Argument für Ihren bevorzugten Ansatz ab.
Eric Stein
IMHO ist es (weitaus) einfacher als die Abwärtskompatibilität mit einer einzelnen Version aufrechtzuerhalten.
Glorfindel
Die Rückgabe von zwei Versionen desselben Ressourcentyps in derselben Antwort ist wahrscheinlich die schlechtere Idee, wenn jemand mit REST-APIs arbeitet: - /. Schlagen Sie das in Ihrem Beispiel vor?
Laiv
7

Die beiden Optionen bieten die klassischen Vorteile von Liste und Karte.

1) Die Liste erlaubt doppelte Einträge und behält die Reihenfolge bei. Wenn diese Funktionen wichtig sind, verwenden Sie die Liste, auch wenn sie umständlicher ist.

2) Die Karte erlaubt keine Duplikate. Die Aufrechterhaltung der Ordnung ist mit ein wenig zusätzlicher Arbeit möglich. Der große Vorteil ist die Einfachheit des Datenformats, und die Suche nach einem bestimmten Element ist trivial.

Meine Standardauswahl ist immer die einfachere Karte, aber YMMV.

user949300
quelle
3

Wenn ich Daten von einer API erhalte, überprüfe ich immer , ob alles so ist, wie ich es erwartet habe. Mein Versuch, Ihre Daten zu verarbeiten, besteht also in der Überprüfung und der tatsächlichen Verarbeitung.

In Fall 1 muss ich Folgendes überprüfen: a. Es gibt ein Array. b. Alle Elemente im Array sind Wörterbücher. c. Jedes Wörterbuch hat einen Schlüssel "Name". d. Alle Werte für den Schlüssel "Name" sind eindeutig.

In Fall 3 muss ich Folgendes überprüfen: a. Es gibt ein Wörterbuch. b. Alle Werte im Wörterbuch sind Wörterbücher. c. Jedes Wörterbuch hat einen Schlüsselnamen mit einem Wert, der mit dem Schlüssel im äußeren Wörterbuch übereinstimmt. Etwas besser.

In Fall 2 muss ich Folgendes überprüfen: a. Es gibt ein Wörterbuch.

(Natürlich muss ich auch die Werte überprüfen). Ihr Fall 2 erfordert also die geringste Überprüfung auf meiner Seite. Ich bekomme tatsächlich eine Datenstruktur, die sofort verwendbar ist.

Das einzige Problem mit 2 ist, dass es nicht erweiterbar ist. Anstatt den Wert als Zahl zu senden, können Sie auch {Wert: 10} senden, der dann abwärtskompatibel erweitert werden kann.

Redundanz ist schlecht. Das einzige, was durch Redundanz erreicht wird, ist, dass ich mehr Code schreibe und darüber nachdenke, was ich tun soll, wenn die redundanten Bits nicht übereinstimmen. Version 2 hat keine Redundanz.

gnasher729
quelle
1

Da Sie nach bewährten Methoden für das API-Design gefragt haben:

  • Ich gebe niemals eine API-Antwort zurück, die ein Objekt auf der obersten Ebene enthält. Alle Serviceaufrufe geben eine Menge (als Array) zurück, und diese Menge enthält Elemente (als Objektinstanzen). Die Anzahl der im Array zurückgegebenen Objekte ist für den Server irrelevant. Wenn der Kunde anhand der Anzahl der in der Antwort zurückgegebenen Elemente eine Bestimmung treffen muss, muss der Kunde diese Belastung durchsetzen. Wenn ein einzelnes Element erwartet wird, wird es als Einheitensatz zurückgegeben
  • Wenn ich eine API entwerfe, gehe ich nicht davon aus, zu wissen, welche spezifische Technologie meine API-Kunden verwenden, um diese API zu konsumieren, selbst wenn ich weiß, welche spezifische Technologie sie am wahrscheinlichsten verwenden. Meine Verantwortung ist es, meine Domain-Repräsentationen konsistent an alle Verbraucher zu kommunizieren, nicht an einen bestimmten Verbraucher.
  • Wenn eine strukturelle Option vorhanden ist, mit der die Antwort zusammengestellt werden kann, hat diese Struktur Vorrang vor Optionen, die dies nicht tun
  • Ich bemühe mich zu vermeiden, Darstellungen mit unvorhersehbaren Strukturen zu erstellen.
  • Wenn die Struktur einer Darstellung vorhergesagt werden kann, sollten alle Instanzen innerhalb des Antwortsatzes dieselbe Darstellung haben und der Antwortsatz sollte intern konsistent sein.

Angesichts der von Ihnen vorgeschlagenen Strukturen würde die Struktur, die ich implementieren würde, ähnlich aussehen

[
   { /* 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
quelle
Könnten Sie näher erläutern, warum Sie Punkt 1 folgen, und möglicherweise eine Referenz oder ein Beispiel aus einem Framework oder einigen bekannten Web-APIs zitieren? Insgesamt sieht Ihre Antwort zumindest auf den ersten Blick zu komplex aus.
user949300
@ user949300 ... hmmm. re:overly complexsieht für mich ganz einfach aus. Ich folge Punkt 1, weil dadurch die gesamte Serialisierungslogik konsistente Konventionen beibehält. Die Anzahl der Elemente in einem Antwortsatz ist ein Implementierungsdetail der Serviceschnittstelle. Um "3" Elemente in einem Satz zu kommunizieren, werden diese drei Elemente am bequemsten in ein Array eingeschlossen. "1" ist eine Zahl.
K. Alan Bates
@ user94900 re: example from a well known web APIgoogle.com
K. Alan Bates
@ user94900 re: example from a frameworkalles, was ANSI SQL spricht
K. Alan Bates