Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Nächste Überarbeitung | Vorherige Überarbeitung | ||
ksk_ef:web:apps:apis [2024-08-11 07:52] – angelegt hof | ksk_ef:web:apps:apis [2024-08-11 09:54] (aktuell) – hof | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
## Web-APIs und JSON | ## Web-APIs und JSON | ||
+ | |||
+ | Bisher spielt sich alles Wesentliche auf dem _Client_ (im Browser) ab. Die TicTacToe-App kann zwar [[https:// | ||
+ | |||
+ | Insbesondere ist es auch nicht möglich, übers Netz gegeneinander zu spielen. Dafür müsste die Spiel-Logik nicht in Browser (also im Client) ausgeführt werden, sondern in einem Programm, das auf dem Server läuft. Die beiden Spieler: | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | Wir trennen also die Darstellung (HTML & CSS) von der Spiellogik ab. Die Logik soll auf dem Server ausgeführt werden, die Browser rufen lediglich geeignete Schnittstellen (en. _Application Programming Interface_ oder API) auf. Bei einer Web-App erfolgt der Aufruf der Schnittstelle über eine HTTP-Anfrage. | ||
+ | |||
+ | ### HTTP | ||
+ | Das HyperText Transfer Protocol dient der Übertragung von Informationen zwischen Server und Client (Browser). Bisher haben wir ausschliesslich ganze Dateien (`tictactoe.html`, | ||
+ | |||
+ | #### Request & Response | ||
+ | {{ : | ||
+ | Jeder Request verlangt eine bestimmte // | ||
+ | |||
+ | Der Request enthält eine Anzahl zusätzlicher Informationen als // | ||
+ | * **If-modified-since**: | ||
+ | * Das Dokument nur zurückgeben, | ||
+ | * Sonst antwortet der Server mit einem 304 Response Code, um Caching zu ermöglichen, | ||
+ | * **Referer**: | ||
+ | * wird dazu verwendet, das Surfverhalten von Nutzern zu analysieren | ||
+ | * **User-agent**: | ||
+ | * Enthält Informationen zum Browser des Benutzers. | ||
+ | * Kann zum Beispiel verwendet werden, um ein Mobiltelefon von einem Desktop-Computer zu unterscheiden. | ||
+ | |||
+ | {{ : | ||
+ | Der Server antwortet mit einem // | ||
+ | * **200** (OK): Anfrage ist erfolgreich, | ||
+ | * **304** (UNMODIFIED): | ||
+ | * **404** (NOT FOUND): Die Ressource wurde nicht gefunden. | ||
+ | |||
+ | #### Cookies | ||
+ | Zusätzlich kann der Server noch **Cookies** mitliefern, die der Browser speichert und beim nächsten Request an den gleichen Server im Request mitgeliefert werden. | ||
+ | |||
+ | // | ||
+ | |||
+ | ### Javascript Fetch | ||
+ | Requests werden im klassischen Web vom Browser ausgelöst, um eine HTML-Datei und die darin eingebundenen Ressourcen (Stylesheets, | ||
+ | |||
+ | Wir werden diese Technik verwenden, um den Spielstand auf dem Server nachzuladen, | ||
+ | |||
+ | #### Asynchronous code | ||
+ | |||
+ | Eine Herausforderung in Javascript (und nicht nur dort) ist der Umgang mit längeren Aufgaben. Reagiert unser Code ja auf einen Event (z.B. einen Klick) und führt dann eine kurze Aufgabe (z.B. den Game-State ändern) aus, ist das kein Problem. Wollen wir eine potentiell längere Aufgabe (insbesondere: | ||
+ | |||
+ | Wir wollen längere Aufgaben // | ||
+ | |||
+ | ##### Promise | ||
+ | |||
+ | Eine '' | ||
+ | |||
+ | ##### Await & Async | ||
+ | |||
+ | Wenn wir im Code auf das Resultat einer Promise warten möchten, können wir das mit dem Keyword `await` tun. Da die Ausführung dieses Codes eine Weile dauern könnte, ist die Verwendung von `await` nur in Funktionen zulässig, die mit dem Keyword `async` (für _asynchronous_, | ||
+ | |||
+ | <code javascript> | ||
+ | async fetchUpdateFromServer() { | ||
+ | try { | ||
+ | const response = await fetch('/ | ||
+ | const json = await response.json(); | ||
+ | updateUi(json)); | ||
+ | } catch (error) { | ||
+ | console.log(error); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Merke: | ||
+ | * '' | ||
+ | * '' | ||
+ | * Fehler können mit dem gewohnten '' | ||
+ | |||
+ | * read up on '' | ||
+ | * [[https:// | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | ### JSON | ||
+ | Sollen nicht ganze Dateien, sondern nur kleine Informationsschnipsel übertragen werden, wird dafür die JavaScript Object Notation (_JSON_) verwendet. JSON sieht so aus: | ||
+ | |||
+ | <code javascript> | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " ", | ||
+ | " ", | ||
+ | " | ||
+ | " | ||
+ | " ", | ||
+ | " | ||
+ | " | ||
+ | " " | ||
+ | ], | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | }</ | ||
+ | |||
+ | Merke: | ||
+ | * alle Informationen sind in einem Objekt mit geschweiften Klammern eingebettet. | ||
+ | * alle Informationen in einem Objekt haben die Notation `key: value`, wobei der `key` ein String sein muss, der Wert aber eines der folgenden Elemente sein kann: | ||
+ | * String (z.B. `" | ||
+ | * Zahl (z.B. `42`) | ||
+ | * Liste (Array), z.B. das Spiel-Grid im obigen Beispiel, in eckigen Klammern. | ||
+ | * wieder ein Objekt. | ||
+ | * Mehrere Einträge sind durch Komma getrennt. | ||
+ | |||
+ | ### Web-API Beispiel | ||
+ | |||
+ | Bevor wir ein eigenes Web-API für TicTacToe schreiben, werden wir ein frei verfügbares Web-API verwenden, um eine dynamische Webseite zu erstellen. | ||
+ | |||
+ | Die Seite https:// | ||
+ | |||
+ | * https:// | ||
+ | * https:// | ||
+ | * `16` ist die Id der Badi Romanshorn | ||
+ | * Das API ist [[https:// | ||
+ | |||
+ | Erstelle eine neue HTML-Datei `bodensee.html` mit folgendem Inhalt: | ||
+ | |||
+ | <code html bodensee.html> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | <script src=" | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Unser Javascript verlangt die JSON-API mittels `fetch`. Die Antwort wird, sobald sie eintrifft, als JSON interpretiert und weiter verarbeitet: | ||
+ | |||
+ | <code javascript bodensee.js> | ||
+ | const tempBodensee = document.getElementById(' | ||
+ | const badi_romanshorn_id = 16; | ||
+ | const bodensee_id = 51; | ||
+ | const url = `https:// | ||
+ | |||
+ | // Um await zu verwenden, muss die Funktion mit async markiert werden. | ||
+ | async function requestTemp () { | ||
+ | try { | ||
+ | // Await macht folgendes: | ||
+ | // fetch(url) wird nebenläufig ausgeführt das Resultat | ||
+ | // wird irgendwann in Zukunft zur Verfügung stehen. Die | ||
+ | // nebenläufige Berechnung wird mit einer Promise verfolgt. | ||
+ | fetchPromise = fetch(url); | ||
+ | // Wird die Promise fulfilled, wird die response-Variable | ||
+ | // gesetzt und der weitere Code ausgeführt. | ||
+ | response = await fetchPromise; | ||
+ | if (response.ok) { | ||
+ | json = await response.json(); | ||
+ | tempBodensee.textContent = json[bodensee_id].temp + ' | ||
+ | } | ||
+ | } catch (x) { | ||
+ | console.log(`Cannot fetch ${url}, status: ${x}`); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | requestTemp(); | ||
+ | </ | ||
+ | |||
+ | #### Aufgabe Web-APIs | ||
+ | Füge obigen Code (`bodensee.html` und `bodensee.js`) in dein Projekt ein und öffne die Webseite im Browser. Wie warm ist der Bodensee? | ||
+ | |||
+ | * Ändere den Code, um die Temperatur in deiner Lieblingsbadi darzustellen! | ||
+ | * Achtung, die Badi Kreuzlingen scheint seit 10 Jahren keine Messungen mehr bereitzustellen... | ||
+ | * Füge `console.log(Date.now())` Zeilen in den JS-Code ein, um festzustellen, | ||
+ | * [[https:// | ||
+ | |||