Wie entwerfe ich API-Endpunkte zum Posten eines untergeordneten Objekts und zum Abrufen aller untergeordneten Elemente aller Eltern?

11

Zum Beispiel habe ich Entitäten: Client, Bericht. Der Client verfügt möglicherweise über viele Berichte, und ich denke, der Endpunkt für eine einzelne Berichtsverwaltung sollte wie folgt verschachtelt sein:

/clients/{client_id}/reports/{report_id}

Wie für alle Berichte eines Clients wird der Enpoint erwartet:

/clients/{client_id}/reports

Aber wie sollte ein Endpunkt aussehen, um alle Berichte aller Clients zu erhalten, damit die API konsistent und gut gestaltet bleibt?

Meine Ansätze:

  1. (Ich habe es in einer Google-API gesehen) Verwenden Sie stattdessen "-" und analysieren Sie es als "alle":

/clients/-/reports

Dadurch wird das Endpunktformat beibehalten, es sieht jedoch etwas ungewöhnlich aus. Es kann kein RFC gefunden werden, das dies vorschlägt.

  1. Erstellen Sie einen separaten Endpunkt nur für alle Berichte:

/reports

Aber um Kundenberichte zu erhalten, ist es immer noch:

/clients/{client_id}/reports

  1. Refactor-Endpunkte, um "Client" nicht zu einem übergeordneten Element, sondern nur zu einem Filterparameter zu machen:

/reports?client={client_id} - Berichte eines Kunden

/reports - Berichte aller Kunden

Wenn Sie einen neuen Endpunkt zum Posten eines Berichts für einen bestimmten Client hinzufügen, sieht dieser möglicherweise hässlich aus, da es sich um eine POST-Anforderung mit einem Parameter in der URL handelt.

Gibt es noch andere Ideenvorschläge?

Yann
quelle
2
Sie könnten interessiert sein Frage
Laiv

Antworten:

3

Aber wie sollte ein Endpunkt aussehen, um alle Berichte aller Clients zu erhalten, damit die API konsistent und gut gestaltet bleibt?

Denken Sie vor allem daran, dass es keine goldenen Regeln für die Modellierung von RESTful-APIs gibt. Wir haben nur Best Practices und Konventionen. Abgesehen davon lautet die wahrscheinliche Antwort - wie üblich - diejenige, die Ihren Anforderungen am besten entspricht, und in diesem Fall diejenige, die Ihr Modell am besten ausdrückt.

Überprüfen Sie also die drei Optionen anhand der Ausdruckskraft.

# 1 Die "-" Notation

Das ist eine gute Idee. Es erlaubt uns, die Bedingung auszudrücken, zu der alles reportsgehörtclients . Es beschränkt die "Abfrage" auf einen bestimmten Satz von Berichten (die sich innerhalb der clientsGrenze befinden).

Der Begriff der Hierarchie (Zugehörigkeit) wird ständig beibehalten. Wenn er reportsalso an verschiedenen Orten gefunden werden kann, ist diese Notation eine große Sache. Zum Beispiel:

  • Alle Berichte, die Kunden gehören /clients/-/reports
  • Alle Berichte, die zu Abteilungen gehören /departments/-/reports
  • Alle Berichte, die Mitarbeitern gehören /employees/-/reports

Zum Abrufen aller verfügbaren Berichte im System bietet das Beibehalten der Hierarchie jedoch keinen wertvollen Vorteil gegenüber der nächsten Option.

# 2 Verschiedene URIs

Wenn wir zum Zeitpunkt des Abrufs aller verfügbaren Berichte keine Grenzen / Kontexte / Hierarchien ausdrücken müssen, erscheint mir dieser Ansatz vernünftiger.

Die neue URI ( /reports) lässt auch die Möglichkeit einer Berichtsverwaltung offen . Wir müssen es jedoch nicht vollständig RESTful unterstützen, wenn wir es nicht für notwendig halten. Zum Beispiel haben Sie angegeben Make a separate endpoint just for all the reports. Das ist in Ordnung, Sie müssen nur GETeinige Filter zum Abfragen implementieren und vielleicht ist es soweit.

Beachten Sie, dass Sie dies immer noch tun können /reports?client={client_id}. Es ist in Ordnung, unterschiedliche URI für dieselbe Ressource zu haben. Einige Artikel, die ich gelesen habe, würden diese Robustheit nennen .

# 3 Hierarchie umkehren

Ich habe das Gefühl, dass dieser Ansatz nicht Ihren Erwartungen entspricht. Außerdem denke ich, dass es Sie irgendwann zum Startpunkt bringen wird.

Schlussfolgerungen

Beachten Sie, dass sich Nr. 1 und Nr. 2 nicht gegenseitig ausschließen. Wir können beides umsetzen. In Anbetracht der tatsächlichen Situation und gemäß den Prämissen des OP würde ich nur # 2 implementieren.


1: Es ist äquivalent zu, /clients/-/reportsdenke ich

Laiv
quelle
0

Die API-Entwurfsmuster von Google schlagen vor, in diesem Szenario '-' zu verwenden.

GET /clients/-/reports

Quelle:

https://cloud.google.com/apis/design/design_patterns#list_sub-collections

wfg4
quelle
2
Es liegt mir fern, mit dem allmächtigen Google nicht einverstanden zu sein, aber ich denke, ich würde so etwas wie /client/{client_id}/report/{report_id}und/clients/report/{report_id}
Robert Harvey
2
@ RobertHarvey warum nicht einfach /reports?
Laiv
@Laiv: Das würde alle Berichte implizieren. Aktualisieren Sie Ihre Seite. Ich habe einen Ninja-Schnitt gemacht.
Robert Harvey
@ RobertHarvey Ich meine, warum nicht 2 verschiedene Endpunkte /clients...und /reports.
Laiv
1
@Laiv: OK, aber das wirft nur die Frage auf "Welche Parameter soll ich in den Anfragetext einfügen?"
Robert Harvey