Verschiedene Erholsamen Repräsentationen der gleichen Ressource
Meine Anwendung ist eine Ressource, die sich an /foo
. In der Regel ist es vertreten durch einen HTTP-response-payload wie diese:
{"a": "some text", "b": "some text", "c": "some text", "d": "some text"}
Den client nicht immer müssen alle vier Mitglieder dieses Objekt. Was ist die Erholsam semantische Möglichkeit für den client dem server mitteilen, was er braucht in der Darstellung? z.B. wenn es will:
{"a": "some text", "b": "some text", "d": "some text"}
Wie sollte es GET
es? Einige Möglichkeiten (ich bin auf der Suche nach einer Berichtigung, falls ich missverstanden, REST):
GET /foo?sections=a,b,d
.- Den query-string (genannt Abfrage string, nachdem alle) zu bedeuten scheint "Ressourcen finden, welche dieser Bedingung und erzählen Sie mir davon", nicht "repräsentieren diese Ressource, um mich nach dieser Anpassung".
GET /foo/a+b+d
Meine Lieblings - wenn REST-Semantik nicht gerade dieses Problem, wegen seiner Einfachheit.- Bricht URI Deckkraft, die Verletzung von HATEOAS.
- Scheint zu brechen, die die Unterscheidung zwischen Ressource (der einzige Sinn, der ein URI ist, zu identifizieren eine Ressource) und Darstellung. Aber das ist fraglich, denn es ist konsistent mit
/widgets
repräsentieren eine vorzeigbare Liste der/widget/<id>
Ressourcen, die ich hatte noch nie ein problem mit.
- Lösen meine Zwänge, reagieren
GET /foo/a
usw, und der client eine Anfrage pro Komponente/foo
es will.- Multipliziert overhead, das kann zu einem Alptraum werden, wenn
/foo
hat Hunderte von Komponenten ein-und der Kunde muss 100. - Wenn ich will eine HTML-Darstellung der
/foo
muss ich Ajax verwenden, was problematisch ist, wenn ich nur eine einzige HTML-Seite, die gecrawlt werden können, erbracht durch minimalistische Browser, etc. - Zu pflegen, HATEOAS, es erfordert auch links zu den "sub-Ressourcen" zu existieren, die in anderen Darstellungen, wahrscheinlich in
/foo
:{"a": {"url": "/foo/a", "content": "some text"}, ...}
- Multipliziert overhead, das kann zu einem Alptraum werden, wenn
GET /foo
,Content-Type: application/json
und{"sections": ["a","b","d"]}
im request-body.- Unbookmarkable und uncacheable.
- HTTP nicht definiert ist Körper Semantik für
GET
. Es ist legal HTTP, aber wie kann ich garantieren, einige Benutzer den proxy nicht Streifen den Körper von einerGET
Anfrage? - Meine REST-client wird nicht lassen Sie mich einen Körper auf einer
GET
Anfrage, so dass ich nicht verwenden können, dass für die Prüfung.
- Einen benutzerdefinierten HTTP-header:
Sections-Needed: a,b,d
- Würde ich eher vermeiden, benutzerdefinierte Header, wenn möglich.
- Unbookmarkable und uncacheable.
POST /foo/requests
,Content-Type: application/json
und{"sections": ["a","b","d"]}
im request-body. Erhalten201
mitLocation: /foo/requests/1
. DannGET /foo/requests/1
erhalten die gewünschte Darstellung/foo
- Klobig; erfordert hin-und-her und einigen seltsam aussehenden code.
- Unbookmarkable und uncacheable, da
/foo/requests/1
ist nur ein alias, das würde nur einmal verwendet und nur solange aufbewahrt, wie es gefordert wird.
- Ich würde mich für den query-string-Ansatz. Der query-string ist ein Teil der URL und das ist, wo die scoping information gehen sollte. Es ist auch, wie Facebook es tut. Hier ist ein netter screencast Erörterung dieser Angelegenheit: Lehren einen Hund zur RUHE. Es zeigt einige andere Formate, die Sie möglicherweise in Betracht zu.
- Könnten Sie die 2-Repräsentationen der gleichen Ressource und mit content-negotiation.. 100% erholsam. vnd.jordan.foo mit allen, vnd.jordan.foo.minimal würde nicht zählen d. wenn das nur ein Beispiel und nicht ein allgemeiner Fall gehst du mit _fields, dass auch 100% erholsamen und individuell. Ihre Lieblings-a+b+d ist WIRKLICH schlecht, so vermeiden Sie es 🙂 foo/Anfragen/1 ist auch schlecht.. nicht, weil es nicht performant oder logisch ist, sondern weil es so Brauch ist. REST wird hauptsächlich über die Verwendung von best practices und Vermeidung von überraschungen 🙂 NEIN, um benutzerdefinierte Header. KEINE zu BEKOMMEN, mit dem Körper.. Sorry für den strukturlosen Kommentar 🙂
- _fields ist, was Sie nennen "Abschnitte", du hast Recht es sieht aus wie ein filter, aber _fields wird Häufig verwendet und akzeptiert, nicht Wundern würde jeder Entwickler.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde vorschlagen, die querystring-Lösung (Ihre erste). Ihre Argumente gegen die anderen alternativen gute Argumente (und diejenigen, die ich ' ve stoßen in der Praxis, wenn Sie versuchen, dasselbe problem zu lösen). Insbesondere das "lösen Sie die Einschränkungen/Antworten
foo/a
" Lösung kann arbeiten in begrenzten Fällen, jedoch führt eine Menge von Komplexität in eine API für die Implementierung und den Konsum und nicht in meiner Erfahrung hat sich gelohnt.Werde ich schwach gegen Ihre "zu bedeuten scheint" - argument mit einem Beispiel: betrachten Sie die Ressource, die eine große Liste der Objekte (
GET /Customers
). Es ist durchaus sinnvoll, um die Seite dieser Objekte, und es ist alltäglich verwenden Sie die querystring zu tun:GET /Customers?offset=100&take=50
als ein Beispiel. In diesem Fall wird der querystring nicht filtern, die auf jede Eigenschaft des denkmalgeschützten Objekt, die Parameter für eine sub-Ansicht auf das Objekt.Mehr konkret, ich würde sagen, dass können Sie Konsistenz und HATEOAS durch diese Kriterien für die Verwendung der querystring:
Jedoch, was zu zurück für diese Uris können manchmal eine komplexere Fragen:
/foo
ist eine Einheit, sondernfoo/a
ist ein string); die alternative ist die Rückgabe einer teilweise gefüllt wird, die Einheit/foo
keinea
eine404
status ist irreführend (/foo
hat existieren!), aber eine leere Antwort kann ebenso verwirrenda
ist obligatorisch, aber die client-Anfragen nurb
, sind Sie gezwungen, wieder entweder eine junk-Wert füra
oder ein ungültiges Objekt)In der Vergangenheit habe ich versucht zu beheben, durch die Definition von spezifischen namens "views" der benötigten Entitäten und ermöglicht eine querystring wie
?view=summary
oder?view=totalsOnly
- Begrenzung der Anzahl der Permutationen. Dies ermöglicht auch die definition einer Untermenge der Entitäten, die "macht Sinn" für den Verbraucher der service und dokumentiert werden können.Letztlich, ich denke, dass dies eine Frage der Konsistenz mehr als alles andere: Sie treffen HATEOAS Führung mit querystring relativ leicht, aber die Entscheidungen, die Sie treffen müssen konsistent sein, Ihre API-und, ich würde sagen, gut dokumentiert.
Habe ich Folgendes beschlossen:
Unterstützen einige Elementkombinationen: ich werde kommen mit einem Namen für jede Kombination. wenn z.B. ein Artikel hat die Mitglieder für den Autor, das Datum und die Körper
/article/some-slug
zurückkehren wird, alle von ihm und/article/some-slug/meta
wird nur wieder der Autor und das Datum.Der Unterstützung von vielen Kombinationen: ich werde einzelmitglied Namen durch Bindestriche:
/foo/a-b-c
.So oder so, werde ich wieder ein
404
wenn die Kombination nicht unterstützt wird.Strukturelle Einschränkung
REST
Identifizieren von Ressourcen
Aus der definition der REST:
Darstellung wird ein HTTP-body, und eine Kennung wird eine URL.
Dies ist von entscheidender Bedeutung. Ein Bezeichner ist nur ein Wert im Zusammenhang mit anderen Bezeichnern und Darstellungen. Das ist, unterscheidet sich von der Kennung→Darstellung zuordnen. Kann der server anzeigen, was Kennung er will eine Zusicherung, vorausgesetzt, beide sind verbunden durch die gleiche Ressource.
Es ist bis auf die Entwickler zu kommen mit Ressource-Definitionen, die einigermaßen beschreiben, das Geschäft durch das denken von Kategorien wie "Benutzer" und "Beiträge".
HATEOAS
Wenn ich wirklich über perfekte HATEOAS, ich könnte einen hyperlink irgendwo in der
/foo
Darstellung zu/foo/members
, und diese Darstellung würde nur enthalten einen hyperlink auf jede unterstützte Kombination von Elementen.HTTP
Aus der definition URL:
So
/foo?sections=a,b,d
und/foo?sections=b
sind unterschiedliche Bezeichner. Aber Sie können verbunden innerhalb der gleichen Ressource, während zugeordnet zu unterschiedlichen Darstellungen.HTTP ist
404
code bedeutet, dass der server konnte nicht finden, alles, was zum anzeigen der URL, nicht, dass die URL nicht im Zusammenhang mit einer Ressource.Funktionalität
Kein browser oder cache wird immer Mühe haben mit Schrägstriche oder Bindestriche.
Eigentlich kommt es auf die Funktionalität der Ressource.
Wenn zum Beispiel die Ressource stellt eine Entität:
/customers/5
Hier die '5' stellt eine id des Kunden
Antwort:
Also, wenn wir ihn genau betrachten, jedes json-Eigenschaft stellt tatsächlich eine Feld des Datensatzes für Kunden Ressource-Instanz.
Nehmen wir an, der Verbraucher möchte partielle Antwort bedeutet, Teil der Felder. Wir betrachten es als den der Verbraucher wünscht, die Möglichkeit haben, wählen Sie die verschiedenen Felder über die Anfrage, die für ihn interessant sind, aber nicht mehr (um zu sparen, den Verkehr oder die Leistung, wenn ein Teil der Felder schwer zu berechnen sind).
Ich denke, in dieser situation, die lesbar ist und die richtige API wäre (zum Beispiel, bekommen nur Namen und Nachname)
Antwort:
HTTP/1.1
fields=id,name
oderfields=name,id
), obwohl die Reaktion ist die gleiche, die Antworten werden separat zwischengespeichert.HATEOAS
Wenn a,b,c sind Eigenschaft einer Ressource wie admin für die role-Eigenschaft der richtige Weg ist, um zu verwenden ist der erste Weg, den du vorgeschlagen hast
GET /foo?sections=a,b,d
denn in diesem Fall würden Sie einen filter anwenden, um diefoo
Sammlung. Ansonsten, wenn a,b und c sind eine singole Ressourcefoo
Kollektion, die die Art und Weise, die Folgen würde, zu tun, eine Reihe vonGET
Anfragen/foo/a /foo/b /foo/c
. Dieser Ansatz, wie Sie sagte, hat eine hohe Zuladung für die Anfrage, aber es ist der richtige Weg zu verfolgen den Ansatz, Erholsamen. Würde ich nicht verwenden, der zweite Vorschlag von Ihnen, weil plus char in einer url eine Besondere Bedeutung.Einem anderen Vorschlag ist der Verzicht auf die Verwendung von GET und POST, und erstellen Sie eine Aktion für die
foo
Sammlung etwa so:/foo/filter
oder/foo/selection
oder alle Verben, die darstellen, eine Aktion für die Sammlung. Auf diese Weise, mit einem post-request-body, können Sie ein json-Liste die Ressource, die Sie würde./posts
ist eine Sammlung, weil/posts
stellt alle Ressourcen vom Typ 'post', so dass eine Abfrage würde das Spektrum der Beiträge, die es repräsentiert (siehe meine Antwort wie definiere ich 'Ressource') in der Erwägung, dass/foo
nur noch repräsentiert eine Ressource. So tun es diese Möglichkeit geben würde, die URI-Abfrage eine doppelte Bedeutung. (Eh, der REST kümmert sich nicht um die Abfrage -- nur es kümmert sich um die Kennungen zuordnen, um die Darstellungen.)+
-- ich kann nicht scheinen zu finden, eine verlässliche Antwort, ob+
vorbehalten ist, außerhalb oder nur innerhalb der Abfrage, aber ich möchte lieber sicher sein als traurig.könnte man eine zweite vendor-media-Typ in der Anfrage-header application/vnd.com.MeineFirma.Ressource.rep2, Sie können nicht fügen Sie dies jedoch, query-Parameter werden nicht zwischengespeichert (/foo?Abschnitte=a,b,c) könnten Sie werfen Sie einen Blick auf die matrix-Parameter jedoch in Bezug auf diese Frage sollten Sie zwischengespeichert werden URL-matrix-Parameter vs. Anfrage-Parameter