Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.

Link zu der Vergleichsansicht

Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung
ksk_ef:web:apps:apis [2024-08-11 08:53] hofksk_ef:web:apps:apis [2024-08-11 09:54] (aktuell) hof
Zeile 37: Zeile 37:
 //Session-Cookies// leben nur, solange das Browser-Fenster offen ist und sind in der Regel unproblematisch. Long-lived cookies können über Jahre installiert bleiben und bei jedem Seitenbesuch erneuert werden. Sie werden zum Teil benützt, um Benutzer über Webseiten hinweg zu verfolgen, und haben zur ganzen Diskussion um Cookies geführt. Um den Benutzer zu identifizieren (zum Beispiel nach erfolgreichem Login) sind sie aber unverzichtbar. //Session-Cookies// leben nur, solange das Browser-Fenster offen ist und sind in der Regel unproblematisch. Long-lived cookies können über Jahre installiert bleiben und bei jedem Seitenbesuch erneuert werden. Sie werden zum Teil benützt, um Benutzer über Webseiten hinweg zu verfolgen, und haben zur ganzen Diskussion um Cookies geführt. Um den Benutzer zu identifizieren (zum Beispiel nach erfolgreichem Login) sind sie aber unverzichtbar.
  
-### Web-APIs+### Javascript Fetch 
 +Requests werden im klassischen Web vom Browser ausgelöst, um eine HTML-Datei und die darin eingebundenen Ressourcen (Stylesheets, Bilder, Javascript) zu laden. Sie können aber auch vom Javascript-Code angefordert werden. Dieser Mechanismus ([[https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch|Fetch]]) wird von allen modernen Webapps benutzt, um Inhalte dynamisch nachzuladen. Beispielsweise lädt Google Maps Kartenkacheln nach, wenn der Kartenausschnitt durch Zoomen oder Verschieben verändert wird. 
 + 
 +Wir werden diese Technik verwenden, um den Spielstand auf dem Server nachzuladen, wenn der andere Spieler gespielt hat, und um Spielzüge auszuführen. 
 + 
 +#### 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: Network-Traffic über ''fetch()'', oder eine Animation) ausführen, reklamiert der Browser, weil wir damit den Event-Thread blockieren. Das heisst, dass andere Events nicht richtig ausgeliefert werden können, und die App "eingefroren" ist.  
 + 
 +Wir wollen längere Aufgaben //asynchron// oder //nebenläufig// ausführen können. Modernes Javascript unterstützt die Programmierung von asynchronem Code mit zwei Konstrukten: ''Promises'' und den ''async'' / ''await'' Keywords, die auf ''Promise'' aufbauen. 
 + 
 +##### Promise 
 + 
 +Eine ''Promise'' ist ein //Versprechen// für das Resultat einer nebenläufigen Aufgabe. Die Promise ist zu beginn im Zustand ''pending'' und geht von da entweder über zu ''fulfilled'' (die Aufgabe war erfolgreich) oder ''rejected'' (die Aufgabe ist fehlgeschlagen). ''fulfilled'' und ''rejected'' werden zusammen als ''settled'' bezeichnet. 
 + 
 +##### 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_, also nebenläufig) markiert sind. Eine solche Funktion gibt automatisch immer selbst eine Promise zurück, auch wenn das im Code nicht so markiert ist. 
 + 
 +<code javascript> 
 +  async fetchUpdateFromServer() { 
 +    try { 
 +      const response = await fetch('/game/0'); 
 +      const json = await response.json(); 
 +      updateUi(json)); 
 +    } catch (error) { 
 +      console.log(error); 
 +    } 
 +  } 
 +</code> 
 + 
 +Merke: 
 +  * ''await'' wartet auf das Fulfilment einer Promise. Das bedeutet auch, dass die Methode lange dauern könnte. 
 +  * ''await'' ist deshalb nur in ''async'' Funktionen erlaubt. Async Funktionen geben immer eine Promise zurück, auch wenn das im Code nicht mehr sichtbar ist. 
 +  * Fehler können mit dem gewohnten ''try-catch'' gefangen werden. 
 + 
 +  * read up on ''async'' and ''await'' [[https://developers.google.com/web/fundamentals/primers/async-functions|here]] 
 +  * [[https://web.dev/promises/|more on Promises]] 
 + 
 +{{ :ef_informatik:javascript_async_fetch_promises.png?nolink&600 | }} 
 + 
 +### 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> 
 +
 +  "id": 0, 
 +  "state": "ended", 
 +  "grid":
 +    "X", 
 +    " ", 
 +    " ", 
 +    "X", 
 +    "O", 
 +    " ", 
 +    "X", 
 +    "O", 
 +    " " 
 +  ], 
 +  "winner": "X", 
 +  "player": "X", 
 +  "next": "O" 
 +}</code> 
 + 
 +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. `"ended"`) 
 +    * 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://wiewarm.ch stellt neben der Webseite auch ein JSON-Web-API bereit, das die Wassertemperaturen von vielen Badeanstalten in der Schweiz rapportiert. Wichtig ist die Unterscheidung: 
 + 
 +  * https://www.wiewarm.ch/bad/Seebad_Romanshorn ist die für menschliche Benutzer:innen gedachte Webseite 
 +  * https://www.wiewarm.ch/api/v1/temperature.json/16 rapportiert die Temperatur eines Bades im JSON-Format, für die weitere programmatische Verarbeitung. 
 +    * `16` ist die Id der Badi Romanshorn 
 +    * Das API ist [[https://www.wiewarm.ch/api/doc/index.html#!/temperature-v1/v1-temperature-_badid-_get|hier weiter dokumentiert]]. 
 + 
 +Erstelle eine neue HTML-Datei `bodensee.html` mit folgendem Inhalt: 
 + 
 +<code html bodensee.html> 
 +<html> 
 +  <head> 
 +    <title>Bodensee-Temperatur</title> 
 +  </head> 
 +  <body> 
 +    <main> 
 +      <h1>Bodensee</h1> 
 +      <p>Temperatur: <span id="tempBodensee"></span></p> 
 +    </main> 
 +    <script src="bodensee.js"></script> 
 +  </body> 
 +</html> 
 +</code> 
 + 
 +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('tempBodensee'); 
 +const badi_romanshorn_id = 16; 
 +const bodensee_id = 51; 
 +const url = `https://www.wiewarm.ch/api/v1/temperature.json/${badi_romanshorn_id}`; 
 + 
 +// 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 + '°C'; 
 +    } 
 +  } catch (x) { 
 +    console.log(`Cannot fetch ${url}, status: ${x}`); 
 +  } 
 +}; 
 + 
 +requestTemp(); 
 +</code> 
 + 
 +#### 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, in welcher Reihenfolge der Code ausgeführt wird 
 +    * [[https://tkilla77.github.io/ksr_tictactoe/static/bodensee.html|Beispiel hier]] 
 + 
  • ksk_ef/web/apps/apis.1723366431.txt.gz
  • Zuletzt geändert: 2024-08-11 08:53
  • von hof