Bitte führen Sie einen Streit zwischen mir und einem Freund.
Wir entwickeln derzeit eine Produkt-API. Unsere Produkteinheit sieht so aus
{
"Id": "",
"ProductName": "",
"StockQuantity": 0
}
Produktverkäufe werden von Dritten abgewickelt und sind verpflichtet, uns die gekaufte Menge mitzuteilen, damit das StockQuantity
Feld verkleinert werden kann.
Mein Ansatz:
PUT /api/Product/{Id}/ --data { "StockQuantity": "{NewStockQuantity}" }
Der Dritte ist dafür verantwortlich, das Produkt abzufragen, die Berechnung auf der Grundlage der aktuellen StockQuantity
und gekauften Menge durchzuführen und eine PUT
Anfrage mit dem neuen Wert zu senden .
Mein Freund möchte nicht, dass der Dritte die Berechnung durchführt. Sein Ansatz
PUT /api/Product/{Id}/DecreaseStock --data { "PurchasedQuantity": "{PurchasedQuantity}" }
So können wir die Berechnung durchführen und die aktualisieren StockQuantity
Ich möchte keine funktionsbasierten Endpunkte erstellen und er möchte nicht auf Dritte vertrauen, um die Berechnungen durchzuführen.
Was wäre der richtige Weg für uns, um dieses Problem anzugehen?
quelle
Antworten:
Sie können Ihre Drittanbieter Verkäufe an Ihr Produkt senden lassen. Zum Beispiel:
Ich stimme sowohl Ihrem als auch dem Ihres Kollegen zu. Dies ist Geschäftslogik und sollte nicht dem Client der API überlassen werden, aber Sie sollten auch vermeiden, "Funktionen" als Endpunkte zu haben.
Manchmal ist es so einfach, solche Probleme zu lösen, wie es anders zu nennen, zugegebenermaßen nicht immer.
quelle
/sale
Endpunkts noch gültig?/sale
und/product/{id}/sale
sind völlig unabhängig und die Tatsache, dass sie ähnliche Namen haben, bedeutet in keiner Weise, dass sie auf dieselbe Ressource verweisen.sale
ist nicht in meiner Domain und es ist nicht Teil vonproduct
. Ist es immer noch sinnvoll zu erstellen,/product/{id}/sale
während es keine tatsächliche Ressource darstellt?Es gibt keinen Grund, warum Sie das auch nicht können. oder beides.
In einem Point-of-Sale-Kontext ist die Verfolgung einzelner Transaktionen sehr sinnvoll. Dort macht Roberts Lösung sehr viel Sinn.
In einem Lager- / Lagerkontext verfolgen Sie Transaktionen nicht unbedingt, sondern "Inventar". einen Endpunkt haben, über den der Kunde seine Lagerbestände melden kann
macht sehr viel Sinn.
Die Lagerbestände ändern sich aus anderen Gründen als "Verkäufe". nur etwas zu beachten.
Theoretisch sollte der Lagerbestand aus den Änderungen berechenbar sein; In einigen Bereichen ist dies jedoch genau die Annahme, die Sie überprüfen möchten . Sie möchten in der Lage sein, den Lagerbestand auf zwei verschiedene Arten zu berechnen und auf Unstimmigkeiten zu prüfen (auch als "Schrumpfung" bezeichnet).
Daher denke ich nicht, dass die Semantik eindeutig ist, basierend auf dem von Ihnen angegebenen Kontext.
Wie für den HTTP-Teil;
PUT [target-uri]
Semantisch sinnvoll, wenn Sie eine Darstellung eines Dokuments durch eine andere ersetzen. Es ist einUPSERT
- der zweite PUT zu einer Ressource fordert zum Überschreiben der vorhandenen Darstellung auf.sagt, dass die Menge der verkauften Einheiten
3
nicht ist10
.So
10
sieht es ausDas ist eine andere Art der Rechtschreibung
10
.Dies ist auch für HTTP akzeptabel. In einem unzuverlässigen Netzwerk ist dies jedoch keine gute Wahl, da Nachrichten manchmal doppelt vorhanden sind.
Ist das
13
? oder10
?Das ist eindeutig
10
Das ist eindeutig
10
Das ist eindeutig
13
Das ist eindeutig
13
10
13
(Um fair zu sein, HTTP unterstützt bedingte Anforderungen . Sie können einige der Metadaten aus Ihrem domänenspezifischen Protokoll in die domänenunabhängigen Header heben, um einige Unklarheiten zu beseitigen - wenn Sie den Client zum Mitspielen überreden können.)
Natürlich gibt es Kompromisse - HTML bietet keine native PUT-Unterstützung. Wenn Sie beabsichtigen, dass die Clients Ihrer API Browser sind, benötigen Sie entweder ein auf POST basierendes Protokoll oder Code-on-Demand-Erweiterungen, um die Formularübermittlung von einem POST in einen PUT zu konvertieren.
quelle
Dies scheint ein wirklich schlechtes Design zu sein, egal wie Sie es schneiden. Ich würde niemals einem Dritten vertrauen, der mir mein aktuelles Inventar mitteilt, es sei denn, ich habe ihn mit der Verwaltung meines Lagers beauftragt.
Darüber hinaus ist der funktionsorientierte Ansatz überhaupt nicht REST-konform und führt bei Ihren Verbrauchern zu Bestürzung.
Schließlich kann ich mir kein Szenario vorstellen, in dem das einzige, was Sie an einem Verkauf interessiert, das resultierende Inventar ist, das Sie nach dessen Abschluss übrig haben.
Es ist viel besser, wenn der Dritte eine Verkaufs- oder Rechnungsressource an Sie sendet (mit Informationen wie Produkt, Menge, Datum, Versandart, Kundeninformationen usw.). Auf diese Weise können Sie tatsächlich analysieren und verfolgen, was Sie verkaufen, an wen, wann usw., damit Sie Ihr Unternehmen tatsächlich verwalten können.
Selbst wenn Ihr Dritter die vollständige Auftragserfüllung durchführt, möchten Sie den Umsatz nicht zuletzt für Zwecke der Buchhaltung und der Kundendemografie verfolgen.
quelle
Diese Art von Design hat das Hauptproblem, dass Sie schmutzigen Lese- / Schreibvorgängen ausgesetzt sind, wenn Sie jemals mehr als einen Client-Thread für Ihre API ausführen möchten. Das heißt, zwischen dem Zeitpunkt, zu dem der Kunde die aktuelle Menge abruft und den neuen Wert berechnet, kann ein anderer Kunde denselben vorherigen Wert abrufen und eine andere Antwort berechnen. Die Menge, die Sie am Ende erhalten, ist diejenige, die zuletzt aktualisiert wurde, aber keine ist korrekt. Angenommen, Ihre aktuelle Menge ist 10. Kunde A möchte 5 Artikel verkaufen und zieht die aktuelle Menge. Gleichzeitig möchte Kunde B 6 Artikel verkaufen und zieht die aktuelle Menge. Beide sehen 10 Artikel auf Lager. A berechnet 5 verbleibende Elemente. B.berechnet 4 verbleibende. Beide aktualisieren. Sie zeigen jetzt 4 oder 5 verbleibende Elemente an, je nachdem, wer zuletzt aktualisiert wurde. Sie haben jedoch tatsächlich mehr Artikel verkauft, als Sie tatsächlich haben. Schlimmer ist, dass es keinen einfachen Weg gibt, durchzugehen und zu sehen, was schief gelaufen ist. Alles, was Sie haben, sind zwei falsche
PUTs
in Ihren Protokollen zu betrachten.In jedem realen Aufzeichnungssystem ist es nicht ausreichend, nur eine aktuelle Summe zu haben. Überlegen Sie, ob Sie in ein Geschäft gehen und eine Reihe von Artikeln kaufen. Sie fordern eine Quittung an und die Kassiererin gibt Ihnen nur einen Zettel mit einem einzigen Gesamtbetrag. Wie würden Sie zeigen, dass die Gesamtsumme aus dieser Quittung korrekt ist? Wie würden Sie zeigen, dass Sie einen Artikel gekauft haben, wenn Sie etwas zurückgeben möchten?
Der Ansatz Ihres Freundes ist besser, aber ich würde vorschlagen, dem Mix eine Transaktions-ID hinzuzufügen. Dies behebt die wirklichen Bedenken, die VoiceOfUnreason in Bezug auf doppelte Transaktionen erwähnt. Eine Möglichkeit besteht darin, eine
POST
Operation zum Erstellen einer neuen Transaktion bereitzustellen und diese dannPUT
zu bestätigen. Zum Zeitpunkt der Bestätigung reduzieren Sie den Gesamtbestand oder lehnen die Anfrage ab, da nicht genügend verfügbar ist.quelle
Da Verkäufe von Dritten abgewickelt werden, müssen Sie die Kontrolle über Ihren Produktbestand haben, indem Sie nicht zulassen, dass diese die Lageranzahl aktualisieren.
Für den internen Gebrauch, z. B. zur Bestandszählung, können Sie Ihren Ansatz festlegen, d
PUT /api/Product/{Id}/ --data { "StockQuantity": "{NewStockQuantity}" }
. H.Für den externen Gebrauch müssen Sie eine separate Schnittstelle erstellen, z. B.
/api/SalesOrder/
eine Liste von Produkten und Mengen, wie z.Basierend auf
SalesOrder
den von Dritten gesendeten Daten kann die Menge jedes Produkts aktualisiert und der Bestellung zugewiesen werden, oder Sie können die Bestellung ablehnen, wenn nicht genügend Produkte verfügbar sind.Die Verarbeitung und Bestandszählung erfolgt intern. Dritte benötigen lediglich eine Schnittstelle, damit sie ihre Bestellungen an das Inventar weiterleiten können. Grundsätzlich
SalesOrder
kommunizieren Vertrieb, Finanzen und Lager auf diese Weise, um einen Verkauf abzuschließen.quelle