Einführung
Beschriftungen, bedingte Sitzplatznotiz und responsives Layout von Still & Spoke sind vorbereitet. Der aktuelle Handler kann eine Demo-Bestätigung anzeigen, ohne eine Buchung zu senden. Du ersetzt ihn durch eine echte asynchrone Anfrage und Rückmeldungen, die die tatsächliche Annahme des Studios widerspiegeln. Eine korrekt aussehende Seite ist erst eine Buchung, wenn der vorbereitete Dienst seine Bestätigung liefert.
Du benötigst HTML-Formulare, grundlegendes CSS-Layout sowie JavaScript-Objekte, Funktionen, DOM-Auswahl und Ereignisse. Dieses Lab vermittelt JSON, async/await, fetch, HTTP-Ergebnisse, Wartezustand und Rückmeldungen mit Wiederherstellungsmöglichkeit. Semantik und bedingte Regeln sind vorbereitet; das vorherige Lab hilft, seine VM-Dateien sind aber unnötig. Ändere nur /home/labex/project/stillspoke/request.js und feedback.js. Erhalte andere Frontenddateien, API, Kapazität und Besucher. Alle Identitäten sind synthetisch; keine E-Mail oder Zahlung wird ausgelöst. Die 60 Minuten sind eine Autorenschätzung, kein gemessenes Anfängerergebnis.
Nutze Workspace für vollständige Dateiersetzungen und Studio für die Website. Study form ist ein unabhängiges funktionierendes Beispiel; seine Buchungen vervollständigen die Arbeitsseite nie. Studio records liest akzeptierte Buchungen. Practice room ist eine getrennte Trainingsseite, die eine Anfrage vor jeder Annahme ablehnen kann. Jedes Lab beginnt mit eigenen Daten. Es lehrt weder den vorbereiteten Backendaufbau noch Produktionsdeployment, Idempotenz beliebiger Anfragen oder vollständige Barrierefreiheitskonformität.
Sende eine echte Anfrage und warte auf die Antwort
Ersetze in diesem Schritt den Demo-Handler durch einen echten POST, verhindere doppelte Aktivierung während der Wartezeit und zeige eine echte Serverbestätigung.
Wähle in Studio Study form. Gehe mit Tab zu Your name und gib Example Guest ein; Tab zu Email, dann sample@example.test; Tab zu Session, tippe C und lies Clay, slowly / 10:00. Gehe mit Tab am ungewählten Hilfekästchen und der optionalen Notiz vorbei zu Reserve my place. Drücke einmal Enter. Warte auf die echte Confirmation SS-…, wähle Studio records und gleiche Name, E-Mail und Uhrzeit ab. Kehre über Back to signup und Work form zurück. Das Beispiel nutzt eine eigene Datenbank. Deine Arbeitsseite enthält nur die vorhandenen Besucher; ihr Demotext beweist keine Annahme.
Das Beispiel zeigt das erwartete sichtbare Ergebnis: eine Bestätigung mit eigener Überschrift und lesbarer Zeit. Deine Nummer ist anders.

Die vorbereitete API gehört zur lokalen Umgebung. Ihre öffentlichen Felder und Regeln lauten:
| JSON-Feld | Bedeutung |
|---|---|
name |
Mindestens zwei Zeichen nach Entfernen äußerer Leerzeichen. |
email |
Synthetische Adresse mit Endung @example.test. Der Browser prüft zuerst native Syntax. |
session |
Gelistete stabile ID: clay-morning für 10:00 oder clay-afternoon für 14:00. Nachmittags ist bereits voll. |
support |
Boolescher Wert für ausgewählte Sitzplatzhilfe. |
note |
Zeichenfolge mit mindestens fünf Zeichen bei Hilfe, sonst optional. |
Ein POST sendet einen Buchungsvorschlag an api/bookings. Dies ist eine relative URL unter der aktuellen Arbeits- oder Beispielseite; beide bleiben in ihrem Geschäftsbereich. Die API liefert JSON, ein Textformat für Objekte, Zeichenfolgen, Zahlen und boolesche Werte. Eigenschaftsnamen und JSON-Strings stehen in doppelten Anführungszeichen. JSON.stringify(data) macht aus dem JavaScript-Objekt JSON-Text; response.json() analysiert die Antwort wieder als Objekt. Der Header Content-Type: application/json beschreibt den Anfrageinhalt. Weder Frontendtext noch deaktivierter Button implementieren die Kapazitätsregel des Dienstes.
HTTP-Status unterscheiden die Ergebnisse:
| Status | Antwort und bewiesener Sachverhalt |
|---|---|
201 |
booking enthält akzeptierte Felder, lesbaren sessionTitle und servergenerierte id. Eine Buchung wurde angenommen; die Nummer beginnt mit SS-. Erfinde sie niemals. |
422 |
errors ordnet Feldnamen Erklärungen zu. Nichts gebucht; markierte Felder korrigieren. |
409 |
Termin voll. Nichts gebucht; verfügbaren Termin wählen. |
503 |
Die kontrollierte Trainingspause lehnt vor der Annahme ab. Nichts gebucht; Wiederholung ist sicher. |
fetch liefert eine Promise, die für ein späteres Ergebnis steht. Ein async-Handler kann mit await seine eigene Arbeit bis zum Erfolg oder Fehlschlag der Promise aussetzen, während der Browser nutzbar bleibt. Warte erst auf HTTP, dann auf die JSON-Analyse. Eine HTTP-Ablehnung wie 422 oder 503 erfüllt fetch ebenfalls; sie führt nicht automatisch in catch. Prüfe den Status ausdrücklich. Netzwerk- oder Analysefehler können catch erreichen, ohne zu beweisen, ob die Buchung angenommen wurde. Die Meldung muss unbekannte Annahme nennen und auf Studio records zur Klärung verweisen.
Das Formularereignis submit deckt Buttonaktivierung und Enter im Feld ab. event.preventDefault() verhindert die normale Navigation, damit der Handler JSON senden kann. Nativ ungültige Felder stoppen das Absenden, bevor das Ereignis den Handler erreicht. form.elements sucht über name, nicht sichtbare Reihenfolge oder HTML-id. Textfelder nutzen .value, das Kästchen .checked.
Setze pending vor jeder Warteoperation. Die Schutzabfrage kehrt früh zurück, wenn währenddessen ein weiteres Submit-Ereignis eintrifft; .disabled deaktiviert den nativen Button sichtbar. Das verhindert mehrfache Aktivierung dieser Seite während einer laufenden Anfrage, garantiert aber nichts für andere Seiten oder beliebige gleichzeitige Clients. try führt die Anfrage aus; catch meldet bei Fehlern unbekannte Annahme; finally aktiviert den Button und leert die passive Meldung in jedem Fall. Erhalte die Werte, statt das Formular zurückzusetzen.
clearErrors, showMessage und showResponse sind Funktionen in feedback.js. Die Seite lädt nach dem HTML-Parsing mit defer nacheinander scenario.js, validity.js, feedback.js und request.js. Die erste Datei liefert Daten, die zweite die native Bedingung, die letzten beiden kooperieren für Anfrage und Rückmeldung. Die aktuelle Rückmeldung verarbeitet einen normalen 201; Feldablehnungen verbesserst du als Nächstes.
Wähle in Workspace mit cd das Verzeichnis. cat > request.js ersetzt nur diese Datei. Der zitierte Here-Dokument-Marker JS hält den Inhalt wörtlich bis zur letzten Zeile mit nur JS; füge den ganzen Block ohne Markdown-Backticks ein. Mit der zurückgekehrten Eingabeaufforderung ist die Datei gespeichert.
cd /home/labex/project/stillspoke
cat > request.js <<'JS'
const form = document.querySelector('form');
const reserveButton = form.querySelector('[type="submit"]');
const progress = document.querySelector('#progress');
let pending = false;
form.addEventListener('submit', async (event) => {
event.preventDefault();
if (pending) return;
clearErrors();
document.querySelector('#result').hidden = true;
const data = {
name: form.elements.name.value,
email: form.elements.email.value,
session: form.elements.session.value,
support: form.elements.support.checked,
note: form.elements.note.value
};
pending = true;
reserveButton.disabled = true;
progress.textContent = 'Sending your request...';
try {
const response = await fetch('api/bookings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const body = await response.json();
showResponse(response.status, body);
} catch (error) {
showMessage('No confirmation received. Acceptance is unknown. Check Studio records; wait for the original attempt to be resolved before a new submission.');
} finally {
pending = false;
reserveButton.disabled = false;
progress.textContent = '';
}
});
JS
Kehre zu Studio zurück, aktualisiere, gib Morgan Vale und morgan@example.test ein, wähle Clay, slowly / 10:00 und lasse Hilfe ungewählt. Gehe mit Tab zum Button und drücke einmal Enter. Während Sending your request... ist er deaktiviert. Warte, bis Submission result Reserved for Morgan Vale, eine echte Confirmation SS-… und den lesbaren 10:00-Titel zeigt. Die passive Meldung role="status" wird nie fokussiert; der gewöhnliche Ergebnisabschnitt kann den Fokus erhalten, damit Überschrift und Ergebnis leicht auffindbar sind.
Wähle Studio records, gleiche den vollständigen Eintrag ab und erhalte Existing Visitor und Avery Reed. Die alte Demo-ID darf nicht als akzeptierte Buchung erscheinen. Ein erfolgreicher HTTP-Transfer genügt nicht: Die Antwort muss tatsächlich 201 sein, und die Bestätigung muss aus ihrem angenommenen booking stammen. Selbstkontrolle: Ein echter angenommener Datensatz existiert, laufendes Senden verhindert doppelte Aktivierung und der Handler stellt den Button wieder her.
Ordne die Serverablehnung dem richtigen Feld zu
Mache in diesem Schritt aus einer echten Servervalidierungsablehnung einen lesbaren Feldfehler, ohne andere Eingaben zu löschen.
Der Browser kann fehlerhafte E-Mail-Syntax ablehnen; der Dienst hat zusätzlich die Geschäftsregel, dass Übungsadressen auf @example.test enden. morgan@other.test ist syntaktisch gültig, erreicht den Server und erzeugt HTTP 422. Das ist eine echte Anfrage und Ablehnung, anders als das native Pflichtfeldfenster.
Eine Fehlerantwort sieht so aus; dies sind Daten zum Lesen, kein Befehl:
{
"message": "Please correct the marked fields. Nothing was booked.",
"errors": {
"email": "Use an address ending in @example.test for this practice."
}
}
errors.email bezeichnet den API-Schlüssel email. Ordne ihn über form.elements[name] zu, nicht anhand der Reihenfolge oder des ersten Fehlerabsatzes. Ein Stringschlüssel in Klammern wählt die entsprechende Objekteigenschaft. Object.keys(body.errors) erzeugt ein Array der Eigenschaftsnamen; for (const name of ...) besucht jeden Namen. Eine mit let deklarierte Variable lässt sich neu zuweisen, daher merkt sich first das erste markierte Feld.
textContent zeigt Fehler und Ergebnisse als Text statt Servermeldungen als HTML zu interpretieren. aria-invalid="true" markiert ein ungültiges Feld; der verbundene Absatz email-error liefert über das vorhandene aria-describedby einen sichtbaren Grund. Ersetze dauerhafte Hilfe nicht nur durch Farbe. Das Löschen alter Fehler vor einer neuen Anfrage verhindert eine veraltete Beschreibung korrigierter Felder. Zeige bei 422 erst das Gesamtergebnis, dann fokussiere das erste markierte Eingabefeld. Bei anderen Ergebnissen kann der gewöhnliche Ergebnisabschnitt den Fokus erhalten. Die passive Live-Statusmeldung ist getrennt und sollte nicht zwangsweise fokussiert werden.
Die Erfolgsmeldung verwendet ein Template-Literal: Backticks umschließen den Text, ${booking.id} setzt den aktuellen Eigenschaftswert ein. Die entstandene Zeichenfolge zeigt textContent wörtlich. Die Bestätigung stammt aus dem Antwortobjekt, nicht einer lokal erfundenen Nummer.
Ersetze in Workspace feedback.js durch diese Funktionen:
cd /home/labex/project/stillspoke
cat > feedback.js <<'JS'
function clearErrors() {
for (const field of document.querySelectorAll('form [name]')) {
field.removeAttribute('aria-invalid');
const error = document.getElementById(field.name + '-error');
if (error) error.textContent = '';
}
}
function showMessage(text) {
const panel = document.querySelector('#result');
document.querySelector('#message').textContent = text;
panel.hidden = false;
panel.focus();
}
function showResponse(status, body) {
if (status === 201) {
const booking = body.booking;
showMessage(`Reserved for ${booking.name}. Confirmation ${booking.id}. ${booking.sessionTitle}.`);
} else if (status === 422) {
showMessage(body.message);
let first;
for (const name of Object.keys(body.errors)) {
const field = document.querySelector('form').elements[name];
document.getElementById(name + '-error').textContent = body.errors[name];
field.setAttribute('aria-invalid', 'true');
if (!first) first = field;
}
first.focus();
} else {
showMessage(body.message);
}
}
JS
Kehre zu Studio zurück, aktualisiere und gib Morgan Vale, morgan@other.test, Clay, slowly / 10:00, gewählte Hilfe und A seat near the entrance ein. Sende einmal. Du solltest die Gesamtmeldung Nothing was booked sowie einen neuen E-Mail-Fehler sehen. Der Fokus geht zu Email, Beschriftung und Hilfe bleiben sichtbar, ebenso Name, Termin, Kästchen und Notiz. Studio records darf keinen Eintrag für die abgelehnte Adresse erhalten. Zum Lesen ohne Verlassen des Entwurfs öffne den Link Studio records mit Open Link in New Tab des Browsers in einer anderen Seite und kehre zum ursprünglichen Formular zurück.
Korrigiere nur die Adresse zu morgan@example.test und sende erneut. Der alte Feldfehler verschwindet, eine echte neue Bestätigung erscheint und die Notiz gelangt in den Datensatz. Teste auch ein anderes Feld: Ersetze bei sonst gültigen Werten den Namen durch genau zwei Leerzeichen. Natives minlength="2" zählt diese getippten Zeichen; die veröffentlichte Serverregel entfernt dagegen zuerst äußere Leerzeichen und verlangt danach zwei Zeichen. Der echte 422 muss Your name markieren und fokussieren, nicht immer Email, während E-Mail, Termin und Notiz bleiben. Stelle Morgan Vale wieder her. Derselbe synthetische Name darf eine zweite angenommene Buchung erhalten; dies ist kein System für eindeutige E-Mail-Adressen. Die bisherigen Besucher bleiben.
Bei versehentlichem morgan.example.test ohne @ lehnt der Browser schon vor POST ab. Diese native Meldung ist erwartbar, testet aber nicht 422. Nutze das nativ gültige morgan@other.test, um die Serverregel zu prüfen. Bleibt die Rückmeldung nach einer Änderung unverändert, nutze cat feedback.js in Workspace, vergleiche den ganzen Block, korrigiere den Tippfehler und aktualisiere Studio. Lösche keine Daten und starte keinen Dienst neu, um einen JavaScript-Schreibfehler zu beheben. Selbstkontrolle: Der tatsächliche Serverfeldschlüssel ist mit passendem Feld und lesbarem Fehler verbunden, andere Eingaben bleiben und Korrektur sowie erneutes Senden funktionieren.
Erhole dich von vollen Terminen und einer sicheren Pause
Unterscheide in diesem Schritt einen vollen Termin von einer Ablehnung vor Annahme, erhalte den Entwurf und führe eine sichere Wiederholung aus.
Aktualisiere Studio und gib Casey Brook, casey@example.test, Clay, slowly / 14:00, ausgewählte Hilfe und A seat near the entrance ein. Lies vor dem Senden den 14:00-Titel im Selektor. Ein erstes C wählt die erste passende Clay-Option; ein weiteres wechselt zur nächsten. Lies die sichtbare Auswahl, statt von einer festen Tastenposition auszugehen.
Sende einmal. Der Dienst liefert HTTP 409, weil der Termin voll ist. Lies That session is full. Nothing was booked; choose another session. Eingaben bleiben und der Button wird wieder nutzbar. Lösche nicht den vorhandenen 14:00-Besucher, um Platz zu schaffen. 409 braucht keine ungültige E-Mail oder kaputte Anfrage; es ist die geschäftliche Ablehnung eines korrekt gebildeten Vorschlags.
Ändere nur den Termin zu Clay, slowly / 10:00. Wähle Practice room; es öffnet eine andere Seite, damit dein Formular offen bleibt. Dies ist ein Trainingsbereich getrennt vom Kundenablauf. Wähle Pause next submission und warte auf Next submission will be refused before a booking is accepted. Schließe die Trainingsseite oder kehre zum ursprünglichen Studio-Formular zurück. Ersetze den noch offenen Entwurf nicht über Back to signup auf der Trainingsseite.
Die getrennte Seite nennt die Zusage der Ablehnung vor Annahme. Lass beim Bedienen dieses Schalters das Originalformular offen.

Sende das Original einmal. Der Dienst liefert nun HTTP 503 und ausdrücklich Nothing was booked. Service paused; please retry. Name, Adresse, gewählter 10:00-Termin, Kästchen und Notiz bleiben erhalten. Diese Anfrage verbraucht die Pause. Drücke mit den erhaltenen Werten noch einmal Enter auf Reserve my place. Warte auf den echten 201 und gleiche in Studio records Casey Brook, E-Mail, 10:00 und Sitzplatznotiz ab. Vorhandene Besucher und frühere angenommene Buchungen bleiben.
Der 503-Trainingsvertrag ist eng: Er lehnt vor jeder Buchungsannahme ab, deshalb ist diese Wiederholung sicher. Verbindungsverlust oder unlesbare Antworten sind anders. catch meldet unbekannte Annahme, nicht Nothing was booked. Öffne dann Studio records in einer anderen Seite. Ein passender Datensatz kann eine Bestätigung auffinden helfen; wiederholte Namen und Werte identifizieren aber nicht immer den verursachenden Versuch. Sende nicht erneut, solange der ursprüngliche Versuch ungeklärt ist. Auch ein erfolgreiches Lesen ohne Treffer beweist keine Ablehnung: Die ursprüngliche Anfrage kann noch laufen. Warte auf deren Klärung oder frage den Studiobetreiber (hier die Lehrperson). Sind die Datensätze nicht lesbar, warte auch auf den Dienst. Nur die ausdrücklich vor Annahme erfolgte 503-Ablehnung belegt hier eine sichere Wiederholung. Dieses Lab verspricht keine Idempotenz und lehrt keinen verteilten Zahlungsablauf.
Wechsle für eine gewöhnliche Bearbeitungskorrektur zu Workspace und zeige die gespeicherte Anfragedatei:
cd /home/labex/project/stillspoke
cat request.js
Prüfe die exakte relative URL api/bookings, die Schreibweise JSON.stringify, beide await-Ausdrücke und finally. Wurde etwas vertippt, ersetze die Datei mit dem vollständigen Block aus Schritt 1 und aktualisiere Studio. Kläre vor jeder neuen Sendung frühere unbekannte Versuche nach obiger Grenze; eine Tippfehlerkorrektur allein beweist keine frühere Ablehnung. Ist der Versuch sicher geklärt, wiederhole den passenden Normaltest mit neuem synthetischem Namen. Die schreibgeschützte Prüfung installiert keinen Ersatzhandler und bucht nicht live, um die Arbeit zu reparieren.
Selbstkontrolle: Voll und Pause liefern nach dem Warten sichtbare Ergebnisse, erhalten den Entwurf, erlauben Korrektur oder sichere Wiederholung und zeigen nie erfundene Annahmenummern. Gleichwertige verständliche Formulierungen sind zulässig. Eine normale akzeptierte Buchung existiert weiterhin, die gesamte vorbereitete Kapazität und die Besucher bleiben intakt.
Zusammenfassung
Du hast JSON per POST mit abgewarteter Antwort gesendet, HTTP-Ablehnungen von Verbindungsunsicherheit unterschieden, Aktivierungen während laufender Anfragen geschützt und die tatsächliche Bestätigung angezeigt. Du hast Serverfehler den Feldern zugeordnet, Eingaben bei Vollbelegung und Pause erhalten und Datensätze zur Klärung genutzt, ohne jeden Verbindungsfehler als Nichtannahme zu deuten.
