Appearance
Async HTTP mit JS
Folgende Ziele werden in diesem Versuch angestrebt
- HTML Webseite erstellen
- Seite mit CSS und Flexbox stylen
- Mit JavaScript asynchrone Requests an Web API ausführen
- HTTP Response parsen
- DOM der Webseite änderen um den Inhalt der Server Response zu visualisieren.
In diesem Versuch arbeiten wir vollständig Clientseitg (wir verwenden eine öffentliche API eines HTTP Servers, welche wir selber implementieren).
Moderne Webapplikationen arbeiten mit APIs, welche Nutzdaten (häufig in JSON) zur Verfügung stellen. Dabei wird die API kein CSS oder HTML liefern, dieses wird separat gehostet. In diesen Versuch erstellen wir wieder eine statische HTML und CSS Seite im Filesystem des Gastsystems (die Webseite wird also nicht einmal über einen lokalen HTTP Server geliefert).
Trennung von Client und Server
Der Webbrowser konsumiert HTML, CSS und JS. Hinzu kommen oft Bilder, Videos und andere Medien. Das Hosting von solchen statischen Files (das HTML, JS und CSS bleibt meistens immer gleich) ist nicht rechenintensiv, verbraucht aber trotzdem RAM und Netzwerkkapazität vom Server.
Aus diesem Grund wird in skalierbaren Webapplikationen meistens ein dedizierter HTTP "Fileserver" verwendet, der diese statischen Inhalte vom Filesystem liest und für den Client bereitstellt.
Dienste wie AWS S3 und Shared Webhosting sind auf diese operationen spezialisiert und sind im Vergleich zu einem dedizierten Serverdienst wie flask
, expressjs
oder django
kostengünstig zu erhalten.
Aus diesem Grund wird die API meistens getrennt implementiert. Folgende Ansätze werden oft praktiziert:
- Separate Subdomain (und IP) für API
- Loadbalancer der Cloud Infrastruktur
- um z.B. Requests nach
/api
an eine separate Serverinstanz weiterzuleiten.
- um z.B. Requests nach
nginx
oderapache
als Loadbalancer auf dem eigenen Server mit reverse proxy.
Web Applikation Dogs
In dieser Applikation wird eine öffentlich zugängliche API verwendet, bei welcher man einen JSON als Response erhält und deren Inhalt einen Link zu einem zufälligen Bild mit einem Hund beinhaltet.
Der Link wird ausgelesen und als http resource für ein Bild verwendet.
Click man auf das Bild, dann wird ein neuer Request ausgelöst und das nächste Bild gelanden.
HTTP Api für "dogs"
Unter der URL https://dog.ceo/api/breeds/image/random
erhalten Sie mit einem GET Request eine JSON Antwort.
- Führen Sie den GET Request mit dem Webbrowser aus. (Was ist die einfachste Methode hierzu?)
- Verwenden Sie auf dem Gastsystem
curl
um den API Request auszuführen. - Installieren Sie die VS Code Extension
Thunder Client
und führen Sie den Request auch hier aus.
Aufgabe
Was erhalten Sie für eine Antwort? Wie kommen Sie an die Image Resource?
Wenn Sie den Request mit Thunder Client ausführen sehen Sie eine Reihe Headers in der Response. Für was steht dabei access-control-allow-origin
?
Recherchieren Sie hierzu folgenden Blogeintrag https://www.freecodecamp.org/news/access-control-allow-origin-header-explained/.
Webseite Implementieren
Toolset
Folgen Sie im Vorfeld folgenden Beiträgen, die für den Versuch wichtig sind.
- IMG Element mit Link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#image_link
- Object Fit Property für images: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
- Wenn Sie das Beispiel anschauen, welche
object-fit
Property ist die passende, die wir verwenden wollen? - Fetch API mit HTTP Request https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
HTML und CSS
- Erstellen Sie wie in den vorherigen Versuchen eine HTML Seite mit jeweils einem JS
main.js
undstyle.css
. - Designen Sie
style.css
so, dass Sie ein statisches Bild mit der URLhttps://images.dog.ceo/breeds/kelpie/n02105412_4038.jpg
anzeigen und das Layout wie im Beispiel auf dem Bildschirm zentrieren. Die Dimensionen des Bildes sind für Breite und Höhe jeweils200px
. - Achten Sie darauf, dass der
html
resp.body
Tag by default nicht100%
der Höhe des Bildschirms umfassen.
JS window.onload
Die HTTP API, die wir verwenden werden ist folgende: https://dog.ceo/api/breeds/image/random
. Wir führen dabei einen GET Request aus. Keine weiteren Parameter sind notwendig (weder Headers
noch Request Parms
als URL encodierung).
Promises, async
und await
Funktionen können Promise
objekte zurückgeben. Ein Promise liefert hier nicht sofort das Resultat, sondern braucht im Hintergrund etwas Zeit, bis das Resultat zur Verfügung steht. Die fetch
API liefert hier ein Promise zurück.
js
const result = fetch("https://dog.ceo/api/breeds/image/random");
// was ist im Resultat drin?
console.log('result', result);
// callback registrieren, wenn result returned
result.then((httpRes) => {
// resultat des Requests ist hier als param erhältlich.
console.log('res', httpRes);
// JSON muss geparsed werden, hierzu gibt es auch wieder ein Promise
const jsonPromise = httpRes.json();
jsonPromise.then((json) => {
// endlich haben wir das resultat!!
console.log('json result', json);
});
});
Das Beispiel zeigt, dass wir bereits relativ nahe an der sogennanten "Callback Hell" sind, da wir gezwungen sind funktionen ineinander zu verschachteln.
Das async
und await
Feature schafft hierbei Abhilfe. Wollen wir auf ein Resultat mit await
warten, müssen wir uns in einem async
Context befinden. Das ist relativ einfach machbar, in dem dass wir eine Funktion mit dem async
Keyword deklarieren. Wir dürfen nicht vergessen, diese später aufzurufen. Natürlich könnten wir auch einfach unsere window.onload
Methode async
deklarieren, dann wäre ein manueller Aufruf nicht notwendig.
Folgender Code führt zum gleichen Resultat wie oben.
js
const start = async () => {
const res = await fetch('https://dog.ceo/api/breeds/image/random');
const json = await res.json();
console.log('json', json);
}
start();
- Erstellen Sie ein
onload
Callback und führen Sie einen Request viafetch
aus. - Das
onload
Callback soll dabeiasync
sein, da wir diefetch
API mitawait
aufrufen werden. - Führen Sie den
fetch
aus um das Resultat vom Server zu erhalten. - Schauen Sie sich das JSON Resultat an. Wie erhalten Sie den Link für das
img
Element? - Mit
document.querySelector()
können Sie eine Referenz auf das img Element erhalten. - Im DOM können Sie mit
.setAttribute()
ein Attribut eines Elements setzen (welches Attribut müssen Sie bei<img>
setzen um die Bildresource anzuzeigen?). - Erstellen Sie nun eine Funktion
updateImage()
, welche denfetch
ausführt und das Bild aktualisiert. - In
onload
registrieren Sie nun einenonlclick
Listener auf demimg
Element, welcher dieupdateImage()
Methode aufruft.