Der Server schrieb deutsche Sätze an eine Stelle, die niemand liest

„Die Anfrage war so nicht zu gebrauchen" — das ist der Ersatzsatz des
Browsers für eine Ablehnung ohne Begründung. Dabei stand die Begründung
da: „Benutzername darf nicht leer sein, das Passwort braucht mindestens 8
Zeichen." Nur eben in `errors`, und beide Clients lesen `detail`.

Zwei Formen waren betroffen. `Results.ValidationProblem` legt den Satz
unter `errors` ab, `Results.BadRequest(new { fehler = … })` unter
`fehler` — in beiden Fällen kommt er nirgends an. Zusammen 36 Stellen,
darunter jede Zeile, die ich gestern für die Meldungen geschrieben habe.
Dass die Clients `title` und `errors` auslassen, ist dabei richtig: dort
stehen sonst die englischen Prüftexte des Rahmenwerks, und „Not Found" ist
keine Auskunft.

Jetzt eine Form, hinter `Einwand.Bitte` / `.Fehlt` / `.Belegt`. Dass es
drei benannte Türen sind statt eines Aufrufs mit Zahl, hat einen Grund:
man sieht am Wort, ob der Server um eine bessere Eingabe bittet, etwas
nicht findet oder auf etwas Bestehendes stösst.

**Auffallen konnte es nicht**, und das ist der eigentliche Fund. Die
vorhandenen Tests prüften den Rumpf als Zeichenkette — der Satz *stand* ja
drin, nur im falschen Feld. Der neue Test prüft deshalb, in welchem Feld,
und ein Wächter am Quelltext schlägt an, wenn eine der beiden alten Formen
zurückkommt. Er hat beim ersten Lauf gleich eine Stelle gefunden, die mein
Suchmuster übersehen hatte.

Dazu drei Kleinigkeiten, die beim Lesen auffielen:

**Passwörter wurden getrimmt.** Der Dialog schnitt jedem Feld die Ränder
ab, auch dem Passwort — `login.ts` sendet es ungeschoren. Ein Leerzeichen
am Ende, und das angelegte Konto war für immer unbetretbar.

**Beim Einrichten stapelten sich die Fehlerzeilen**, weil `.error`
weggeräumt wurde und `.fehler` entsteht. Drei Fehlversuche, drei rote
Kästen.

**Der Benutzerdialog versprach acht Zeichen und prüfte nichts.** Jetzt
sagt er es selbst, ohne den Umweg über die Leitung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-07 17:12:57 +02:00
co-authored by Claude Opus 5
parent 7cd48f5528
commit 8e9da1355c
15 changed files with 248 additions and 81 deletions
@@ -40,16 +40,10 @@ public static class MatchEndpoints
var titel = anfrage.Title?.Trim();
if (string.IsNullOrEmpty(titel))
{
return Results.ValidationProblem(new Dictionary<string, string[]>
{
["title"] = ["Ein Titel darf nicht leer sein."],
});
return Einwand.Bitte("Ein Titel darf nicht leer sein.");
}
if (titel.Length > 512)
return Results.ValidationProblem(new Dictionary<string, string[]>
{
["title"] = ["Höchstens 512 Zeichen."],
});
return Einwand.Bitte("Höchstens 512 Zeichen.");
// **Der Sortiertitel bleibt, wenn er von Hand gesetzt wurde.**
// Sonst wäre „Harry Potter 3" nach jeder Titeländerung wieder weg.
@@ -84,8 +78,7 @@ public static class MatchEndpoints
statusCode: StatusCodes.Status400BadRequest);
}
if (sortiert.Length > 512)
return Results.Problem("Höchstens 512 Zeichen.",
statusCode: StatusCodes.Status400BadRequest);
return Einwand.Bitte("Höchstens 512 Zeichen.");
var betroffen = art == "movies"
? await db.Movies.Where(m => m.Id == id).ExecuteUpdateAsync(s => s
@@ -283,8 +276,7 @@ public static class MatchEndpoints
var gefunden = await anbieter.GetMovieAsync(anfrage.TmdbId);
if (gefunden is null)
return Results.Problem($"TMDB kennt den Film {anfrage.TmdbId} nicht.",
statusCode: StatusCodes.Status404NotFound);
return Einwand.Fehlt($"TMDB kennt den Film {anfrage.TmdbId} nicht.");
// **Hat die Kennung schon jemand, ist es derselbe Film.**
//
@@ -343,8 +335,7 @@ public static class MatchEndpoints
var gefunden = await anbieter.GetSeriesAsync(anfrage.TmdbId);
if (gefunden is null)
return Results.Problem($"TMDB kennt die Serie {anfrage.TmdbId} nicht.",
statusCode: StatusCodes.Status404NotFound);
return Einwand.Fehlt($"TMDB kennt die Serie {anfrage.TmdbId} nicht.");
// Siehe bei den Filmen: dieselbe Kennung heisst dieselbe Serie,
// und zwei Ordner derselben Serie gehören zusammengelegt.