Ich halte es bei meinen APIs im wesentlichen so wie es Restful vorgibt. Pflichtparameter wie Ressourcen-Ids werden im Pfad abgebildet (/users/123), Listen mit Filteroptionen per Queryparameter (/users?q=abc&id=123...). Wenn Ressourcen im Backend mit den Pflichtparametern nicht gefunden werden wird ein 404 zurückgegeben. Bei Listen kann auch eine leere Liste mit 200 oder Empty mit 204 zurückkommen. Ich bevorzuge aber die leere Liste weil diese Listen meistens in Tabellen oder Grids dargestellt werden und man im Consumer keine große Sonderlogik braucht. 400 als Response wenn Eingabeobjekte nicht korrekt sind (Properties fehlen, falsches Format,...). 401 wenn der User nicht authentifiziert ist. 403 wenn der User nicht autorisiert ist die Operation durchzuführen. Alles mit Statuscode >=500 hat einen Fehler im Backend produziert und der Request hat nicht korrekt funktioniert. Diese Statuscodes nicht auch in Verbindung mit fachlichen Zusammenhängen zu verwenden macht aus meiner Sicht keinen Sinn und eine harte Grenze zwischen technisch und fachlich ist schwer zu ziehen. In einer hexagonalen Architektur sind die DTOs und das Interface passend zum Protokoll des entsprechenden Controllers (in dem Fall HTTP/REST). Daher kann man hier auch alle zur Verfügung stehenden Mittel nutzen. In HTTP kann ich Cookies und Header für zusätzliche Parameter wie SessionIds nutzen, für Websocket muss das DTO ggf. ein Errorobjekt enthalten, beim nächsten Protokoll gibt es einen zusätzlichen Errorkanal usw. Gerade bei REST und im Frontend sind Libraries wie Axios darauf ausgelegt, dass die Statuscodes >=400 kommen um eine Fehlerbehandlung (try/catch) zu starten. Das alles selbst neu zu erfinden, zu programmieren und auf irgendwelche Subobjekte zu prüfen, verwirrt und ist schwer zu warten, besonders bei größeren Teams.
2 роки тому+7
Wo machst Du denn den Cut bei "technisch"? Wenn ich über einen Nginx statische Files bereitstelle und (im Default) die Datei nicht existiert werde ich einen 404 bekommen - ist jetzt die fehlende Datei so anders als eine fehlende Row in einer Datenbank (falls ja was lässt der Sharepoint Grüßen, der ein Dateisystem über die DB abbildet). Ich denke es ist nicht alles schwarz/weiß und und wenn ihr mit eurem Team lieber mit Graph-QL und der Schnittstelle dort arbeitet ist das doch super. HTTP mit Verben/Status-Codes (REST oder nicht) zu verwenden oder nicht ist IMO eine Architekturentscheidung und hat Vor-/Nachteile. Wenn Du Websockets unterstützen willst/musst sollte das in die Entscheidung mit eingehen.
Danke für das Video! HTTP kommt halt noch aus einer Zeit wo die Entscheidung einfach war. Das Web wird aber immer komplexer und über die Basics wird immer weniger nachgedacht bzw. werden sie weniger beachtet. Das ist aber nur mein Eindruck.
Ich denke eher dass die Leute, die nicht mit dem Web aufgewachsen sind, sich schwerer tun, den ursprünglichen Sinn dahinter zu verstehen. Es ist viel leichter mit einer Technologie aufzuwachen, ihre Schritte mitzuverfolgen und Skill mäßig mitzuwachsen, als dass man ein bereits gewachsenes "System" lernen muss. Ähnlich verhält es sich bei der CLI. Früher ist man nicht daran vorbeigekommen und es war State of the Art, folglich hat sich damit jeder beschäftigt. Heute tun sich diese Entwickler viel leichter die Art und Weise von Programmen, Shell Skripten etc. zu verstehen. Aber nur meine Meinung.
Sorry, aber das find ich (als langjähriger REST-API-Entwickler) tatsächlich fragwürdig. Also ich versteh deinen Point, das kann man durchaus so argumentieren, aber ich bin trotzdem nicht der Meinung, dass man es in der Praxis so machen sollte. Beispiel: Wenn ein Datensatz nicht gefunden wird, ist 404 der einzig richtige Statuscode. Wenn "/Get?id=42" spezifiziert ist als "liefer den Datensatz mit Id 42", und der Response-Code 200 ist, muss der Response-Body (by definition) auch den Datensatz enthalten. Wenn nicht, dann ist 200 der falsche Statuscode. Alles andere wäre nicht RESTful. Die Response-Code sollen ja nicht nur technisch (z. B. hinsichtlich der HTTP-Route) sondern auch inhaltlich Aufschluss darüber geben, ob der Response erfolgreich ist oder nicht. "Not found" bezieht sich ja auf die angeforderte Ressource, und die kann eben auch ein Datensatz aus einer Datenbank sein. Ob im konkreten Fall die Route falsch war oder der Datensatz nicht existiert kann ja dann ggf. (im 404-Fall) immernoch im Response-Body stehen. Was liefert "/Get?id=42" also dann via Spezifikation im Response-Body im Fall Statuscode 200 zurück? Normalerweise würde man sagen: '{"id":42, "data":"foo"}' Du argumentierst jetzt aber, dass something like "{"errormessage":"Dataset not found"}" auch korrekt ist. Damit kann man als Client doch nicht arbeiten. Wenn man Statuscode 200 zurückbekommt und dann den Response-Body erst parsen muss, macht es das clientseitige Coding aufwändiger und fehleranfälliger, weil es keine einheitliche bzw. eindeutige Spezifikation gibt, wie Response-Bodys letztendlich aussehen. Und man sieht dann in den Developer-Tools die Requests, die inhaltlich falsch waren, trotzdem als 200. Selbst sowas wie "/Get?id=4q2", was eigentlich ein Bad-Request ist, ist dann clientseitig vom Statuscode her nicht mehr als solcher zu erkennen, weil er auch 200 zurückliefert (mit Error-message im Body), wenn der Web-Server so implementiert ist, wie du argumentierst. Siehe übrigens auch stackoverflow.com/a/26845858/3905529
Wenn für "/Get?id=4q2" das Schema korrekt validiert wird, dann könnte man mit Bad Request antworten, weil 4q2 keine Ganzzahl ist. Da würde es doch wieder passen. Generell stimme ich dir aber schon zu, denn wo trennt man technisch von fachlich, wenn man z. B. automatisch generierte URLs hat, per Mapping auf Dateisystem, auf DB, dynamisch ausgewertet. Ich denke, es ist eher entscheidend, ob man davon ausgeht, dass andere (z. B. Browser oder Menschen direkt) auf die Endpunkte zugreifen oder es eine API ist, die nur von den eigenen Entwicklungen oder von anderen Entwicklern entsprechend eines dokumentierten Schemas verwendet wird. Bei der eigenen oder gar internen API halte ich das Wegkapseln für sinnvoll.
Die Frage, die ich mir stelle ist: Wann ist eine Route technisch korrekt and wann fachlich? Das technisch wird hier mit statischen Ressourcen im Filesystem gleichgesetzt und das ist abstrakt betrachtet nicht anders als der Zugriff auf eine Datenbank. Nach der Logik müsste ich bei allen Routen ein 200er zurückgeben weil ja der Host existiert und die fachliche Anfrage an das Filesystem kein Ergebnis gebracht hat. GraphQL ist in einigen Aspekten eleganter, keine Frage, aber ich sehe diese Trennung zwischen "technisch" und "fachlich" definitiv anders.
Bei der Entwerfen einer Architektur sollte man nicht an eine Technologie denken sondern nur abstract an eine Schnittstelle. Danke für diesen Beitrag! Ich finde viele REST APIs die leider genauso aufgebaut sind.. sogar 417 kommen einem da unter... auch von sehr senior KollegenInnen gebaut... Was dann noch "lustig" wird: Wie erkennt die aufrufende Anwendung den unterschied zwischen 404 der Kunde hat keine Einträge im Warenkorb und 404 nichts gefunden :-) Außerdem habe ich bin jetzt noch keine Webschnittstelle gehabt die irgendwann asncron angesprochen werden sollte... und dann hat man eine Anwendung die im Kern mit HTTP Status Codes arbeitet und einer Batch Schnittstelle :-) Leider ziehen sich die HTTPStatus Schnittstellen immer tiefer in die Anwendung mit rein. Also noch mal Danke für Deine Videos! Sie sind immer ein guter Kompass
Hi Golo, vielen Dank für dieses Video und vor allem auch das Beispiel mit dem 404. Ich hatte über exakt dieses Thema schon etliche Diskussionen auf Arbeit und musste immer wieder schmerzlich feststellen, dass viele entweder keinen Wert auf die strikte Trennung legen oder meine Argumente diesbezüglich einfach nicht einsehen wollten. Auch das Argument mit mehr Aufwand, ist doch ehrlich gesagt absoluter Schwachsinn. Wenn einmal am Anfang ein Standard definiert und festgelegt würde, egal wie dieser auch aussehen würde, hätten am Ende alle eine Zeitersparnis und es würde weniger Missverständnisse geben. Ich sehe den Anwendungsfall für den 404 HTTP Status Code ebenfalls als klar technischen Fehler auf Protokollebene an und bin dagegen, diesen für fachliche Aussagen zu missbrauchen. Ein 404 gehört ins HTTP Protokoll und hat mit der Business Logik meiner Meinung nach, absolut nix zu tun. Wenn ein Datensatz nicht existiert, gibt es für mich nur eine korrekte Antwort: 200 mit einem leeren Response je nach Content Typ. Die Anfrage war erfolgreich, es wurde jedoch nix gefunden. Der Rest ist Implementierung auf Clientebene.
Das ist wirklich ein guter Punkt. Würde da gern meine Erfahrung teilen. Ich entwickle APIs und UIs nun schon ein paar Jahre. Und halte es für einen Fehler allgemein StatusCode für Applikations-responses zu nutzen. Also kurz um empfehle ich eher NUR 200 oder 400 zu nutzen. Also auch kein 204 oder so bei leeren Ergebnis. Ich weis klingt erstmal falsch. Aber hier die Erklärung: Wie im Video erklärt wird über den Protokoll-Status Code gern kommuniziert was mit dem Protokoll nichts zu tun hat. Man kann es klar sehen wenn man sich das alte ISO/OSI Modell vor Augenführt. Das ist ungefähr so als würde man erfolgreiche Antworten an einen IP-Port schicken und fehlgeschlagene an einen anderen. Zusätzlich kommt hinzu dass die StatusCodes redundant entsprechend der Verarbeitung in der App selbst erstellt werden müssen. Man kann also beliebige Codes bei beliebiger Verarbeitung schicken. Fehleranfällig. Also bei irgend einen 400er weis ich dass das Protokoll oder Technik iwo versagt hat. Bei 200er checke ich die Antwort. Und dort ist entweder ein Fehler oder Daten drin. Ich weis. ist blöd wenn man direkt parsen will. Aber das kann man auch lösen. Mit default body containern oder einfachen checks vor dem Parsen... ist leider nicht optimal. Ich finde also da wurde ein kleiner Fehler gemacht bei der HTTP Definition. Welcher dan ausser Kontrolle geraten ist. -Ist nur ein Erfahrungsbericht. Bin offen für Feedback.
Oft spielt es ja für den Client keine Rolle, ob der Request fachlich oder technisch nicht korrekt war. Das Ergebnis ist in beiden Fällen gleich, der Client muss mit einem fehlerhaften Request zurecht kommen. Einen 404er finde ich deswegen nicht falsch. Zu dem anderen Punkte, dass man mehrere unterschiedliche Daten auf einen Request bekommt: Das ist meiner Meinung nach eine falsch designte Schnittstelle. REST hat ja genau die Idee: dass jede Adresse genau eine Ressource abbildet. Ich finde es übrigens mutig zu sagen, dass der Großteil der Entwickler REST falsch versteht und anwendet.
Die eigentlich wichtigste Frage für den 404 Fall hat bisher noch keiner gestellt: Woher hat der Aufrufer die URI und ist die Quelle dieser URI evtl fehlerhaft, weil veraltet?
[gr] Ja, guter Punkt - und ich würde sagen, darauf gibt es eine ganze Reihe von Antwortmöglichkeiten: - Entwickler:in hat sich vertippt - Veralteter Link - Fehler beim Zusammenbau der URL - Fehler beim Redirect (falsche Angabe des Location-Headers, wobei das letztlich auf die vorigen drei Gründe zurückfällt, nur an anderer Stelle) - Server hat temporäre Probleme und findet URL nicht - …
Also alles Fehler, auf die ein Entwickler bzw. sein Team eigentlich reagieren und die Ursache beheben sollte. Warum dann dafür verschiedene Statuscodes verwenden? 404 ist von gelegentlichen eventual consistency Problemen abgesehen ein Fall, der fachlich nicht auftreten sollte. Wer diese Antwort regelmäßig bekommt, arbeitet entweder mit stark veralteten Daten (bspw. aufgrund der Verwendung von batch imports statt event streaming) oder hat tatsächlich irgendwo ein Konfigurations- bzw. Codeproblem. Beides sind technische Probleme, die keine fachliche Relevanz haben.
Klingt erst mal charmant aber die Regel zum erkennen ob http Fehler oder nicht ist evtl zu streng. Was ist bei 500ern? Wenn ich z.B als Api-Entwickler Probleme habe meine interne Persistenz zu erreichen, hätte ich das Problem ja unabhängig davon ob ich auf http antworte oder etwas anderes. Wäre also ein 200er und ich müsste einen extra Fehler im Body codieren (Weil die Route gibt es ja)? Das fänden meine Devops und Sysadmins nicht so toll wenn sie für ihr Monitoring erst Bodys parsen muss um 500er-like Fehler schnell zu erkennen. Ich befürchte das ist in der Praxis oft ein Kompromiss zwischen ganz verschiedenen Instanzen. Und ja, ich hab mich da auch schon oft verzettelt. Weiß also auch nicht die eine Lösung für alles. :D
Danke für das Video. Dieses Thema ärgert mich schon seit Jahren. Wo ich auch drüber nachdenke: Müsste man bei dem Thema nicht auch die Requestmethode mit einbeziehen? Macht es da dann überhaupt Sinn die Semantik auf die Transportschicht zu ziehen, wenn ich beim Response nur noch die technische Verbindung betrachte? 🤔 Ich bin mir da, im Gegensatz zu den Statuscodes nicht so sicher… ich glaube aber, dass es konsequent wäre. Was meint ihr?
Sehr gut. Gerade habe ich eine neue API entworfen und merke das ich mir keine wirkliche Gedanken um die HTTP-Status-Codes gemacht habe. Ich sehe es genauso das ein Status 200 immer richtig ist, egal zu welchem Ergebnis es kommt. Statt gesuchter Werte, kommt halt "Keine Daten", "Nichts gefunden" oder sowas. Ein 404 ist dafür da, das unbekannte Routen abgefangen werden. 307, 308 kannte ich bisher nicht. 302 kenne ich und nutze für Umleitungen. Schöner Beitrag und danke dafür.
Den Gedanken kann ich nachvollziehen. In der Praxis bedeutet das aber eben auch den Overhead, ein eignes gut durchdachtes Fehlerhandling zu bauen. Mein Gefühl ist, dass diese angestrebte Trennung zwar vielleicht theoretisch korrekt ist, die Komplexität aber erhöht und Zeit kostet. Zumindest in einem Projekt an dem ich mitarbeiten „durfte“, war das Fehlerhandling dann ganz furchtbar umgesetzt (im Client überall dupliziertes String matching, kein Interceptor o.ä., kein zwischen Server und Client geteilter Code etc.). Ist Authentifizierung und Autorisierung fachlich oder technisch zu sehen?
Genau diese Unterscheidung von technisch und fachlich forciere ich auch und ist im Frontend auch viel besser zu händeln, geht etwas technisch schief, dann gibt es ein Popup und der Anwender kann sich allenfalls an den Support wenden, hat sich der Anwender vertippt, wird was nicht gefunden, ist die Validierung nicht durchgelaufen oder fehlt die Berechtigung, dann kann ich dem Anwender die Information weitergeben und der Anwender kann auch darauf reagieren. Das nichts gefunden wird, kann man auch ganz einfach mit einen leer zurückgegeben Objekt sagen. Bei uns hat aber generell jeder Antwort neben den angeforderten Daten auch einen separaten Status und gegebenenfalls eine Errormessage.
Was wenn eine Website (wie zB WordPress) erst mal alle Requests annimmt? Sollte man dann für nicht gefundene Inhalte trotzdem den Statuscode 200 verwenden und dann das crawlen dieser Seite durch andere Techniken verhindern?
Also ich gehe immer mehr dazu über bei REST(ful)-APIs die etwas komplexer sind, Antworten auf GET-Requests, wenn es sich um JSON-Ressourcen handelt, immer mit einem Array zu beantworten und zwar auch bei Single-Ressourcen. Ein leeres Array ist gleichbedeutend mit dem dass eine Ressource nicht gefunden wurde. Und es hat den Vorteil, dass man nur eine einzige Art der Deserialisierung haben muss. Zusätzlich gibt es einen einheitlichen Wrapper bei dem dann neben den eigentlichen JSON-Ressourcen auch noch fachliche Meta-Daten und fachliche Fehler-Daten zurückgegeben werden können. Viele REST(ful) APIs benutzen die Status-Codes entweder falsch oder vermischen halt fachliche Fehler mit HTTP-Fehlern. Ich finde, dass das bei reinen CRUD-Daten-APIs nicht so schlimm ist, aber bei etwas komplexeren APIs oft auch schon die HTTP-Verben im Request falsch benutzt werden. Oft macht es mehr Sinn, RPC-Anfragen zu schreiben und diese einfach mit einem POST zu schicken. Und oft macht es auch Sinn das Verändern von Daten komplett vom Lesen zu entkoppeln und mit Commands die einen sprechenden fachlichen Namen haben zu arbeiten. Dann ist auch der dahinterliegende Intention einer Änderung der Daten nachvollziehbar. Bei einem PUT-Request, bei dem immer die komplette Ressource geschickt wird, ist das nachher eher schwer nachvollziehbar, warum die Daten geändert wurden. Ich finde da CQRS einen interessanten Architekturansatz, der aber auch nicht überall paßt, jedoch das Lesen und Schreiben modelltechnisch komplett trennt.
[gr] Ich persönlich würde vermutlich gar kein 201 schicken - oder bestenfalls dann, wenn es keine Antwort gibt, außer dass etwas empfangen wurde (wobei man da IMHO auch genauso gut die 200 nehmen kann).
Mir ist gerade eine Idee eingefallen, wie man das lösen könnte: zusammengesetzte Statuscodes. Beispiel: 200/404: Anfrage erfolgreich, Daten nicht gedundeb
[gr] Das ist eine interessante Idee - wobei das immer noch nicht mit Listen von Entitäten funktionieren würde. Also Beispiel: Du forderst fünf Objekte an. Die Anfrage funktioniert (technisch), also 200, und der der fünf Objekte können auch geladen werden, aber bei zweien fehlen Dir die Zugriffsrechte. Das müsste dann so was sein wie 200/[200,200,401,200,401] …😉
Wie wäre es denn zb beim Statuscode forbidden. Angenommen ein Benutzer hat eine bestimmte Berechtigung nicht, darf die Software aber generell benutzen... Würde man dann auch 200 zurück geben und im Body ein "eigenes" Protokoll definieren, was sagt: Keine Berechtigung?
Wir verwenden HTTP-Statuscodes zwar ähnlich, aber im Grunde leiten wir in der Auswertung der Statuscodes daran nur ab, ob ein Fehler aufgetreten ist, oder nicht. Also wenn es ein 4xx oder 5xx Code ist, ist es für uns erstmal ein beliebiger Fehler. Im Fehlerfall liefern wir aber im Response-Body eine entsprechende Fehlerbeschreibung mit aussagekräftigen Error-Codes. Wir versuchen zwar natürlich auch, die HTTP-Codes entsprechend zu setzen, aber für die Fehlerauswertung sind sie (in den meisten Fällen) nicht explizit relevant.
Wenn man es nur nach fachlicher/technischer Hinsicht trennt und nur bei technischen Fehlern Http-Statuscodes nutzen soll, wann erhält man dann z.B. eine 401? Denn ist es nicht auch ein fachlicher Fehler, wenn die übermittelten Credentials nicht mit den hinterlegten übereinstimmen? Dann sollte es ja niemals eine 401 (technischer Fehler) geben. Ich verstehe die Gedankengänge, aber so richtig überzeugt mich das bei der Vielzahl und der dazugehörigen Erklärungen der Http-Statuscodes nicht. Und GraphQL als positives Beispiel hervorzuheben finde ich auch fraglich, da es in so vieler Hinsicht falsch macht. Aber das ist ein anderes Thema.
Vielen Dank für dein Video, alles ist schlecht ok . Nun wo finde ich eine bessere Möglichkeit um Fehler für ;variable ohne Inhalt , böse Zeichen in variable oder variable zu lang ' ... Meldungen die auch etwas aussagen von der api zu bekommen, habe versucht mir einen anderen Zahlenraum 600+ zu setzen die werden aber vom Browser einfach nicht durchgeschaltet, bin am Überlegen ob ich einen Handler zwischen schalte und über JSON auch die Fehler klar definiere und dann abfange bevor es weitergeht. Doppelte Variablen Überpüfung möchte ich vermeiden. welcher Weg macht nun wirklich Sinn.
[gr] Wie im Video erwähnt - wenn Du soweit gekommen bist, dass Du erkennst, dass zB ein Feld einen ungültigen Wert enthält, dann hat die Anfrage auf technischer Ebene (also aus Sicht der Transportschicht) ja bereits funktioniert. Insofern gibst Du einen 200 zurück, und im Response-Body eine Struktur, die den Fehler beschreibt.
@@thenativeweb, ihre Antwort findet fruchtbaren Boden. Im Selbststudium bin ich dabei eine eigene API-Struktur zu erstellen, um grundlegendes zu vertiefen. Es ist zwar recht gut was an Tutorials zu finden ist, doch manchmal hechtet man von einer super programmier-Form bzw.-Konzept zum Nächten. Was einem sein Projekt dann mehrfach komplett umbauen lässt, bis eine einfach strukturierte form verbleibt, die dann auch noch nach Monaten nachvollziehbar bleibt. Leider wird Dieses Wissen nicht immer sauber vermittelt und muss über den langen weg erarbeitet werden. Vielen dank für deine Videos
Ich finde beide Wege in Ordnung: Wenn die Anwendung nur HTTP anbietet, finde ich es legitim, das Statushandling über HTTP zu machen. Also z.B. 401=nicht erlaubt oder 204=keine Daten. Oder 404. Das hat auch große Vorteile bei Anwendungen, die HTTP benutzen. Beispiel: Curl liefert einen RC != 0 zurück, wenn Status != 2xx,3xx so kann man per Bash einfach den Status verarbeiten. Falls das eigene Protokoll selber einen Status verwaltet kann man das natürlich auch machen und immer HTTP 200 zurückliefern. Allerdings muss der Client dann das interne Wissen über die Status der Anwendung haben. Bei HTTP 5xx ist halt klar, das ein Fehler auftritt. Wenn die Anwendung aber den eigenen Status 56789 definiert, dann muss der Client all dieses Wissen in sich tragen. Beide Lösungen haben ihre Vorteile. Sofern die HTTP-Status aussagekräftig genug sind, würde ich diese auch nutzen. WebDAV macht es ja auch so.
Ich persönlich nutzte die im Grunde technisch. BadRequest für fehlerhafte requests (unter anderem auch wenn eine resource nicht gefunden wurde) Bswp. Ein Problem hab ich jedoch mit unauthorized... Theoretisch sollte dieser ja kommen, wenn der Zugriff auf einen Endpunkt nicht erlaubt ist. Allerdings verwässert das die Sicherheit, weswegen ich in solchen Fällen 404 zurück gebe. Gefällt mir eigentlich nicht... Erlaubt aber, dass bei korrekt eingerichteter Software, der Endpunkt nur denen verfügbar ist, die das ganze auch benutzen dürfen.
Vielen Dank für den Beitrag. Ich hatte schon mehrfach die Diskussion mit meinen Kollegen. Vor allem um 404. Am Ende hatte sich bei uns 404 durchgesetzt, wenn für eine Anfrage fachlich keine Antwort möglich war. Meine Vorschläge: - HTTP-Status 204 no content - Rückgabe von null - leere Liste wurden von der Gruppe abgelehnt. Für den Vorschlag Status 204 zu nutzen, wurde ich regelrecht ausgebuht. Dazu zwei Fragen: 1) Status 204. Wann sollte/könnte man ihn nutzen? 2) Gibt es Regeln, welcher Status bei welchen Request-Methoden (PUT, POST, GET, usw.) verwendet/nicht verwendet werden sollte?
Zu 1) Wir benutzen den 204 Status Code oft als Folge für einem erfolgreichen DELETE-Request. Zu 2) Nun ja, GET Requests haben keinen Body, also alle Status-Codes, welche irgendetwas mit der Verarbeitung eines Request-Bodys zu tun haben, wären hier fehl am Platze...
Gerade mal geguckt, wann die Error-Section in einem AJAX-Call geTriggert wird... ist auch eine Frage, wie es im Client vom Entwickler gedacht war/wird/ist.
Vielen Dank für den Beitrag, tatsächlich sind HTTP codes immer wieder in Projekten ein Diskussionsthema. Ich habe aber auch gesehen, dass es viele Probleme gab, eine geeignete Fehlerdatenstruktur zu finden. IMHO nimmt man ja gerne die HTTP codes um sich vor so einer Designentscheidung zu drücken:-) Als Lösung habe ich jetzt schon mehrmals gute Erfahrung mit dem RFC 7807 gemacht: Ein flexibler Standard für fachliche Fehler und tatsächlich schon einige Bibliotheken, die es unterstützen ohne das Rad (parsen, (de-)serializieren,...) immer wieder neu zu erfinden. Was hast du denn für Erfahrungen gemacht mit Fehlerdatenstrukturen in HTTP APIs? Eher custom oder standards? Wenn Standards, welche?
Zum einen gebe ich dir da vollkommen Recht. Aber hier ist es klar von der Interpretation der Definitionen abhängig. Ist ein Script am Ende eine Ressource (technisch) oder erst die primären Daten/die Anwendung/das erwartete spezifische Ergebnis (fachlich), die vom Script einer URL zurückgeliefert wird? Gerade bei letzterem kann ich den Drang zur Nutzung des Codes 404 durchaus verstehen. Da fällt am Ende eine Trennung zwischen technischen Statis und den fachlichen recht schwer, wenn auf Seiten des Clients in beiden Fällen nichts für den Nutzer herausspringt und auch technisch nichts verwertbares geliefert wird. Aber wie du schon sagtest verliert man dadurch die Möglichkeit, auf das HTTP-Protokoll zu verzichten, da man die Client-Applikation und dessen Verhaltensweisen direkt auch an das Trägerprotokoll geknüpft hat. Ich denke, das wir hier aber auch von einem ganz spezifischen Ausgangspunkt reden, der auf Grund der und unserer Entwicklung nachvollziehbar ist. Das Web bestand zu Anfang nur aus reinen Ressourcen. Mit Einführung dynamischer Webinhalte begann schon die Frage danach, ob jetzt mit einer Ressource das Script selbst oder das Ergebnis dieses gemeint ist. Aber auch hier fand man früh eine klare Antwort darauf. Denn zu beginn dynamischer Inhalte waren Anwendungen, die diese erzeugten vorzugsweise Monolithen, bei denen die einzelnen technischen Stationen und ihrer Abarbeitung der Anfragen klar definiert waren. Der Server bekam die Anfrage vom Browser, leitete das ans Script weiter, dieses verarbeitete alles und lieferte dann das fertig erzeugte DOM an den Browser. Es gab also über sehr lange Zeit den Server und den Browser und kommuniziert wurde nun einmal über HTTP. Somit wurde das Trägerprotokoll der Einfachheit halber auch als Anwendungsprotokoll genutzt. Da spielte eine Trennung zwischen einer technischen und fachlichen Ebene keine große Rolle. Denn man ging vor allem bei Monolithen als Entwickler einfach davon aus, das die Anfragen von einem Browser kommen, das Ergebnis an einen Browser geliefert werden und das einzige Protokoll in dieser Kommunikation HTTP sein wird. Mit REST und mobilen Anwendungen als Clients wurde dann das Zeitalter der Entkopplung begonnen. REST war allerdings gefühlt ein Versuch der Erweiterung (oder des Umbiegens?) des HTTP-Protokolls. Das war auch damals die Zeit, in der ich meine Lust ans Web völlig verloren hatte. Das war die Zeit, in der ich mir die Frage nach dem Warum gestellt habe. Warum ist REST so ... wie es ist. Ich habe es gehasst. Und das ging definitiv nicht nur mir so. Man fühlte sich durch den Quasi-Standard völlig in die Ecke gedrängt .... ich schweife ab .... das gehört hier nicht hin *aufdenhinterkopfschlag*. Auf jeden Fall gab es beim Aufkommen von REST einfach nicht das Mindset dafür, eine Trennung von HTTP und Anwendung in Betracht zu ziehen, weil REST nun einmal das HTTP-Protokoll voraussetzt und dessen Header auch aktiv bei der Implementierung von Anwendungen mit einbezieht. Auch hier wäre eine Trennung garnicht richtig sinnvoll. Denn laut Definition von Rest (wie du auch anmerktest) bildet jede URI eine spezifische Ressource ab. Und somit ist es gehüpft wie gesprungen, ob im Falle einer fehlenden Ressource 404 zurückgeliefert wird oder eine Anwendungsspezifische Meldung. Denn REST setzt HTTP voraus und der Client muss dann auch HTTP beherrschen. Und dadurch konnte man sich auch auf HTTP und dessen Statuscodes verlassen. Aber wie schon immer gewesen ändern sich nun einmal die Zeiten (Wissenschaft und Entwicklung sei dank) und mittlerweile wird immer häufiger erkannt, das es doch sinnvoller wäre (vor allem bei der Entkopplung), ein Anwendungsprotokoll für die fachlichen Statis sowie auch der Datenaufbereitung zu verwenden und den technischen Teil das jeweilige Trägerprotokoll machen zu lassen. Ich kann mich noch gut daran erinnern, als ich für Purebasic selbst ein Anwendungsprotokoll definieren musste, weil es ewig gedauert hat, über die HTTP-Bibliothek spezifische Header zu setzen oder auslesen zu können. War witzig. Die Entwickler waren voll Stolz, das deren HTTP-Lib kompatibel zu REST war ... Nur eben nicht mit JWT ... Blöd xD Und was hatte ich damit auf einmal für Möglichkeiten, REST einfach in diesem Zuge zu ignorieren, weil sich das Anwendungsprotokoll darum kümmerte ... Herrlich :) FAZIT: Das wird sich noch ändern. Keine Sorge. Neue Standards und neue Mindsets sind schnell formuliert, verbreitet und ausreichend begründet. Aber bis die Gedanken auch bei allen endgültig zünden, dauert es eine Weile. Das Video hat aber dazu beigetragen, den Leuten ein "es muss anders gehen" Gefühl zu geben und ihren eigenen Umgang mit diesem Thema zu reflektieren. Aber historisch bedingt (und vor allem in Anbetracht der Art und Weise, wie sich das Web entwickelt hat) muss man den Entwicklern auch eine gewisse Zeit lassen. Für viele begann der Ein- bzw. Umstieg von Monolithen zu entkoppelten Systemen vor nicht allzu langer Zeit und es ist üblich erst auf Rest zu stoßen, da es noch immer gefühlt allgegenwertig ist. Vor allem, wenn sie das Web noch so sehen, wie es vor über 10 Jahren war und nicht wie es jetzt ist oder es sein könnte. Das wird schon noch ;)
Wir benutzen die Status Codes RESTful und somit auch fachlich. Wir fragen die Resourcen per Path-Variable ab, wodurch "Resource not found" wieder stimmt. Aber wir hatten eben die gleiche Diskussion auch.
[gr] Das Wichtigste ist am Ende IMHO, dass man eine bewusste Entscheidung trifft, und es nicht "einfach so" und "irgendwie" macht, insofern habt Ihr doch alles richtig gemacht 😊
Bin da letztens auf die schnauze gefallen: wole Daten über eine API ziehen und wundere mich, warum meine Dateien Schrott waren. Hab mich auf die Status Codes verlassen... Ja... HTTP 200, aber die Meldung "no item found"... Aber ja, technisch gesehen ist das ja korrekt
Ich habe mich sogar schon mal über eine Schnittstelle geärgert, die fachliche Fehler nicht über den Statuscode abgebildet hat 😂. Aber du hast völlig recht.
Tolles Video (und Kanal insgesamt), vielen Dank. Wäre z.B. der Status Code - 422 Unprocessable Entity - eine sinnvolle und logische Alternative um das fachliche Problem bei invaliden Requests auf HTTP Ebene anzudeuten? Vielleicht hat ja schon jemand damit schon Erfahrungen und User Feedback gesammelt. Ich weiß das z.B. FastAPI (API Framework für Python) diesen Status Codes bei invaliden Requests nutzt und finde ihn recht passend für das beschriebene Problem.
Bei REST wird ja nicht nur der Statuscode Zweckentfremdet, sondern das ganze http Protokoll (get with body, delete with body, create = post). Das ganze Konzept ist schon an sich schräg. Um ein Minimum an overhead zu haben ist es brauchbar, aber um eine gute Schnittstelle zu definieren ist es das nicht.
Bei REST wird das HTTP Protokoll nicht zweckentfremdet, sondern REST ist eine "Anleitung" dafür, die Intention des Protokolls zu erfüllen und damit seine Stärken zu nutzen. Es lohnt sich, die Dissertation von Roy Fieldings zu lesen, die den Begriff REST eingeführt hat. Ohne die gelesen und verstanden zu haben, finde ich es gewagt, das Konzept zu beurteilen.
@ Nun ja, die Definition ist teilweise aber auch unvollständig und kann so oder so ausgelegt werden. Für reine CRUD-Daten-APIs kann man durchaus eine sehr puristische REST-API bauen. Allerdings schränken meiner Meinung nach gerade bei komplexeren fachlichen APIs das zwanghafte mappen auf HTTP-Verben die eigentliche Fachlogik massiv ein und verwässern die dahinterliegende fachliche Intention einer Datenänderung.
Für meine Begriffe gibt es keinen Fall, in dem mehrere Ressourcen in einer Antwort verarbeitet werden. Eine Liste von mehreren bspw. Datensätzen ist eine Ressource. Daher sehe ich die Argumentation als falsch an.
Ich musste sehr schmerzhaft feststellen, dass einer unserer Services bei nicht gefundenem Datensatz, auf ein GET "../x/y?filter=value" 404 zurückgab. Dabei habe ich Stunden nach Problemen im Proxy gesucht. Wenn die Fehlermeldung doch wenigstens sinnvoller als "not found" wäre...
Auch wenn ich das Video angeklickt habe obwohl ich nichts verstehe fand ich das Video super der Herr ist sehr angenehm zum anhören 😅
[gr] Vielen lieben Dank 😊
Sehr interessanter Beitrag. Vielen Dank! Das ist ja einfach das coupling Problem, dass man beim programmieren vermeiden möchte, auf Protokoll Ebene
[gr] Ja - genau das. Ich finde es interessant, dass man bei all diesen Themen nahezu immer am Ende bei Kopplung und / oder Kohäsion landet 😊
Ich halte es bei meinen APIs im wesentlichen so wie es Restful vorgibt. Pflichtparameter wie Ressourcen-Ids werden im Pfad abgebildet (/users/123), Listen mit Filteroptionen per Queryparameter (/users?q=abc&id=123...).
Wenn Ressourcen im Backend mit den Pflichtparametern nicht gefunden werden wird ein 404 zurückgegeben. Bei Listen kann auch eine leere Liste mit 200 oder Empty mit 204 zurückkommen. Ich bevorzuge aber die leere Liste weil diese Listen meistens in Tabellen oder Grids dargestellt werden und man im Consumer keine große Sonderlogik braucht.
400 als Response wenn Eingabeobjekte nicht korrekt sind (Properties fehlen, falsches Format,...).
401 wenn der User nicht authentifiziert ist.
403 wenn der User nicht autorisiert ist die Operation durchzuführen.
Alles mit Statuscode >=500 hat einen Fehler im Backend produziert und der Request hat nicht korrekt funktioniert.
Diese Statuscodes nicht auch in Verbindung mit fachlichen Zusammenhängen zu verwenden macht aus meiner Sicht keinen Sinn und eine harte Grenze zwischen technisch und fachlich ist schwer zu ziehen. In einer hexagonalen Architektur sind die DTOs und das Interface passend zum Protokoll des entsprechenden Controllers (in dem Fall HTTP/REST). Daher kann man hier auch alle zur Verfügung stehenden Mittel nutzen. In HTTP kann ich Cookies und Header für zusätzliche Parameter wie SessionIds nutzen, für Websocket muss das DTO ggf. ein Errorobjekt enthalten, beim nächsten Protokoll gibt es einen zusätzlichen Errorkanal usw.
Gerade bei REST und im Frontend sind Libraries wie Axios darauf ausgelegt, dass die Statuscodes >=400 kommen um eine Fehlerbehandlung (try/catch) zu starten. Das alles selbst neu zu erfinden, zu programmieren und auf irgendwelche Subobjekte zu prüfen, verwirrt und ist schwer zu warten, besonders bei größeren Teams.
Wo machst Du denn den Cut bei "technisch"?
Wenn ich über einen Nginx statische Files bereitstelle und (im Default) die Datei nicht existiert werde ich einen 404 bekommen - ist jetzt die fehlende Datei so anders als eine fehlende Row in einer Datenbank (falls ja was lässt der Sharepoint Grüßen, der ein Dateisystem über die DB abbildet).
Ich denke es ist nicht alles schwarz/weiß und und wenn ihr mit eurem Team lieber mit Graph-QL und der Schnittstelle dort arbeitet ist das doch super. HTTP mit Verben/Status-Codes (REST oder nicht) zu verwenden oder nicht ist IMO eine Architekturentscheidung und hat Vor-/Nachteile. Wenn Du Websockets unterstützen willst/musst sollte das in die Entscheidung mit eingehen.
Danke für das Video! HTTP kommt halt noch aus einer Zeit wo die Entscheidung einfach war. Das Web wird aber immer komplexer und über die Basics wird immer weniger nachgedacht bzw. werden sie weniger beachtet. Das ist aber nur mein Eindruck.
Ich denke eher dass die Leute, die nicht mit dem Web aufgewachsen sind, sich schwerer tun, den ursprünglichen Sinn dahinter zu verstehen. Es ist viel leichter mit einer Technologie aufzuwachen, ihre Schritte mitzuverfolgen und Skill mäßig mitzuwachsen, als dass man ein bereits gewachsenes "System" lernen muss. Ähnlich verhält es sich bei der CLI. Früher ist man nicht daran vorbeigekommen und es war State of the Art, folglich hat sich damit jeder beschäftigt. Heute tun sich diese Entwickler viel leichter die Art und Weise von Programmen, Shell Skripten etc. zu verstehen. Aber nur meine Meinung.
Sorry, aber das find ich (als langjähriger REST-API-Entwickler) tatsächlich fragwürdig. Also ich versteh deinen Point, das kann man durchaus so argumentieren, aber ich bin trotzdem nicht der Meinung, dass man es in der Praxis so machen sollte. Beispiel:
Wenn ein Datensatz nicht gefunden wird, ist 404 der einzig richtige Statuscode.
Wenn "/Get?id=42" spezifiziert ist als "liefer den Datensatz mit Id 42", und der Response-Code 200 ist, muss der Response-Body (by definition) auch den Datensatz enthalten. Wenn nicht, dann ist 200 der falsche Statuscode. Alles andere wäre nicht RESTful.
Die Response-Code sollen ja nicht nur technisch (z. B. hinsichtlich der HTTP-Route) sondern auch inhaltlich Aufschluss darüber geben, ob der Response erfolgreich ist oder nicht. "Not found" bezieht sich ja auf die angeforderte Ressource, und die kann eben auch ein Datensatz aus einer Datenbank sein. Ob im konkreten Fall die Route falsch war oder der Datensatz nicht existiert kann ja dann ggf. (im 404-Fall) immernoch im Response-Body stehen.
Was liefert "/Get?id=42" also dann via Spezifikation im Response-Body im Fall Statuscode 200 zurück? Normalerweise würde man sagen: '{"id":42, "data":"foo"}'
Du argumentierst jetzt aber, dass something like "{"errormessage":"Dataset not found"}" auch korrekt ist.
Damit kann man als Client doch nicht arbeiten.
Wenn man Statuscode 200 zurückbekommt und dann den Response-Body erst parsen muss, macht es das clientseitige Coding aufwändiger und fehleranfälliger, weil es keine einheitliche bzw. eindeutige Spezifikation gibt, wie Response-Bodys letztendlich aussehen. Und man sieht dann in den Developer-Tools die Requests, die inhaltlich falsch waren, trotzdem als 200. Selbst sowas wie "/Get?id=4q2", was eigentlich ein Bad-Request ist, ist dann clientseitig vom Statuscode her nicht mehr als solcher zu erkennen, weil er auch 200 zurückliefert (mit Error-message im Body), wenn der Web-Server so implementiert ist, wie du argumentierst.
Siehe übrigens auch stackoverflow.com/a/26845858/3905529
Wenn für "/Get?id=4q2" das Schema korrekt validiert wird, dann könnte man mit Bad Request antworten, weil 4q2 keine Ganzzahl ist. Da würde es doch wieder passen.
Generell stimme ich dir aber schon zu, denn wo trennt man technisch von fachlich, wenn man z. B. automatisch generierte URLs hat, per Mapping auf Dateisystem, auf DB, dynamisch ausgewertet.
Ich denke, es ist eher entscheidend, ob man davon ausgeht, dass andere (z. B. Browser oder Menschen direkt) auf die Endpunkte zugreifen oder es eine API ist, die nur von den eigenen Entwicklungen oder von anderen Entwicklern entsprechend eines dokumentierten Schemas verwendet wird. Bei der eigenen oder gar internen API halte ich das Wegkapseln für sinnvoll.
Die Frage, die ich mir stelle ist: Wann ist eine Route technisch korrekt and wann fachlich? Das technisch wird hier mit statischen Ressourcen im Filesystem gleichgesetzt und das ist abstrakt betrachtet nicht anders als der Zugriff auf eine Datenbank. Nach der Logik müsste ich bei allen Routen ein 200er zurückgeben weil ja der Host existiert und die fachliche Anfrage an das Filesystem kein Ergebnis gebracht hat. GraphQL ist in einigen Aspekten eleganter, keine Frage, aber ich sehe diese Trennung zwischen "technisch" und "fachlich" definitiv anders.
Statt direkt mit 200 zu antworten, wenn nichts gefunden wird ginge auch ein 204. In dem Fall müsste noch nicht einmal der Body geparst werden.
Bei der Entwerfen einer Architektur sollte man nicht an eine Technologie denken sondern nur abstract an eine Schnittstelle. Danke für diesen Beitrag! Ich finde viele REST APIs die leider genauso aufgebaut sind.. sogar 417 kommen einem da unter... auch von sehr senior KollegenInnen gebaut... Was dann noch "lustig" wird: Wie erkennt die aufrufende Anwendung den unterschied zwischen 404 der Kunde hat keine Einträge im Warenkorb und 404 nichts gefunden :-)
Außerdem habe ich bin jetzt noch keine Webschnittstelle gehabt die irgendwann asncron angesprochen werden sollte... und dann hat man eine Anwendung die im Kern mit HTTP Status Codes arbeitet und einer Batch Schnittstelle :-)
Leider ziehen sich die HTTPStatus Schnittstellen immer tiefer in die Anwendung mit rein.
Also noch mal Danke für Deine Videos! Sie sind immer ein guter Kompass
[gr] Oh ja - asynchrone HTTP-Schnittstellen vs REST, das Spielchen kenne ich auch zur Genüge … 🙄
Vielen Dank für das Lob bezüglich der Videos 😊
Cooler Beitrag. Danke dafür. Ich ertappe mich auch manchmal dabei, auf biegen und brechen fachliche Fehler in HTTP status codes zu verpacken.
Vielen Dank für diesen Beitrag, auch hier ein oft diskutiertes Thema. Du hast hier einiges ins rechte Licht gerückt, Danke dafür 👍👌
[gr] Danke für das Lob, das freut mich 😊
Hi Golo, vielen Dank für dieses Video und vor allem auch das Beispiel mit dem 404.
Ich hatte über exakt dieses Thema schon etliche Diskussionen auf Arbeit und musste immer wieder schmerzlich feststellen, dass viele entweder keinen Wert auf die strikte Trennung legen oder meine Argumente diesbezüglich einfach nicht einsehen wollten. Auch das Argument mit mehr Aufwand, ist doch ehrlich gesagt absoluter Schwachsinn. Wenn einmal am Anfang ein Standard definiert und festgelegt würde, egal wie dieser auch aussehen würde, hätten am Ende alle eine Zeitersparnis und es würde weniger Missverständnisse geben. Ich sehe den Anwendungsfall für den 404 HTTP Status Code ebenfalls als klar technischen Fehler auf Protokollebene an und bin dagegen, diesen für fachliche Aussagen zu missbrauchen. Ein 404 gehört ins HTTP Protokoll und hat mit der Business Logik meiner Meinung nach, absolut nix zu tun. Wenn ein Datensatz nicht existiert, gibt es für mich nur eine korrekte Antwort: 200 mit einem leeren Response je nach Content Typ. Die Anfrage war erfolgreich, es wurde jedoch nix gefunden. Der Rest ist Implementierung auf Clientebene.
Das ist wirklich ein guter Punkt. Würde da gern meine Erfahrung teilen.
Ich entwickle APIs und UIs nun schon ein paar Jahre.
Und halte es für einen Fehler allgemein StatusCode für Applikations-responses zu nutzen.
Also kurz um empfehle ich eher NUR 200 oder 400 zu nutzen. Also auch kein 204 oder so bei leeren Ergebnis.
Ich weis klingt erstmal falsch. Aber hier die Erklärung:
Wie im Video erklärt wird über den Protokoll-Status Code gern kommuniziert was mit dem Protokoll nichts zu tun hat. Man kann es klar sehen wenn man sich das alte ISO/OSI Modell vor Augenführt. Das ist ungefähr so als würde man erfolgreiche Antworten an einen IP-Port schicken und fehlgeschlagene an einen anderen.
Zusätzlich kommt hinzu dass die StatusCodes redundant entsprechend der Verarbeitung in der App selbst erstellt werden müssen. Man kann also beliebige Codes bei beliebiger Verarbeitung schicken. Fehleranfällig.
Also bei irgend einen 400er weis ich dass das Protokoll oder Technik iwo versagt hat.
Bei 200er checke ich die Antwort. Und dort ist entweder ein Fehler oder Daten drin. Ich weis. ist blöd wenn man direkt parsen will. Aber das kann man auch lösen. Mit default body containern oder einfachen checks vor dem Parsen... ist leider nicht optimal.
Ich finde also da wurde ein kleiner Fehler gemacht bei der HTTP Definition. Welcher dan ausser Kontrolle geraten ist.
-Ist nur ein Erfahrungsbericht. Bin offen für Feedback.
Der Voice Crack bei 4:04 passt einfach zu gut :D
[gr] Stimmt 🤣
Diese Diskussion hatte ich bereits mit so vielen Entwicklern. GraphQL bietet da den Perfekten weg. (kein Fan Boy :P)
[gr] Den Satz würde ich genau so unterschreiben (und ja, ich bin auch kein übermäßig großer Fan von GraphQL).
Oft spielt es ja für den Client keine Rolle, ob der Request fachlich oder technisch nicht korrekt war. Das Ergebnis ist in beiden Fällen gleich, der Client muss mit einem fehlerhaften Request zurecht kommen. Einen 404er finde ich deswegen nicht falsch. Zu dem anderen Punkte, dass man mehrere unterschiedliche Daten auf einen Request bekommt: Das ist meiner Meinung nach eine falsch designte Schnittstelle. REST hat ja genau die Idee: dass jede Adresse genau eine Ressource abbildet. Ich finde es übrigens mutig zu sagen, dass der Großteil der Entwickler REST falsch versteht und anwendet.
Die eigentlich wichtigste Frage für den 404 Fall hat bisher noch keiner gestellt: Woher hat der Aufrufer die URI und ist die Quelle dieser URI evtl fehlerhaft, weil veraltet?
[gr] Ja, guter Punkt - und ich würde sagen, darauf gibt es eine ganze Reihe von Antwortmöglichkeiten:
- Entwickler:in hat sich vertippt
- Veralteter Link
- Fehler beim Zusammenbau der URL
- Fehler beim Redirect (falsche Angabe des Location-Headers, wobei das letztlich auf die vorigen drei Gründe zurückfällt, nur an anderer Stelle)
- Server hat temporäre Probleme und findet URL nicht
- …
Also alles Fehler, auf die ein Entwickler bzw. sein Team eigentlich reagieren und die Ursache beheben sollte. Warum dann dafür verschiedene Statuscodes verwenden? 404 ist von gelegentlichen eventual consistency Problemen abgesehen ein Fall, der fachlich nicht auftreten sollte.
Wer diese Antwort regelmäßig bekommt, arbeitet entweder mit stark veralteten Daten (bspw. aufgrund der Verwendung von batch imports statt event streaming) oder hat tatsächlich irgendwo ein Konfigurations- bzw. Codeproblem. Beides sind technische Probleme, die keine fachliche Relevanz haben.
Dem kann ich aus Erfahrung nur beipflichten. Network / Http Errors und Businesslogic Errors sollte man unbedingt trennen!
[gr] Danke schön 😊
Klingt erst mal charmant aber die Regel zum erkennen ob http Fehler oder nicht ist evtl zu streng. Was ist bei 500ern? Wenn ich z.B als Api-Entwickler Probleme habe meine interne Persistenz zu erreichen, hätte ich das Problem ja unabhängig davon ob ich auf http antworte oder etwas anderes. Wäre also ein 200er und ich müsste einen extra Fehler im Body codieren (Weil die Route gibt es ja)?
Das fänden meine Devops und Sysadmins nicht so toll wenn sie für ihr Monitoring erst Bodys parsen muss um 500er-like Fehler schnell zu erkennen.
Ich befürchte das ist in der Praxis oft ein Kompromiss zwischen ganz verschiedenen Instanzen. Und ja, ich hab mich da auch schon oft verzettelt. Weiß also auch nicht die eine Lösung für alles. :D
Danke für das Video. Dieses Thema ärgert mich schon seit Jahren.
Wo ich auch drüber nachdenke:
Müsste man bei dem Thema nicht auch die Requestmethode mit einbeziehen? Macht es da dann überhaupt Sinn die Semantik auf die Transportschicht zu ziehen, wenn ich beim Response nur noch die technische Verbindung betrachte? 🤔
Ich bin mir da, im Gegensatz zu den Statuscodes nicht so sicher… ich glaube aber, dass es konsequent wäre.
Was meint ihr?
Sehr gut. Gerade habe ich eine neue API entworfen und merke das ich mir keine wirkliche Gedanken um die HTTP-Status-Codes gemacht habe. Ich sehe es genauso das ein Status 200 immer richtig ist, egal zu welchem Ergebnis es kommt. Statt gesuchter Werte, kommt halt "Keine Daten", "Nichts gefunden" oder sowas. Ein 404 ist dafür da, das unbekannte Routen abgefangen werden. 307, 308 kannte ich bisher nicht. 302 kenne ich und nutze für Umleitungen. Schöner Beitrag und danke dafür.
Den Gedanken kann ich nachvollziehen. In der Praxis bedeutet das aber eben auch den Overhead, ein eignes gut durchdachtes Fehlerhandling zu bauen.
Mein Gefühl ist, dass diese angestrebte Trennung zwar vielleicht theoretisch korrekt ist, die Komplexität aber erhöht und Zeit kostet. Zumindest in einem Projekt an dem ich mitarbeiten „durfte“, war das Fehlerhandling dann ganz furchtbar umgesetzt (im Client überall dupliziertes String matching, kein Interceptor o.ä., kein zwischen Server und Client geteilter Code etc.).
Ist Authentifizierung und Autorisierung fachlich oder technisch zu sehen?
Genau diese Unterscheidung von technisch und fachlich forciere ich auch und ist im Frontend auch viel besser zu händeln, geht etwas technisch schief, dann gibt es ein Popup und der Anwender kann sich allenfalls an den Support wenden, hat sich der Anwender vertippt, wird was nicht gefunden, ist die Validierung nicht durchgelaufen oder fehlt die Berechtigung, dann kann ich dem Anwender die Information weitergeben und der Anwender kann auch darauf reagieren. Das nichts gefunden wird, kann man auch ganz einfach mit einen leer zurückgegeben Objekt sagen. Bei uns hat aber generell jeder Antwort neben den angeforderten Daten auch einen separaten Status und gegebenenfalls eine Errormessage.
Was wenn eine Website (wie zB WordPress) erst mal alle Requests annimmt? Sollte man dann für nicht gefundene Inhalte trotzdem den Statuscode 200 verwenden und dann das crawlen dieser Seite durch andere Techniken verhindern?
Also ich gehe immer mehr dazu über bei REST(ful)-APIs die etwas komplexer sind, Antworten auf GET-Requests, wenn es sich um JSON-Ressourcen handelt, immer mit einem Array zu beantworten und zwar auch bei Single-Ressourcen. Ein leeres Array ist gleichbedeutend mit dem dass eine Ressource nicht gefunden wurde. Und es hat den Vorteil, dass man nur eine einzige Art der Deserialisierung haben muss. Zusätzlich gibt es einen einheitlichen Wrapper bei dem dann neben den eigentlichen JSON-Ressourcen auch noch fachliche Meta-Daten und fachliche Fehler-Daten zurückgegeben werden können. Viele REST(ful) APIs benutzen die Status-Codes entweder falsch oder vermischen halt fachliche Fehler mit HTTP-Fehlern. Ich finde, dass das bei reinen CRUD-Daten-APIs nicht so schlimm ist, aber bei etwas komplexeren APIs oft auch schon die HTTP-Verben im Request falsch benutzt werden. Oft macht es mehr Sinn, RPC-Anfragen zu schreiben und diese einfach mit einem POST zu schicken. Und oft macht es auch Sinn das Verändern von Daten komplett vom Lesen zu entkoppeln und mit Commands die einen sprechenden fachlichen Namen haben zu arbeiten. Dann ist auch der dahinterliegende Intention einer Änderung der Daten nachvollziehbar. Bei einem PUT-Request, bei dem immer die komplette Ressource geschickt wird, ist das nachher eher schwer nachvollziehbar, warum die Daten geändert wurden. Ich finde da CQRS einen interessanten Architekturansatz, der aber auch nicht überall paßt, jedoch das Lesen und Schreiben modelltechnisch komplett trennt.
Wann würde ich denn bei dieser Trennung z.B. ein 201 senden?
[gr] Ich persönlich würde vermutlich gar kein 201 schicken - oder bestenfalls dann, wenn es keine Antwort gibt, außer dass etwas empfangen wurde (wobei man da IMHO auch genauso gut die 200 nehmen kann).
Mir ist gerade eine Idee eingefallen, wie man das lösen könnte: zusammengesetzte Statuscodes. Beispiel:
200/404: Anfrage erfolgreich, Daten nicht gedundeb
[gr] Das ist eine interessante Idee - wobei das immer noch nicht mit Listen von Entitäten funktionieren würde.
Also Beispiel: Du forderst fünf Objekte an. Die Anfrage funktioniert (technisch), also 200, und der der fünf Objekte können auch geladen werden, aber bei zweien fehlen Dir die Zugriffsrechte. Das müsste dann so was sein wie 200/[200,200,401,200,401] …😉
@@thenativeweb na ja, die Idee kam mir wirklich sehr spontan. Habe nicht so sehr darüber nachgedacht.
Wie wäre es denn zb beim Statuscode forbidden. Angenommen ein Benutzer hat eine bestimmte Berechtigung nicht, darf die Software aber generell benutzen... Würde man dann auch 200 zurück geben und im Body ein "eigenes" Protokoll definieren, was sagt: Keine Berechtigung?
Wir verwenden HTTP-Statuscodes zwar ähnlich, aber im Grunde leiten wir in der Auswertung der Statuscodes daran nur ab, ob ein Fehler aufgetreten ist, oder nicht. Also wenn es ein 4xx oder 5xx Code ist, ist es für uns erstmal ein beliebiger Fehler. Im Fehlerfall liefern wir aber im Response-Body eine entsprechende Fehlerbeschreibung mit aussagekräftigen Error-Codes. Wir versuchen zwar natürlich auch, die HTTP-Codes entsprechend zu setzen, aber für die Fehlerauswertung sind sie (in den meisten Fällen) nicht explizit relevant.
Seehr gutes Video! Danke!
[gr] Vielen Dank 😊
Top Content, nur leider immer noch etwas zu leise im Vergleich zu den meisten anderen Y! Videos.
Wenn man es nur nach fachlicher/technischer Hinsicht trennt und nur bei technischen Fehlern Http-Statuscodes nutzen soll, wann erhält man dann z.B. eine 401? Denn ist es nicht auch ein fachlicher Fehler, wenn die übermittelten Credentials nicht mit den hinterlegten übereinstimmen? Dann sollte es ja niemals eine 401 (technischer Fehler) geben.
Ich verstehe die Gedankengänge, aber so richtig überzeugt mich das bei der Vielzahl und der dazugehörigen Erklärungen der Http-Statuscodes nicht.
Und GraphQL als positives Beispiel hervorzuheben finde ich auch fraglich, da es in so vieler Hinsicht falsch macht. Aber das ist ein anderes Thema.
Vielen Dank für dein Video, alles ist schlecht ok .
Nun wo finde ich eine bessere Möglichkeit um Fehler für ;variable ohne Inhalt , böse Zeichen in variable oder variable zu lang ' ... Meldungen die auch etwas aussagen von der api zu bekommen, habe versucht mir einen anderen Zahlenraum 600+ zu setzen die werden aber vom Browser einfach nicht durchgeschaltet, bin am Überlegen ob ich einen Handler zwischen schalte und über JSON auch die Fehler klar definiere und dann abfange bevor es weitergeht. Doppelte Variablen Überpüfung möchte ich vermeiden. welcher Weg macht nun wirklich Sinn.
[gr] Wie im Video erwähnt - wenn Du soweit gekommen bist, dass Du erkennst, dass zB ein Feld einen ungültigen Wert enthält, dann hat die Anfrage auf technischer Ebene (also aus Sicht der Transportschicht) ja bereits funktioniert. Insofern gibst Du einen 200 zurück, und im Response-Body eine Struktur, die den Fehler beschreibt.
@@thenativeweb, ihre Antwort findet fruchtbaren Boden. Im Selbststudium bin ich dabei eine eigene
API-Struktur zu erstellen, um grundlegendes zu vertiefen. Es ist zwar recht gut was an Tutorials zu finden ist, doch manchmal hechtet man von einer super programmier-Form bzw.-Konzept zum Nächten. Was einem sein Projekt dann mehrfach komplett umbauen lässt, bis eine einfach strukturierte form verbleibt, die dann auch noch nach Monaten nachvollziehbar bleibt.
Leider wird Dieses Wissen nicht immer sauber vermittelt und muss über den langen weg erarbeitet werden. Vielen dank für deine Videos
Ich finde beide Wege in Ordnung: Wenn die Anwendung nur HTTP anbietet, finde ich es legitim, das Statushandling über HTTP zu machen. Also z.B. 401=nicht erlaubt oder 204=keine Daten. Oder 404. Das hat auch große Vorteile bei Anwendungen, die HTTP benutzen. Beispiel: Curl liefert einen RC != 0 zurück, wenn Status != 2xx,3xx so kann man per Bash einfach den Status verarbeiten. Falls das eigene Protokoll selber einen Status verwaltet kann man das natürlich auch machen und immer HTTP 200 zurückliefern. Allerdings muss der Client dann das interne Wissen über die Status der Anwendung haben. Bei HTTP 5xx ist halt klar, das ein Fehler auftritt. Wenn die Anwendung aber den eigenen Status 56789 definiert, dann muss der Client all dieses Wissen in sich tragen. Beide Lösungen haben ihre Vorteile.
Sofern die HTTP-Status aussagekräftig genug sind, würde ich diese auch nutzen. WebDAV macht es ja auch so.
Ich persönlich nutzte die im Grunde technisch. BadRequest für fehlerhafte requests (unter anderem auch wenn eine resource nicht gefunden wurde) Bswp.
Ein Problem hab ich jedoch mit unauthorized... Theoretisch sollte dieser ja kommen, wenn der Zugriff auf einen Endpunkt nicht erlaubt ist. Allerdings verwässert das die Sicherheit, weswegen ich in solchen Fällen 404 zurück gebe. Gefällt mir eigentlich nicht... Erlaubt aber, dass bei korrekt eingerichteter Software, der Endpunkt nur denen verfügbar ist, die das ganze auch benutzen dürfen.
Vielen Dank für den Beitrag. Ich hatte schon mehrfach die Diskussion mit meinen Kollegen. Vor allem um 404. Am Ende hatte sich bei uns 404 durchgesetzt, wenn für eine Anfrage fachlich keine Antwort möglich war. Meine Vorschläge:
- HTTP-Status 204 no content
- Rückgabe von null
- leere Liste
wurden von der Gruppe abgelehnt. Für den Vorschlag Status 204 zu nutzen, wurde ich regelrecht ausgebuht. Dazu zwei Fragen:
1) Status 204. Wann sollte/könnte man ihn nutzen?
2) Gibt es Regeln, welcher Status bei welchen Request-Methoden (PUT, POST, GET, usw.) verwendet/nicht verwendet werden sollte?
Zu 1) Wir benutzen den 204 Status Code oft als Folge für einem erfolgreichen DELETE-Request.
Zu 2) Nun ja, GET Requests haben keinen Body, also alle Status-Codes, welche irgendetwas mit der Verarbeitung eines Request-Bodys zu tun haben, wären hier fehl am Platze...
Gerade mal geguckt, wann die Error-Section in einem AJAX-Call geTriggert wird... ist auch eine Frage, wie es im Client vom Entwickler gedacht war/wird/ist.
Vielen Dank für den Beitrag, tatsächlich sind HTTP codes immer wieder in Projekten ein Diskussionsthema. Ich habe aber auch gesehen, dass es viele Probleme gab, eine geeignete Fehlerdatenstruktur zu finden. IMHO nimmt man ja gerne die HTTP codes um sich vor so einer Designentscheidung zu drücken:-)
Als Lösung habe ich jetzt schon mehrmals gute Erfahrung mit dem RFC 7807 gemacht: Ein flexibler Standard für fachliche Fehler und tatsächlich schon einige Bibliotheken, die es unterstützen ohne das Rad (parsen, (de-)serializieren,...) immer wieder neu zu erfinden. Was hast du denn für Erfahrungen gemacht mit Fehlerdatenstrukturen in HTTP APIs? Eher custom oder standards? Wenn Standards, welche?
Zum einen gebe ich dir da vollkommen Recht. Aber hier ist es klar von der Interpretation der Definitionen abhängig. Ist ein Script am Ende eine Ressource (technisch) oder erst die primären Daten/die Anwendung/das erwartete spezifische Ergebnis (fachlich), die vom Script einer URL zurückgeliefert wird? Gerade bei letzterem kann ich den Drang zur Nutzung des Codes 404 durchaus verstehen. Da fällt am Ende eine Trennung zwischen technischen Statis und den fachlichen recht schwer, wenn auf Seiten des Clients in beiden Fällen nichts für den Nutzer herausspringt und auch technisch nichts verwertbares geliefert wird. Aber wie du schon sagtest verliert man dadurch die Möglichkeit, auf das HTTP-Protokoll zu verzichten, da man die Client-Applikation und dessen Verhaltensweisen direkt auch an das Trägerprotokoll geknüpft hat.
Ich denke, das wir hier aber auch von einem ganz spezifischen Ausgangspunkt reden, der auf Grund der und unserer Entwicklung nachvollziehbar ist. Das Web bestand zu Anfang nur aus reinen Ressourcen. Mit Einführung dynamischer Webinhalte begann schon die Frage danach, ob jetzt mit einer Ressource das Script selbst oder das Ergebnis dieses gemeint ist. Aber auch hier fand man früh eine klare Antwort darauf. Denn zu beginn dynamischer Inhalte waren Anwendungen, die diese erzeugten vorzugsweise Monolithen, bei denen die einzelnen technischen Stationen und ihrer Abarbeitung der Anfragen klar definiert waren. Der Server bekam die Anfrage vom Browser, leitete das ans Script weiter, dieses verarbeitete alles und lieferte dann das fertig erzeugte DOM an den Browser. Es gab also über sehr lange Zeit den Server und den Browser und kommuniziert wurde nun einmal über HTTP. Somit wurde das Trägerprotokoll der Einfachheit halber auch als Anwendungsprotokoll genutzt. Da spielte eine Trennung zwischen einer technischen und fachlichen Ebene keine große Rolle. Denn man ging vor allem bei Monolithen als Entwickler einfach davon aus, das die Anfragen von einem Browser kommen, das Ergebnis an einen Browser geliefert werden und das einzige Protokoll in dieser Kommunikation HTTP sein wird.
Mit REST und mobilen Anwendungen als Clients wurde dann das Zeitalter der Entkopplung begonnen. REST war allerdings gefühlt ein Versuch der Erweiterung (oder des Umbiegens?) des HTTP-Protokolls. Das war auch damals die Zeit, in der ich meine Lust ans Web völlig verloren hatte. Das war die Zeit, in der ich mir die Frage nach dem Warum gestellt habe. Warum ist REST so ... wie es ist. Ich habe es gehasst. Und das ging definitiv nicht nur mir so. Man fühlte sich durch den Quasi-Standard völlig in die Ecke gedrängt .... ich schweife ab .... das gehört hier nicht hin *aufdenhinterkopfschlag*. Auf jeden Fall gab es beim Aufkommen von REST einfach nicht das Mindset dafür, eine Trennung von HTTP und Anwendung in Betracht zu ziehen, weil REST nun einmal das HTTP-Protokoll voraussetzt und dessen Header auch aktiv bei der Implementierung von Anwendungen mit einbezieht. Auch hier wäre eine Trennung garnicht richtig sinnvoll. Denn laut Definition von Rest (wie du auch anmerktest) bildet jede URI eine spezifische Ressource ab. Und somit ist es gehüpft wie gesprungen, ob im Falle einer fehlenden Ressource 404 zurückgeliefert wird oder eine Anwendungsspezifische Meldung. Denn REST setzt HTTP voraus und der Client muss dann auch HTTP beherrschen. Und dadurch konnte man sich auch auf HTTP und dessen Statuscodes verlassen.
Aber wie schon immer gewesen ändern sich nun einmal die Zeiten (Wissenschaft und Entwicklung sei dank) und mittlerweile wird immer häufiger erkannt, das es doch sinnvoller wäre (vor allem bei der Entkopplung), ein Anwendungsprotokoll für die fachlichen Statis sowie auch der Datenaufbereitung zu verwenden und den technischen Teil das jeweilige Trägerprotokoll machen zu lassen. Ich kann mich noch gut daran erinnern, als ich für Purebasic selbst ein Anwendungsprotokoll definieren musste, weil es ewig gedauert hat, über die HTTP-Bibliothek spezifische Header zu setzen oder auslesen zu können. War witzig. Die Entwickler waren voll Stolz, das deren HTTP-Lib kompatibel zu REST war ... Nur eben nicht mit JWT ... Blöd xD
Und was hatte ich damit auf einmal für Möglichkeiten, REST einfach in diesem Zuge zu ignorieren, weil sich das Anwendungsprotokoll darum kümmerte ... Herrlich :)
FAZIT: Das wird sich noch ändern. Keine Sorge. Neue Standards und neue Mindsets sind schnell formuliert, verbreitet und ausreichend begründet. Aber bis die Gedanken auch bei allen endgültig zünden, dauert es eine Weile. Das Video hat aber dazu beigetragen, den Leuten ein "es muss anders gehen" Gefühl zu geben und ihren eigenen Umgang mit diesem Thema zu reflektieren. Aber historisch bedingt (und vor allem in Anbetracht der Art und Weise, wie sich das Web entwickelt hat) muss man den Entwicklern auch eine gewisse Zeit lassen. Für viele begann der Ein- bzw. Umstieg von Monolithen zu entkoppelten Systemen vor nicht allzu langer Zeit und es ist üblich erst auf Rest zu stoßen, da es noch immer gefühlt allgegenwertig ist. Vor allem, wenn sie das Web noch so sehen, wie es vor über 10 Jahren war und nicht wie es jetzt ist oder es sein könnte. Das wird schon noch ;)
Wir benutzen die Status Codes RESTful und somit auch fachlich. Wir fragen die Resourcen per Path-Variable ab, wodurch "Resource not found" wieder stimmt. Aber wir hatten eben die gleiche Diskussion auch.
[gr] Das Wichtigste ist am Ende IMHO, dass man eine bewusste Entscheidung trifft, und es nicht "einfach so" und "irgendwie" macht, insofern habt Ihr doch alles richtig gemacht 😊
Bin da letztens auf die schnauze gefallen: wole Daten über eine API ziehen und wundere mich, warum meine Dateien Schrott waren. Hab mich auf die Status Codes verlassen... Ja... HTTP 200, aber die Meldung "no item found"... Aber ja, technisch gesehen ist das ja korrekt
Ich habe mich sogar schon mal über eine Schnittstelle geärgert, die fachliche Fehler nicht über den Statuscode abgebildet hat 😂. Aber du hast völlig recht.
Tolles Video (und Kanal insgesamt), vielen Dank.
Wäre z.B. der Status Code - 422 Unprocessable Entity - eine sinnvolle und logische Alternative um das fachliche Problem bei invaliden Requests auf HTTP Ebene anzudeuten?
Vielleicht hat ja schon jemand damit schon Erfahrungen und User Feedback gesammelt.
Ich weiß das z.B. FastAPI (API Framework für Python) diesen Status Codes bei invaliden Requests nutzt und finde ihn recht passend für das beschriebene Problem.
Bei REST wird ja nicht nur der Statuscode Zweckentfremdet, sondern das ganze http Protokoll (get with body, delete with body, create = post). Das ganze Konzept ist schon an sich schräg. Um ein Minimum an overhead zu haben ist es brauchbar, aber um eine gute Schnittstelle zu definieren ist es das nicht.
Bei REST wird das HTTP Protokoll nicht zweckentfremdet, sondern REST ist eine "Anleitung" dafür, die Intention des Protokolls zu erfüllen und damit seine Stärken zu nutzen.
Es lohnt sich, die Dissertation von Roy Fieldings zu lesen, die den Begriff REST eingeführt hat.
Ohne die gelesen und verstanden zu haben, finde ich es gewagt, das Konzept zu beurteilen.
Top!
[gr] Danke schön 😊
Die Denke kann nur entstehen, wenn man RPC macht und HTTP bloß als Transportvehikel nutzt.
Sind wir ehrlich, jedes tolle REST endet irgendwann zumindest teilweise in RPC
@@_nikeee allerdings ;) (schwitz)
Ich denke REST ist wie SCRUM oder OOP - viele "machen" es aber keiner wirklich nach Definition.
@ Nun ja, die Definition ist teilweise aber auch unvollständig und kann so oder so ausgelegt werden. Für reine CRUD-Daten-APIs kann man durchaus eine sehr puristische REST-API bauen. Allerdings schränken meiner Meinung nach gerade bei komplexeren fachlichen APIs das zwanghafte mappen auf HTTP-Verben die eigentliche Fachlogik massiv ein und verwässern die dahinterliegende fachliche Intention einer Datenänderung.
Für meine Begriffe gibt es keinen Fall, in dem mehrere Ressourcen in einer Antwort verarbeitet werden. Eine Liste von mehreren bspw. Datensätzen ist eine Ressource. Daher sehe ich die Argumentation als falsch an.
Ich musste sehr schmerzhaft feststellen, dass einer unserer Services bei nicht gefundenem Datensatz, auf ein GET "../x/y?filter=value" 404 zurückgab. Dabei habe ich Stunden nach Problemen im Proxy gesucht. Wenn die Fehlermeldung doch wenigstens sinnvoller als "not found" wäre...