1
0
Fork 0
mirror of https://github.com/TheTaz25/denis.ergin.git synced 2025-07-06 13:18:49 +00:00

feat(slides): data fetching

This commit is contained in:
Denis Ergin 2025-01-06 09:46:41 +01:00
parent e61700405e
commit 9512c81903
8 changed files with 332 additions and 0 deletions

View file

@ -0,0 +1,32 @@
---
interface Props {
url: string,
id: string,
converter: 'text',
}
const { url, id, converter } = Astro.props;
---
<div class="fetch-demo">
<button id={id}>
Request starten...
</button>
<div id={`${id}-result`}>
</div>
<script define:vars={{id, url, converter}} is:inline>
const target = document.getElementById(`${id}-result`);
const button = document.getElementById(id).onclick = async function() {
target.innerText = 'Abfrage läuft...';
const response = await fetch(url);
if (converter === 'text') {
const text = await response.text();
target.innerText = text;
}
}
</script>
</div>

View file

@ -0,0 +1,54 @@
<section>
<section>
<h2>Headers</h2>
</section>
<section>
<p>Headers sind dafür zuständig zusätzliche Informationen vom und zum Server zu übertragen.</p>
<p>Diese Informationen sind unter anderem: Authentifizierungs und Authentifikations-Informationen, Caching-Informationen, Content-Flags, Cookies, Cross-Origin-Resource-Sharing-Informationen, und viele weitere.</p>
<p>Eine Umfangreiche Liste ist zu finden auf <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank" rel="noreferrer noopener">Developer Mozilla</a></p>
</section>
<section>
<p>Header sind eine spezielle Klasse die initiiert werden kann.</p>
<pre class="js"><code data-trim data-line-numbers is:raw>
const headers = new Headers();
// Header können folgendermaßen in
// einem Request verwendet werden
const response = await fetch('url', {
headers,
});
</code></pre>
</section>
<section>
<p>Die Header-Instanz enthält folgende Funktionen um Header zu modifizieren:</p>
</section>
<section>
<p>headers.append(name, value)</p>
<p>Fügt einen neuen Header-Eintrag zum Objekt hinzu</p>
</section>
<section>
<p>headers.delete(name)</p>
<p>Entfernt einen Eintrag aus dem Header</p>
</section>
<section>
<p>headers.get(name)</p>
<p>Gibt einen String zurück der den Inhalt des Angegebenen Header-Eintrages abbildet. <code>null</code> wenn kein Eintrag vorhanden ist.</p>
</section>
<section>
<p>headers.has(name)</p>
<p>Prüft ob ein Header-Eintrag mit gegebenen Namen existiert, falls ja liefert die Funktion <code>true</code>, andernfalls <code>false</code>.</p>
</section>
<section>
<p>headers.set(name, value)</p>
<p>Setzt einen Eintrag im Header-Objekt mit angegebenem Wert, überschreibt existierende Werte.</p>
<p>Zum Anhängen an einen existierenden Wert, kann man die Funktion <code>.append()</code> nutzen</p>
</section>
</section>

View file

@ -0,0 +1,15 @@
---
import Title from "./title.astro";
import MakeARequest from "./make-a-request.astro";
import Json from "./json.astro";
import Response from "./response.astro";
import Headers from "./headers.astro";
---
<div class="slides">
<Title />
<MakeARequest />
<Json />
<Response />
<Headers />
</div>

View file

@ -0,0 +1,65 @@
<section>
<section>
<h2>JSON</h2>
<p>"Jason", oder auch "JavaScript Object Notation"</p>
</section>
<section>
<p>JSON ist ein modernes Datenformat um strukturierte Daten zu übertragen.</p>
<p>Der Inhalt ist dabei stark den JavaScript-Objekten nachempfunden</p>
</section>
<section>
<pre class="json"><code data-trim data-line-numbers is:raw style="max-height: 600px;">
{
"days_until":38,
"following_production": {
"days_until":58,
"id":202555,
"overview":"Matt Murdock, a blind lawyer with heightened abilities, is fighting for justice through his bustling law firm, while former mob boss Wilson Fisk pursues his own political endeavors in New York. When their past identities begin to emerge, both men find themselves on an inevitable collision course.",
"poster_url":"https://image.tmdb.org/t/p/w500/bSsjWM91kSZqW0BagqaoIeo8Jz7.jpg",
"release_date":"2025-03-04",
"title":"Daredevil: Born Again",
"type":"TV Show"
},
"id":822119,
"overview":"After meeting with newly elected U.S. President Thaddeus Ross, Sam finds himself in the middle of an international incident. He must discover the reason behind a nefarious global plot before the true mastermind has the entire world seeing red.",
"poster_url":"https://image.tmdb.org/t/p/w500/z0ujnXounP4yq637zyLBiZThF7Y.jpg",
"release_date":"2025-02-12",
"title":"Captain America: Brave New World",
"type":"Movie"
}
</code></pre>
</section>
<section>
<p>Es sind alle Gängigen JavaScript Datentypen erlaubt, inklusive <code>null</code> und <code>undefined</code>.</p>
<p>Es gibt per-se keine Feste Datenstruktur, die vorgibt welche keys erlaubt sind und welche nicht. Wir können das Datenformat entsprechend dynamisch gestalten.</p>
</section>
<section>
<p>Es gibt aber darauf aufbauend das JSON-Schema, mit dem ein Parser eine "wohlgeformte" JSON-Struktur identifizieren kann.</p>
<p>JSON-Schema ist aber nicht teil dieser Vorlesung.</p>
</section>
<section>
<p>"Vorgänger" von JSON ist / war SOAP. SOAP war XML-Basiert und wurde früher in großem Umfang von vielen Systemen benutzt. Aufgrund des Aufwandes ist aber JSON nun der de-facto Standard bei Datenübertragungen.</p>
<p>Alle modernen Programmiersprachen bieten Optionen, JSON in Strukturierte Klassen zu parsen.</p>
<p>Und selbst in JavaScript müssen wir "rohes" JSON in geparste Objekte übersetzten.</p>
</section>
<section>
<p>Hierfür steht uns das globale Objekt <code>JSON</code> mit den Funktionen <code>stringify &amp; parse</code> zur Verfügung</p>
<pre class="js"><code data-trim data-line-numbers is:raw>
const myObject = { value: 42 };
const asString = JSON.stringify(myObject);
console.log(asString);
const parsed = JSON.parse(asString);
console.log(parsed);
</code></pre>
</section>
</section>

View file

@ -0,0 +1,53 @@
---
import FetchDemo from "./fetch-demo.astro";
---
<section>
<section>
<h2>Requests &amp; Fetch API</h2>
</section>
<section>
<p>Ein Disclaimer: Wir werden im Rahmen der Vorlesung mit der moderneren <code>fetch</code> API arbeiten. Die Fetch-API hat <code>XMLHttpRequest</code> abgelöst und bietet moderne Features.</p>
</section>
<!-- https://www.whenisthenextmcufilm.com/api -->
<section>
<p>Anatomie eines Fetch-Aufrufs</p>
<p>Zu Demonstrations-Zwecken nutzen wir eine offene API, die wir ansteuern können:</p>
<pre class="js"><code data-trim data-line-numbers is:raw>
// Eine offene API zum abfragen einfacher Wetter-Daten
const url = 'https://wttr.in/Karlsruhe?format=4';
// Fetch gibt uns ein Promise
// erfolgreich wenn Request erfolgreich
const response = await fetch(url);
// als letzter schritt holen wir die daten mittels .text()
console.log(await response.text());
</code></pre>
<FetchDemo converter="text" url="https://wttr.in/Karlsruhe?format=4" id="wttr-demo-1" />
</section>
<section>
<p>Wenn wir nichts weiter als die URL angeben, wird ein <code>GET</code> Request ausgeführt.</p>
<p>Die verschiedenen Request-Formate haben wir bereits betrachtet.</p>
<p>Weiterhin können wir erkennen, dass ein fetch-Aufruf ein Promise zurück gibt, dass wir <code>await</code>'en müsen</p>
</section>
<section>
<h3>Fetch-Optionen</h3>
</section>
<section>
<p>Wenn wir z.B. POST Requests machen wollen, müssen wir zusätzliche Optionen als 2. Parameter mitgeben</p>
<pre class="js"><code data-trim data-line-numbers is:raw>
fetch("url", {
method: "POST", // "PUT", "DELETE"
body: "Inhalt",
});
</code></pre>
</section>
</section>

View file

@ -0,0 +1,102 @@
<section>
<section>
<h2>Responses</h2>
</section>
<section>
<p>Wir haben unseren Request abgeschickt und haben eine Antwort erhalten.</p>
<p>In den Folien vorher haben wir auch die Antwort bereits extrahiert und angezeigt.</p>
<p>Bisher haben wir aber nur die Funktion <code>await response.text()</code> verwendet. Sie liefert den Inhalt der Antwort als normalen String zurück.</p>
</section>
<section>
<p>Falls es euch damals aufgefallen ist, haben wir beim Empfang des Inhalts mittels <code>.text()</code> die Antwort mit <code>await</code> abwarten mussten.</p>
<p>Die Funktion liefert also ein Promise das mit dem Inhalt der Antwort des Requests zurück kommt.</p>
<p>Aber warum?</p>
</section>
<section>
<p>Das liegt daran wie die Datenübertragung funktioniert.</p>
<p>In dem Moment in dem der Request-Promise "erfüllt" ist, haben wir zwangsweise noch keine Daten erhalten.</p>
<p>Die Daten vom Body werden als Stream gespeichert. Solange die Datenübertragung noch nicht abgeschlossen ist wird der Stream weiter gefüllt.</p>
<p>Die Abfrage der Inhalte vom Body mittels <code>.text()</code> erwartet also, dass der Stream vollständig ist.</p>
</section>
<section>
<p>Blicken wir aber noch genauer auf den Zustand zwischen dem Request Promise und dem Aufruf um Inhalte zu erhalten.</p>
</section>
<section>
<p>Wenn wir vom Server eine Antwort erhalten, kommen die Header zuerst im Browser an.</p>
<p>Im Header stehen alle für den Request Relevanten Meta-Informationen.</p>
<p>Unter anderem ist dort auch der HTTP-Status-Code enthalten, mit dem wir den Erfolg des Requests bestimmen können.</p>
</section>
<section>
<p>HTTP-Statuscodes sind eine 3-Stellige Nummer zwischen 100 und 599.</p>
<p>Jede Nummer steht für eine andere Art von Antwort. Grob Kategorisiert werden diese im Hunderter-Bereich:</p>
<ol>
<li>100er > "Informative" Antworten</li>
<li>200er > Erfolgreiche Antworten</li>
<li>300er > Umleitungen / Redirects</li>
<li>400er > Client-Fehler</li>
<li>500er > Server-Fehler</li>
</ol>
</section>
<section>
<p>Die am gebräuchlichsten Antworten sind:</p>
<p>200 > OK, 201 > Created, 204 > No Content, 301 > Moved Permanently, 304 > Not Modified, 400 > Bad Request, 401 > Unauthorized, 403 > Forbidden, 404 > Not Found, 500 > Internal Server Error</p>
<p>Für eine komplette Liste, kann man das Internet fragen, z.B. <a href="https://http.cat" target="_blank" rel="noopener noreferrer">HTTP Cats</a></p>
</section>
<section>
<p>Zurück zur Response: Wir erhalten also in den Headern bereits den Erfolg oder Miserfolg des Requests, bevor die Daten angekommen sind.</p>
<p>Entsprechend wird der Request-Promise fullfiled, bevor die Daten komplett angekommen sind.</p>
<p>Deswegen ist <code>.text()</code> ein Promise, wir warten noch auf die Vollständigkeit der Daten.</p>
</section>
<section>
<p>Das Response Objekt hat aber noch weitere Informationen und Funktionen.</p>
</section>
<section>
<p>response.headers</p>
<p>In der headers-property sind alle in der Response beinhalteten Header aufgelistet. </p>
</section>
<section>
<p>response.ok</p>
<p><code>true</code>, wenn der HTTP-Statuscode im Bereich 200 bis 299 liegt.</p>
</section>
<section>
<p>response.status</p>
<p>Der HTTP-Statuscode den der Server übermittelt hat.</p>
</section>
<section>
<p>response.statusText</p>
<p>Eine Beschreibung des Response-Codes (z.B. OK für 200)</p>
</section>
<section>
<p>response.text() (Promise)</p>
<p>Extrahiert die Antwort des Servers als "Plain-Text"</p>
</section>
<section>
<p>response.json() (Promise)</p>
<p>Extrahiert die Antwort des Servers als JSON-Struktur und parsed die sofort in ein JavaScript-Objekt um.</p>
</section>
<section>
<p>Weitere Extraktoren:</p>
<ul>
<li>.formData() zur Extraktion der Antwort als FormData Objekt</li>
<li>.blob() zur Extraktion der Antwort als Blob</li>
<li>.arrayBuffer() zur Extraktion der Antwort als ArrayBuffer</li>
<li>.bytes() zur Extraktion der Antwort in ein Uint8Array</li>
</ul>
</section>
</section>

View file

@ -0,0 +1,3 @@
<section>
<h1>JavaScript: Daten aus dem Backend abfragen</h1>
</section>

View file

@ -0,0 +1,8 @@
---
import Reveal from "../../../layouts/Reveal.astro";
import Slides from "../../../components/slides/javascript/08-data-fetching/index.astro";
---
<Reveal title="JavaScript - Fetch: Daten aus Servern abfragen">
<Slides />
</Reveal>