Wie entwerfe ich eine REST-API für Nicht-CRUD-Operationen?

11

Ich versuche, eine Reihe von SOAP-basierten Diensten in eine RESTful-API zu konvertieren.

Ich begann mit der Identifizierung von Ressourcen durch Analyse der Operationsnamen und erhielt die Ressource Subscription.

Wenn ich den Status des Abonnements aktualisieren muss, kann ich nicht einfach eine POSTAnfrage an den Server senden , da ich keinen direkten Zugriff auf die Ressourcen habe, sondern einige Operationen im RPC-Stil aufrufen muss, um deren Eigenschaften zu aktualisieren. Außerdem ist nur und nur dann ein zusätzlicher Anruf bei einem externen Dienst erforderlich, wenn ich den Status des Abonnements auf "aktiv" ändere.

Was ist in diesen Fällen die beste Vorgehensweise für den Umgang mit zugrunde liegenden Vorgängen?

Die Lösung, die ich gefunden habe, besteht darin, Abfrageparameter zu verwenden. Wenn ich den Aktivierungsdienst aufrufen muss, kann ich Folgendes verwenden:

POST /subscriptions/{subscriptionid}/?activate=true

Gibt es eine bewährte Methode für diese Art der Konvertierung, da ich meine Abonnementobjektfelder nicht direkt aktualisieren kann?

Update 1:

Ich kann in den Text meiner POST-Anfrage einige Werte einfügen, zum Beispiel "state": "active"

und überprüfen Sie in meinem Dienst die ordnungsgemäßen Vorgänge, die ausgelöst werden sollen.

Vektor88
quelle
Die Zuordnung von Befehlen zu HTTP-Verben durch REST schlägt bei komplexen Operationen fehl. Sie sind besser dran, wenn Sie nur einen Anruf im RPC-Stil tätigen. POST enableSubscription / {id} Niemand wird davon verwirrt sein
Ewan
@Ewan Ich bin mir nicht sicher, ob dies mit dem RESTful-Modell übereinstimmt, aber ich habe eine andere Lösung gefunden: In meinem Code kann ich die richtige Operation im RPC-Stil entsprechend der eingegebenen Nutzlast aufrufen (ich kann state = active im Body von übergeben Meine Post-Anfrage, der Code wird den Aktivierungscode aufrufen)
Vektor88
1
Eine Aktualisierung einer vorhandenen Ressource wie dieser sollte ein PATCH sein, und der Hauptteil der Abfrage ist dann ein Teilmodell dessen, was Sie ändern. Ein POST soll eine Anforderung sein, die eine Ressource erstellt. Diese Unterscheidung ist nicht nur für den Benutzer klarer, sondern erleichtert es Ihrem Code auch, zu erkennen, wann dieser Vorgang ausgeführt wird, anstatt einen Ressourcenbeitrag zu verfassen.
Herr Cochese
1
@ Vektor88 Normalerweise, aber das sind idempotente Operationen, bei denen Sie die gesamte Darstellung des Ressourcenstatus übergeben müssen. Dieser Anwendungsfall scheint eher ein teilweises Update zu sein, das sehr gut zu einem PATCH passt.
Herr Cochese
1
@ MrCochese POST ist nicht idempotent.
JimmyJames

Antworten:

8

Sie müssen diesen Vortrag von Jim Webber sehen.

Wenn ich den Status des Abonnements aktualisieren muss, kann ich nicht einfach eine POST-Anforderung an den Server senden, da ich keinen direkten Zugriff auf die Ressourcen habe, sondern einige Operationen im RPC-Stil aufrufen muss, um deren Eigenschaften zu aktualisieren. Außerdem ist nur und nur dann ein zusätzlicher Anruf bei einem externen Dienst erforderlich, wenn ich den Status des Abonnements auf "aktiv" ändere.

Denken Sie "Messaging"; Senden Sie eine Nachricht an Ihre Domain, in der beschrieben wird, was geschehen soll. Der Nebeneffekt der Nachricht besteht darin, dass Ihr Domänenmodell tatsächlich seinen Status ändert. Die "Ressource" ist die Nachrichtenwarteschlange.

POST /subscriptions/{subscriptionid}/?activate=true

Die Schreibweise des Ressourcennamens spielt für die Maschinen keine Rolle. Aber die Leute neigen dazu, pingelig zu werden, wenn die von Ihnen verwendeten Bezeichner von der Konvention abweichen, dass Ressourcen "Substantive" sind.

Außerdem handelt es sich um eine Ressource, die untergeordnet ist. Daher fordert die /subscriptions/{subscriptionid}Konvention (siehe RFC 3986 ), diese Beziehung mit einem Pfadsegment auszudrücken, anstatt den Abfrageteil zu verwenden.

Diese Schreibweisen könnten also vernünftig sein

POST /subscriptions/{subscriptionid}/messages
POST /subscriptions/{subscriptionid}/activations
VoiceOfUnreason
quelle
1
Jim Webbers Vortrag ist verfügbar unter youtube.com/watch?v=aQVSzMV8DWc
user674669
0

Wenn es ein boolesches Flag zum Aktivieren / Deaktivieren von Inhalten ist, würde ich sagen, dass standardmäßig JSON verwendet wird:

POST /subscriptions/{subscriptionid}/
{
    format: 0,
    subscription: 
    {
        active: false
    }
}

Dies kann leicht erweitert werden, wenn Sie mehr Eigenschaften unterstützen möchten. Ein anderer Ansatz besteht darin, ihm einen eigenen Endpunkt zu geben:

POST /subscriptions/{subscriptionid}/active/
DELETE /subscriptions/{subscriptionid}/active/

Persönlich würde ich dies nur verwenden, wenn der activeStatus dieses Ereignisses Eigenschaften benötigt / hat, die Sie dann in JSON übergeben / erhalten können, wie eine Benutzer-ID oder eine Einstellung.

Wenn es sich nicht um einen booleschen Wert handelt, sondern nur um eine Aktion, die Sie auslösen müssen, für die Sie jedoch keine Statusrückmeldung benötigen / haben (mit Ausnahme eines sofortigen OK von 200), würde ich einen Endpunkt wie diesen verwenden, um ihn ähnlich wie einen RPC auszulösen:

POST /subscriptions/{subscriptionid}/activate/

Lesen Sie im Zweifelsfall Folgendes: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful (siehe "Was ist mit Aktionen, die nicht in die Welt der CRUD-Operationen passen? ")

Barry Staes
quelle
0

REST ist nicht funktionsfähig. Activateist ein Verb und kann kein Zustand sein, Activeist ein Zustand.

Da RESTful nicht funktionsfähig ist, können Sie einem RESTful-Dienst nicht mitteilen, was zu tun ist, aber Sie können Arbeit für die Warteschlange eines Dienstes hinzufügen.

Sieh dir das an:

PUT /subscriptionQueue
subscriptionId={subscriptionId}
active=true

Diese Anfrage ist RESTful und unterstützt alle Vorteile von RESTful (wie Leistung, Säure ...)

Peter Rader
quelle