2017-08-25 1 views
1

Ich entwerfe eine Reihe von RESTful API für ein Konzept wie "Jobs". Das Modell eines Auftrags sieht wie folgt aus:Welcher dieser beiden RESTful-API-Designs ist besser?

Job: { 
    id: 1, 
    name: "Brew coffee", 
    status: "paused" | "running" | "finished", 
    progress: 0.75 
} 

und nach RESTful Prinzipien der Client CRUDs Aufträge über HTTP-Verben auf /api/jobs. Zum Beispiel ist eine neue Stelle Initalizing

POST /api/jobs 
-------------- 
Request body: { 
    name: "Push button" 
} 
--------------- 
Response status: 200 OK 
Response body: { 
    id: 2, 
    name: "Cook dinner", 
    status: "running", 
    progress: 0 
} 

und diesen Job ist der Zugriff auf

GET /api/jobs/2 
-------------- 
Request body: {} 
--------------- 
Response status: 200 OK 
Response body: { 
    id: 2, 
    name: "Cook dinner", 
    status: "running", 
    progress: 0.5 
} 

Meine Frage ist, wie soll ich das API-Design für eine Aktion wie "Pause"? Aus der Spitze meinen Kopf Ich bin betrachten zwischen zwei Optionen:

Eine Möglichkeit es als PATCH Anfrage zu entwerfen, und erklären, direkt die Endzustand Ich möchte, wie so

PATCH /api/jobs/2 
-------------- 
Request body: { 
    status: "paused" 
} 
--------------- 
Response status: 200 OK 
Response body: { 
    id: 2, 
    name: "Cook dinner", 
    status: "paused", 
    progress: 0.65 
} 

Die andere Option ist es als POST Anfrage zu entwerfen, und erklären die Aktion ich möchte, wie so

POST /api/jobs/2 
-------------- 
Request body: { 
    action: "pause" 
} 
--------------- 
Response status: 200 OK 
Response body: { 
    // same as above 
} 

betrachten In der Zukunft könnte ich andere Operationen wie "resume", "prioritisieren", "deprioritize" usw. implementieren. Welche dieser beiden Möglichkeiten ist Ihrer Meinung nach besser? Oder gibt es eine noch bessere Praxis?

+2

Die Antwort auf die Frage, die Sie gestellt haben, ist nicht wirklich wichtig ... aber wenn die Antwort von GET/api/jobs/2 Ihnen keine Antwort gibt, dann ist es nicht REST. Es tut mir leid, Roy Fielding auf dich zu bekommen, aber wenn es dir nicht wirklich wichtig ist, ob es REST ist oder nicht, dann tu einfach, was deinen Anforderungen entspricht. –

Antwort

2

Meine Frage ist, wie sollte ich die API für eine Aktion wie "Pause" entwerfen?

Wie würden Sie eine Website entwerfen, die eine Aktion wie "Pause" unterstützt?

Sie würden wahrscheinlich mit einer Zielseite beginnen, die der Client abrufen konnte. Die zurückgegebene Antwort würde wahrscheinlich eine Darstellung des aktuellen Status des Jobs enthalten und Links mit semantischen Annotationen enthalten, die der Benutzer verstehen würde. Eine davon wäre für die "Pause" -Aktion.

Nach der Pause Link könnte ein Formular, mit einer Anzahl von Eingabefeldern, semantische Annotationen für jeden und wahrscheinlich Standardwerte für jedes Feld. Der Client würde einige oder alle Werte in den Eingabefeldern ersetzen und das Formular senden.

Das würde die Formulardaten an den von Ihnen angegebenen Endpunkt senden, und an dieser Stelle würde Ihre Implementierung den Seiteneffekt pause aufrufen und mit einer Repräsentation antworten, die das Ergebnis beschreibt.

Das ist das Modell zu folgen. Die Implementierung Ihrer REST-API ist ein Adapter, der Ihren Service als generische Website erscheinen lässt.

Die Schlüsselidee hier ist, dass der Client nicht im Voraus den zu verwendenden URI oder die zu verwendende http-Methode kennen muss, da diese Informationen in die Darstellungen der vom Server bereitgestellten Links kodiert sind. Der Client muss nur die Links erkennen und folgen.

POST ist fein; HTML-Clients verwenden es seit HTTP/1.0. PUT und PATCH sind auch fein, wenn Sie eine "Remote Authoring" -Schnittstelle bereitstellen möchten.

Sie möchten vielleicht Rest Causistry überprüfen. Stellen Sie sicher, dass Sie durch die Kommentare gehen, wo die wirkliche Diskussion von REST stattfindet. Es ist auch nützlich bewertet Fieldings Paper Tigers and Hidden Dragons ...

Ich sollte auch beachten, dass die oben noch nicht vollständig RESTful ist, zumindest, wie ich den Begriff verwenden. Alles, was ich getan habe, ist die Service-Schnittstellen beschrieben, die nicht mehr als irgendein RPC ist. Um es RESTful zu machen, müsste ich einen Hypertext hinzufügen, um den Dienst einzuführen und zu definieren, beschreiben, wie man das Mapping unter Verwendung von Formularen und/oder Link-Vorlagen durchführt und Code bereitstellt, um die Visualisierungen auf nützliche Weise zu kombinieren.

Matt Timmermans 'Kommentar hat es richtig; Wenn Sie nur eine Reihe von getrennten Endpunkten dokumentieren, die der Client selbstständig navigiert, führen Sie REST nicht aus. Und in Lösungen, in denen Sie nicht zulassen müssen, dass sich die Clients und Server unabhängig entwickeln, ist das auch fein.

REST ist für langlebige netzwerkbasierte Anwendungen gedacht, die mehrere Organisationen umfassen. Wenn Sie die Einschränkungen nicht sehen, verwenden Sie sie nicht.

verfolgen den Kommentar auf:

es scheint, dass diese Art der Navigation-basierte API Organisation ist sehr flexibel, wenn wir von einem menschlichen betrieben Client (wie Browser) sprechen, aber ich bin nicht so sicher, dass es einfach ist, einen automatischen Client zu programmieren, der Änderungen auf der Serverseite anpassen kann. "... fügen Sie einen Hypertext hinzu, um den Service einzuführen und zu definieren, beschreiben Sie, wie Sie das Mapping mithilfe von Formularen und/oder Link-Templates durchführen ..." klingt für mich zu menschlich orientiert.

Ich hatte auch Probleme damit.

Niemand behauptet, dass mit einer REST-API die Maschinenverbraucher magisch in der Lage sein werden, semantische Änderungen in der API zu verstehen. Wenn wir bestehende Clients unterstützen wollen, müssen die Änderungen, die wir auf dem Server vornehmen, rückwärtskompatibel durchgeführt werden. ABER - und das ist die Schlüsselidee - gibt es eine zusätzliche Ebene der Indirektion zwischen der Semantik und der Repräsentation.

Um ein einfaches Beispiel zu wählen, muss der Verbraucher in einer API mit Paginierung die Semantik von next page verstehen; Es muss in der Lage sein, den Client nach einem Handle für den nächsten Seitenlink zu fragen. Aber es muss nichts darüber wissen, wie diese Verknüpfung dargestellt wird, oder die Link-Mechanismen oder die URI oder etwas Ähnliches. Der generische Browser Analog weiß diese Bits, und das alles funktioniert für den Verbraucher.

Es gibt immer noch ein Protokoll, das der Verbraucher verstehen muss; aber dieses Protokoll wird in Links ausgedrückt, nicht in URI.

+0

Danke. Eine Frage bezüglich des RESTful-Designs: Es scheint, dass diese Art von navigationsbasierter API-Organisation sehr flexibel ist, wenn wir von einem menschlich betriebenen Client (wie einem Browser) sprechen, aber ich bin mir nicht sicher, ob es einfach ist, einen automatischen Client zu programmieren das kann Änderungen auf der Serverseite anpassen. "... fügen Sie einen Hypertext hinzu, um den Service einzuführen und zu definieren, beschreiben Sie, wie Sie das Mapping mithilfe von Formularen und/oder Link-Templates durchführen ..." klingt für mich zu menschlich orientiert. – trVoldemort

1

Es gibt ein paar Aspekte dieser Frage, und die Auswahl hängt davon ab, welche Dinge Sie als Priorität festlegen möchten.

Frage 1) Was ist besser aus einer REST-Perspektive?

Aus einer streng REST-Perspektive ist die PATCH mit { "status": "pause" } die richtige. REST ist Representative State Transfer. Und diese Lösung passt am strengsten dazu.

Frage 2) Sollte ich 'Aktion' orientierte Endpunkte verwenden?

Aus einer strengen REST-Perspektive wäre die Antwort nein. Allerdings gibt es in der Praxis viele gute Gründe, dies zu tun. Eine der Nebenwirkungen von strikt REST-API-Implementierungen ist, dass Ihre API aussehen kann und sich wie ein Web-zugreifbarer Datenspeicher verhält und nicht wie ein eigenständiger Dienst. Was passiert, wenn dies passiert, ist, dass mehr und mehr Ihrer Logik in die Client-Seite der API migriert ... wobei komplexe Aktionen im Client-Code als mehrere Aufrufe an verschiedene REST-Aktionen implementiert werden.

Dies ist normalerweise nicht das, was Sie wollen, und während es mit einer sorgfältig gestalteten API vermieden werden kann, ist es meistens nicht.

Frage 3) Was ist die beste Praxis?

Es gibt keinen, zumindest nicht objektiv. Verschiedene APIs mit unterschiedlichen Zwecken passen besser zu REST- oder aktionsorientierten Aufrufmechanismen. Das heißt, ich habe sehr selten eine API gefunden, die völlig RESTful war und keine aktionsorientierten Routinen hatte ... und die meisten von ihnen driftet auf diese Weise im Laufe der Zeit sowieso ...wenn aus keinem anderen Grund als den meisten APIs irgendeine Art von Suchfunktion erforderlich ist, und strenger REST hat dafür keine Vorkehrung.

Also, am Ende ist mein Rat, verwenden Sie REST, wo es funktioniert, es wird Ihre API einfacher für andere Leute zu beginnen mit ... und verwenden Sie aktionsorientierte Endpunkte, wenn die Aktion nicht in die passt REST-Konzepte gut. Es ist besser, einen einfach zu verstehenden Aktionsendpunkt zu haben als eine schwer zu fassende REST-Aktion, die magische Dinge hinter den Kulissen auslöst.

Aber das ist nur wie ... meine Meinung, Mann.

+0

Aber achten Sie darauf, PATCH mit der Anwendung/json nicht als Nutzlast der Anfrage zu verwenden. –

+0

Pflege um zu erarbeiten? – JayKuri

+0

Siehe - Verwenden Sie PATCH nur mit einem Payload-Medientyp, der Semantik für PATCH entworfen hat. Dies ist bei Anwendung/json nicht der Fall. –

Verwandte Themen