====== LU11 – Daten von einer API laden ======
===== Was ist eine API? =====
Bisher lagen alle FAQ-Daten direkt im Code – hartcodiert in einem Array. In echten Webprojekten kommen Inhalte aber fast immer von **aussen**: aus einer Datenbank, einem CMS oder einer externen Quelle.
Der Weg dorthin führt über eine **API** (Application Programming Interface) – eine Schnittstelle, über die zwei Systeme miteinander kommunizieren. Wir schicken eine Anfrage («Gib mir alle FAQs»), die API schickt die Daten zurück.
{{:de:modul:m291:learningunits:lu11:theorie:client_server_http_req_response_kitchen.png?direct&1100|Wie eine API funktioniert: Browser sendet Request, Server antwortet mit Daten}}
^ Wir (Browser / Vue App) ^ ^ API / Server ^
| «Gib mir alle FAQs» | →→ GET Request →→ | Datenbank |
| Bekommt JSON-Daten zurück | ←← Response ←← | Schickt Daten zurück |
===== Das Problem: Netzwerkanfragen brauchen Zeit =====
Ein normaler JavaScript-Funktionsaufruf ist sofort fertig. Eine Anfrage ans Netzwerk dauert dagegen eine Weile – die App weiss nicht, wie lange.
Wenn JavaScript einfach **wartet**, bis die Daten da sind, friert die ganze Seite ein. Buttons reagieren nicht mehr, nichts bewegt sich. Das wäre eine schlechte User Experience.
Die Lösung: **asynchrones JavaScript** – der Browser wartet auf die Daten, aber der Rest der App läuft währenddessen weiter.
{{:de:modul:m291:learningunits:lu11:theorie:async.png?direct&900| Async JavaScript}}
===== async / await =====
Mit den Schlüsselwörtern ''async'' und ''await'' schreiben wir asynchronen Code, der trotzdem einfach zu lesen ist.
async function fetchFaqs() {
const response = await fetch('https://...mockapi.io/faqs');
const data = await response.json();
console.log(data);
}
^ Schlüsselwort ^ Bedeutung ^
| ''async'' | Diese Funktion ist asynchron. Sie erlaubt die Verwendung von ''await'' und blockiert nicht den Rest der App. |
| ''await'' | Halt – warte hier, bis das Ergebnis vorliegt. Danach mach weiter. Nur innerhalb einer ''async''-Funktion erlaubt. |
| ''fetch()'' | Sendet einen HTTP GET-Request an die angegebene URL und gibt ein Promise zurück. |
| ''response.json()'' | Liest den Body der Antwort und wandelt ihn von JSON in ein JavaScript-Objekt um. Auch das ist asynchron – daher auch hier ''await''. |
**Warum zwei ''await''?** ''fetch()'' liefert zuerst nur die Antwort-Hülle (Statuscode, Header). Der eigentliche Inhalt (Body) kommt als Stream und muss erst mit ''response.json()'' ausgelesen werden. Beides dauert einen Moment – daher je ein ''await''.
===== try / catch / finally =====
Was passiert, wenn die API nicht erreichbar ist oder einen Fehler zurückgibt? Ohne Fehlerbehandlung crashed die Applikation. Mit ''try / catch'' fangen wir Fehler ab und zeigen eine verständliche Meldung an.
try {
// Code, der einen Fehler verursachen könnte
const response = await fetch('https://...');
} catch (err) {
// Wird ausgeführt, wenn im try-Block etwas schiefläuft
console.log('Fehler:', err.message);
} finally {
// Wird IMMER ausgeführt – egal ob Erfolg oder Fehler
isLoading.value = false;
}
^ Block ^ Wann? ^
| ''try'' | Enthält den Code, der fehlschlagen könnte |
| ''catch'' | Wird ausgeführt, wenn im ''try''-Block ein Fehler auftritt |
| ''finally'' | Wird immer ausgeführt – ideal um z.B. ''isLoading'' zurückzusetzen |
===== onMounted =====
Wann soll die Funktion ''fetchFaqs()'' ausgeführt werden? Sobald die Komponente im Browser eingebunden ist – dafür gibt es den **Lifecycle-Hook** ''onMounted'':
import { ref, onMounted } from 'vue';
onMounted(fetchFaqs);
''onMounted'' registriert eine Funktion, die Vue automatisch aufruft, sobald die Komponente das erste Mal im DOM gerendert wurde. Das ist der richtige Zeitpunkt, um Daten zu laden – das HTML ist bereit, die Daten können sofort angezeigt werden.
===== v-if / v-else-if / v-else =====
Beim Laden von Daten gibt es immer drei mögliche Zustände, die wir im Template abbilden:
Daten werden geladen...
{{ error }}
^ Direktive ^ Wann wird dieses Element angezeigt? ^
| ''v-if="isLoading"'' | Solange die Daten noch geladen werden |
| ''v-else-if="error"'' | Wenn ein Fehler aufgetreten ist |
| ''v-else'' | Wenn das Laden fertig ist und kein Fehler vorliegt |
Diese drei Blöcke schliessen sich gegenseitig aus – Vue zeigt immer nur einen davon an.
===== Der vollständige Ablauf =====
1. Komponente wird gerendert (onMounted)
↓
2. fetchFaqs() wird aufgerufen
↓
3. isLoading = true → «Daten werden geladen...» erscheint
↓
4. fetch() sendet GET-Request an MockAPI
↓
5. Antwort kommt zurück → response.json() wandelt sie um
↓
6. faqItems.value = data → Vue rendert die AccordionItems
↓
7. isLoading = false → Ladeanzeige verschwindet