Ressourcen restaurieren / anmelden oder registrieren?

122

Ich entwarf eine Web-App und überlegte dann, wie meine API als RESTful-Webdienst gestaltet werden sollte. Derzeit sind die meisten meiner URIs generisch und gelten möglicherweise für verschiedene Web-Apps:

GET  /logout   // destroys session and redirects to /
GET  /login    // gets the webpage that has the login form
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx
GET  /user/xxx // gets and renders current user data in a profile view
POST /user/xxx // updates new information about user

Ich habe das Gefühl, dass ich hier viel falsch mache, nachdem ich mich bei SO und Google umgesehen habe.

Beginnen /logoutwir mit , vielleicht, weil ich eigentlich GETnichts habe - es ist möglicherweise angemessener, POSTeine Anfrage zu stellen /logout, die Sitzung zu zerstören und dann GETumzuleiten. Und soll der /logoutBegriff bleiben?

Was ist mit /loginund /register. Ich könnte zu ändern /register, /registrationaber das ändert nichts an der grundsätzlichen Funktionsweise meines Dienstes - wenn er tiefere Probleme hat.

Ich bemerke jetzt, dass ich niemals eine /userRessource verfügbar mache. Vielleicht könnte das irgendwie genutzt werden. Nehmen Sie zum Beispiel den Benutzer myUser:

foo.com/user/myUser

oder

foo.com/user

Der Endbenutzer benötigt diese zusätzliche Ausführlichkeit in der URI nicht. Welches ist jedoch optisch ansprechender?

Ich habe hier auf SO einige andere Fragen zu diesem REST-Geschäft bemerkt, aber ich würde mich sehr über eine Anleitung freuen, was ich hier dargelegt habe, wenn möglich.

Vielen Dank!

AKTUALISIEREN:

Ich hätte auch gerne einige Meinungen zu:

/user/1

vs.

/user/myUserName
Qcom
quelle

Antworten:

63

Eines sticht insbesondere als nicht REST-voll heraus: die Verwendung einer GET-Anfrage zum Abmelden.

(von http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods )

Einige Methoden (z. B. HEAD, GET, OPTIONS und TRACE) sind als sicher definiert. Dies bedeutet, dass sie nur zum Abrufen von Informationen vorgesehen sind und den Status des Servers nicht ändern sollten. Mit anderen Worten, sie sollten keine Nebenwirkungen haben, außer relativ harmlosen Effekten wie Protokollierung, Caching, Schaltung von Bannerwerbung oder Inkrementierung eines Webzählers. [...]

[... H] andling [von GET-Anfragen] durch den Server ist technisch in keiner Weise eingeschränkt. Daher kann unachtsames oder absichtliches Programmieren nicht triviale Änderungen auf dem Server verursachen. Dies wird nicht empfohlen, da dies Probleme für das Web-Caching, Suchmaschinen und andere automatisierte Agenten verursachen kann [...]

Beim Abmelden und Umleiten kann ein Beitrag zu Ihrem Abmelde-URI eine 303-Antwort geben, die zur Seite nach dem Abmelden umleitet.

http://en.wikipedia.org/wiki/Post/Redirect/Get

http://en.wikipedia.org/wiki/HTTP_303

Bearbeiten, um Bedenken hinsichtlich des URL-Designs auszuräumen:

"Wie gestalte ich meine Ressourcen?" ist eine wichtige Frage für mich; "Wie gestalte ich meine URLs?" ist eine Überlegung in zwei Bereichen:

URLs, die Benutzer sehen, sollten nach Möglichkeit nicht zu hässlich und aussagekräftig sein. Wenn Sie möchten, dass Cookies in Anfragen an eine Ressource gesendet werden, andere jedoch nicht, sollten Sie Ihre Pfade und Cookie-Pfade strukturieren.

Wenn Sie JRandomUsersich sein eigenes Profil ansehen möchten und die URL hübscher als foo.com/user/JRandomUseroder sein soll foo.com/user/(JRandom's numeric user id here), können Sie eine separate URL erstellen , damit ein Benutzer seine eigenen Informationen einsehen kann:

GET foo.com/profile /*examines cookies to figure out who 
                     * is logged in (SomeUser) and then 
                     * displays the same response as a
                     * GET to foo.com/users/SomeUser.
                     */

Ich würde Unwissenheit in diesem Bereich viel leichter als Weisheit behaupten, aber hier sind einige Überlegungen zum Ressourcendesign:

  1. Verbraucher: Welche Ressourcen sollen direkt in einem Browser angezeigt, über XHR geladen oder von einem anderen Client aufgerufen werden?
  2. Zugang / Identität: Hängt die Antwort von Cookies oder Verweisen ab?
ellisbben
quelle
1
Tolle Antwort, danke! Wenn ich Ihren separaten URL-Vorschlag ( GET foo.com/profile/) implementieren würde, wäre das Teil der Präsentationsschicht, wie Momo vorgeschlagen hat? Mit anderen Worten, was genau sollte diese GETAnfrage zurückgeben? Eine Webseite oder ein JSON?
Qcom
2
Ah, ich glaube ich sehe jetzt. Momos Antwort klärte die Dinge wirklich auf. So eine RESTful API mehr Plattformen zu ermöglichen , ist so konstruiert GET, POST, PUT, und DELETERessourcen. Eine Website ist nur eine weitere Plattform, die auf die API zugreift. Mit anderen Worten, das Website-URL-Design unterscheidet sich grundlegend vom RESTful-API-Design. Bitte sag mir, ob ich immer noch falsch liege, haha.
Qcom
Ja, machen Sie Ihre REST-API zu einem Satz von URLs und Ihre Website zu einem anderen Satz. Dann sollte Ihre Website-URL Ihnen das entsprechende HTML + Javascript zurückgeben, damit die Seite entsprechende XmlHttpRequests für Ihre API-URLs ausführt, um als Client zu fungieren.
Ellisbben
129

RESTful kann als Richtlinie zum Erstellen von URLs verwendet werden, und Sie können Sitzungen und Benutzerressourcen erstellen:

  • GET /session/new Ruft die Webseite mit dem Anmeldeformular ab
  • POST /session authentifiziert Anmeldeinformationen anhand der Datenbank
  • DELETE /session zerstört die Sitzung und leitet zu / um
  • GET /users/new Ruft die Webseite mit dem Registrierungsformular ab
  • POST /users Zeichnet die eingegebenen Informationen als neuen / user / xxx in der Datenbank auf
  • GET /users/xxx // ruft aktuelle Benutzerdaten in einer Profilansicht ab und rendert sie
  • POST /users/xxx // aktualisiert neue Informationen über den Benutzer

Diese können Plural oder Singular sein (ich bin mir nicht sicher, welches richtig ist). Ich habe normalerweise /usersfür eine Benutzerindexseite (wie erwartet) verwendet, um /sessionszu sehen, wer angemeldet ist (wie erwartet).

Die Verwendung des Namens in der URL anstelle einer Zahl ( /users/43vs. /users/joe) beruht normalerweise auf dem Wunsch, den Benutzern oder Suchmaschinen gegenüber freundlicher zu sein, und nicht auf technischen Anforderungen. Beides ist in Ordnung, aber ich würde empfehlen, dass Sie konsequent sind.

Ich denke, wenn Sie mit dem Registrieren / Anmelden / Abmelden gehen oder sign(in|up|out), funktioniert es nicht so gut mit der erholsamen Terminologie.

ndp
quelle
6
Genial! Mir gefällt, wie Sie diese Ressourcen benannt haben. das ist ziemlich sauber. Obwohl, wie ich gehört habe, nicht /newan GET /session/nicht RESTful angehängt wird? Ich habe gehört , dass die Verben auf die HTTP - Verben typischerweise links sind ( GET, POSTusw.).
Qcom
2
@Zach neu ist kein Verb. In diesem Fall handelt es sich um eine Unterressource der Sitzung.
Kugel
Wie bestimme ich, welche Sitzung in DELETE / Sitzung gelöscht werden soll? Curl sendet weder Cookies noch Parameter in der DELETE-Anfrage. Ich nehme an - nur um DELETE / session / sessionId zu verwenden? Eine andere Frage ist, wie und in welchem ​​Format die Sitzungs-ID in POST / Sitzung zurückgegeben wird.
Tvaroh
9
Ruhig ist in der Tat eine Möglichkeit, sich unglücklich zu machen und Zeit mit Dingen zu verschwenden, die überhaupt keine Rolle spielen.
Jian Chen
6
Persönlich mag ich die Idee nicht, die Routen zu haben, die das Formular zurückgeben (/ new). Dies unterbricht die Trennung zwischen Ansicht und Geschäftslogik. Das heißt, ohne die / neuen Routen sehen die vorgeschlagenen perfekt aus.
Scadge
60

Sitzungen sind nicht RESTful

  • Ja, ich weiß. Es wird normalerweise mit OAuth durchgeführt, aber Sitzungen sind wirklich nicht RESTful. Sie sollten in erster Linie keine / login / logout-Ressource haben, da Sie keine Sitzungen haben sollten.

  • Wenn Sie es tun wollen, machen Sie es RESTful. Ressourcen sind Substantive und / login und / logout sind keine Substantive. Ich würde mit / Sitzung gehen. Dies macht das Erstellen und Löschen zu einer natürlicheren Aktion.

  • POST vs. GET für Sitzungen ist einfach. Wenn Sie Benutzer / Passwort als Variablen senden, würde ich POST verwenden, da ich nicht möchte, dass das Passwort als Teil des URI gesendet wird. Es wird in Protokollen angezeigt und möglicherweise über dem Draht freigelegt. Sie laufen auch Gefahr, dass Software aufgrund der Einschränkungen von GET args ausfällt.

  • Ich verwende im Allgemeinen Basic Auth oder kein Auth mit REST-Diensten.

Benutzer erstellen

  • Es ist eine Ressource, daher sollten Sie sich nicht registrieren.

    • POST / Benutzer - Erstellt einen Benutzer, wenn der Anforderer die ID nicht angeben kann
    • PUT / user / xxx - Erstellt oder aktualisiert einen Benutzer, sofern Sie die ID zuvor kennen
    • GET / user - listet x Benutzer-IDs auf
    • GET / user / xxx - Ruft die Details des Benutzers mit der ID xxx ab
    • DELETE / user / xxx - Löscht den Benutzer mit der ID xxx
  • Welche Art von ID zu verwenden ist, ist eine schwierige Frage. Sie müssen darüber nachdenken, die Eindeutigkeit durchzusetzen und alte IDs wiederzuverwenden, die gelöscht wurden. Beispielsweise möchten Sie diese IDs nicht als Fremdschlüssel in einem Backend verwenden, wenn IDs recycelt werden sollen (sofern dies überhaupt möglich ist). Sie können jedoch nach externen / internen ID-Konvertierungen suchen, um die Backend-Anforderungen zu verringern.

Dietbuddha
quelle
6
Dies ist die beste Antwort. / login und / logout sind keine Ressourcen und brechen die Idee von REST.
wle8300
5
Authentifizierung! = Sitzung
dietbuddha
1
Ja, in Fieldings These heißt es in Abschnitt 5.1.3, dass "der Sitzungsstatus [...] vollständig beim Kunden liegt". Ferner würde ich argumentieren, dass die Authentifizierung im Idealfall auch auf der Serverseite zustandslos sein sollte, dh anstatt aktive "Authentifizierungstickets" in einer Datenbank zu speichern, sollte der Server in der Lage sein, einen Authentifizierungsnachweis nur auf der Grundlage des Berechtigungsnachweises selbst zu überprüfen. B. durch Verwendung eines in sich geschlossenen kryptografischen Tokens in Verbindung mit einem privaten Schlüssel. Anstelle einer / session-Ressource könnte man also eine / authentication-Ressource einführen, aber es löst das Problem auch nicht wirklich ...
raner
Tatsächlich sind / login und / logout Substantive. Ich nehme an, Sie denken an / log_in und / log_out.
TiggerToo
21

Ich werde einfach aus meiner Erfahrung mit der Integration verschiedener REST-Webdienste für meine Kunden sprechen, sei es für mobile Apps oder für die Server-zu-Server-Kommunikation sowie für die Erstellung der REST-API für andere. Hier sind einige Beobachtungen, die ich aus der REST-API anderer Leute sowie aus denen, die wir selbst erstellt haben, gesammelt habe:

  • Wenn wir API sagen, bezieht es sich normalerweise auf einen Satz von Programmierschnittstellen und nicht auf die Präsentationsschicht. REST ist auch datenzentriert und nicht präsentationsgesteuert. Die meisten REST-Daten geben jedoch Daten in Form von JSON oder XML zurück und geben selten eine bestimmte Präsentationsschicht zurück. Diese Eigenschaft (der Rückgabe von Daten und nicht der direkten Webseite) gab REST die Möglichkeit, eine Mehrkanallieferung durchzuführen. Dies bedeutet, dass derselbe Webservice in HTML, iOS, Android gerendert oder sogar als Server-zu-Server-Kombination verwendet werden kann.
  • Es ist sehr selten, HTML und REST als URL zu kombinieren. Standardmäßig sind REST Gedanken als Dienste und haben keine Präsentationsschicht. Es ist die Aufgabe derjenigen, die die Webservices nutzen, die Daten der von ihnen aufgerufenen Dienste nach ihren Wünschen zu rendern. Bis zu diesem Punkt entspricht Ihre unten stehende URL nicht den meisten REST-basierten Designs, auf die ich bisher gestoßen bin (noch den Standards wie denen, die von Facebook oder Twitter stammen).
GET / register // ruft die Webseite mit dem Registrierungsformular ab
  • Ausgehend vom vorherigen Punkt ist es auch ungewöhnlich (und ich bin nicht darauf gestoßen), dass ein REST-basierter Dienst eine Umleitung wie die unten vorgeschlagenen durchführt:
GET / logout // zerstört die Sitzung und leitet zu / um
POST / login // authentifiziert Anmeldeinformationen für die Datenbank und leitet entweder mit einer neuen Sitzung nach Hause oder zurück zu / login
 

Da REST als Services konzipiert sind, geben Funktionen wie Anmelden und Abmelden normalerweise Erfolgs- / Fehlerergebnisse zurück (normalerweise im JSON- oder XML-Datenformat), die der Verbraucher dann interpretieren würde. Eine solche Interpretation könnte die Weiterleitung auf eine geeignete Webseite umfassen, wie Sie erwähnt haben

  • In REST gibt die URL die durchgeführten Aktionen an. Aus diesem Grund sollten wir so viele Unklarheiten wie möglich beseitigen. Während es in Ihrem Fall legitim ist, sowohl GET als auch POST mit demselben Pfad (z. B. / register) zu haben, die unterschiedliche Aktionen ausführen, führt ein solches Design zu Mehrdeutigkeiten bei den bereitgestellten Diensten und kann den Verbraucher Ihrer Dienste verwirren. Beispielsweise sind die URLs wie die unten eingeführte nicht ideal für REST-basierte Services
GET / register // ruft die Webseite mit dem Registrierungsformular ab
POST / register // zeichnet die eingegebenen Informationen als neuer / user / xxx in der Datenbank auf

Das sind einige Punkte von dem, was ich behandelt habe. Ich hoffe, es könnte Ihnen einige Einblicke geben.

Was nun die Implementierung Ihres REST betrifft, so sind dies die typischen Implementierungen, auf die ich gestoßen bin:

  • GET / Logout  
    

    Führen Sie die Abmeldung im Backend aus und geben Sie JSON zurück, um den Erfolg / Misserfolg des Vorgangs anzuzeigen

  • POST / Login
    

    Senden Sie Ihre Anmeldeinformationen an das Backend. Erfolg / Misserfolg zurückgeben. Bei Erfolg werden normalerweise auch das Sitzungstoken sowie die Profilinformationen zurückgegeben.

  • POST / registrieren
    

    Senden Sie die Registrierung an das Backend. Erfolg / Misserfolg zurückgeben. Wenn dies erfolgreich ist, wird dies normalerweise genauso behandelt wie eine erfolgreiche Anmeldung, oder Sie können die Registrierung als eigenständigen Dienst vornehmen

  • GET / user / xxx
    

    Benutzerprofil abrufen und JSON-Datenformat für das Benutzerprofil zurückgeben

  • POST / user / xxx 
    // umbenannt in 
    POST / updateUser / xxx
    

    Veröffentlichen Sie aktualisierte Profilinformationen im JSON-Format und aktualisieren Sie die Informationen im Backend. Erfolg / Misserfolg an den Anrufer zurückgeben

Momo
quelle
3
Ja, wenn Sie Ihre REST-API in eine HTML-basierte App (über Javascript und AJAX) integrieren, profitieren Sie enorm, da JSON von Javascript nativ analysiert wird. In Android / Java ist JSON im Vergleich zu XML einfacher und einfacher zu analysieren.
Momo
15
GET / Logout ist gefährlich. GET sollte idempotent sein. Auch Browser rufen gerne <a> hrefs vorab ab, wodurch Sie abgemeldet werden!
Kugel
4

Ich glaube, dies ist ein RESTful-Ansatz zur Authentifizierung. Für LogIn verwenden Sie HttpPut. Diese HTTP-Methode kann zur Erstellung verwendet werden, wenn der Schlüssel bereitgestellt wird und wiederholte Aufrufe idempotent sind. Für LogOff geben Sie denselben Pfad unter der HttpDeleteMethode an. Keine Verben verwendet. Richtige Sammlungspluralisierung. Die HTTP-Methoden unterstützen den Zweck.

[HttpPut]
[Route("sessions/current")]
public IActionResult LogIn(LogInModel model) { ... }

[HttpDelete]
[Route("sessions/current")]
public IActionResult LogOff() { ... }

Falls gewünscht, können Sie den aktiven Strom ersetzen.

Chad Kuehn
quelle
1

Ich würde empfehlen, eine Benutzerkonto-URL zu verwenden, die Twitter ähnelt, wobei die URL des Benutzerkontos so aussieht, als foo.com/myUserNamekönnten Sie mit der URL https://twitter.com/joelbyler zu meinem Twitter-Konto gelangen

Ich bin nicht einverstanden, dass für die Abmeldung ein POST erforderlich ist. Wenn Sie als Teil Ihrer API eine Sitzung verwalten möchten, kann eine Sitzungs-ID in Form einer UUID verwendet werden, um den Überblick über einen Benutzer zu behalten und zu bestätigen, dass die ausgeführte Aktion autorisiert ist. Dann kann sogar ein GET die Sitzungs-ID an die Ressource weitergeben.

Kurz gesagt, ich würde empfehlen, dass Sie es einfach halten, URLs sollten kurz und einprägsam sein.

joelbyler
quelle
Die Frage betrifft API-Ressourcen. Ihre Antwort bezieht sich auf die Präsentationsschicht.
Henno