Fetch API
API: Application Programming Interface
Eine API ist eine Art Übersetzungsprogramm für Programme, die verschiedene Sprachen sprechen. Über eine API können sich Programme austauschen, ohne dass sie wissen müssen, wie das andere Programm funktioniert.
Bei all diesen Methoden geht es darum, Daten von einer anderen Anwendung in unser Programm zu laden. Dazu wird ein Request an einen Server geschickt, dessen Antwort (Response) anschließend verarbeitet wird. Dabei sind vor allem zwei Dinge wichtig: Erstens müssen wir auf die Antwort warten (und es ist gar nicht sicher, dass wir eine bekommen), und zweitens ist diese Antwort ein JSON-String, den wir in ein JavaScript-Objekt umwandeln müssen, bevor wir irgendetwas damit anfangen können.
XMLHttpRequest (XHR)
Section titled “XMLHttpRequest (XHR)”XMLHttpRequest ist die alte Methode
XML: Extensible Markup Language (XML hat Ajax erst ermöglicht.)
Ajax: Asynchronous JavaScript and XML
Request
Section titled “Request”// 1. create an XMLHttpRequest Object:const request = new XMLHttpRequest();// 2. we want to know when a response comes back from the server, so we listen for the load event:request.addEventListener('load', e => { // do sth.});// 3. construct and send the request (we use the method 'get'):const url = "https://my-api-endpoint.tld"; // this is my resourcerequest.open('get', url);request.send();Response
Section titled “Response”Die Response Property enthält die Daten, die wir vom Server angefragt haben. XHR gibt uns verschiedene Informationen in Form von Property/Value-Pairs zurück, wie Status, Timeout, responseURL, withCredentials, etc. … Vorrangig interessieren uns body und payload (der die eigentlichen Daten enthält).
Die Response ist ein String, der in JSON formatiert ist. Das müssen wir erst einmal in ein JavaScript-Objekt umwandeln, um damit weiterarbeiten zu können.
// XHR in der console ausgeben:request.addEventListener('load', e => { console.log(e.target);});JavaScript Object Notation
JSON Objekte sind ähnlich wie JavaScript-Objekte, mit zwei grundlegenden Unterschieden:
- JSON-Objekte enthalten nur Strings
- JSON property/value-pairs sind immer, immer in doppelten Anführungszeichen geschrieben.
Es gibt zwei Methoden, JSON in JavaScript umzuwandeln und umgekehrt:
- JSON zu JavaScript:
JSON.parse(el); - JavaScript zu JSON:
JSON.stringify(el);
Beispiel/Übung von mds
Section titled “Beispiel/Übung von mds”Wir holen Daten vom git-Repository und listen Username, URL und die Anzahl der Sternchen auf:
request.addEventListener('load', e => { const allData = JSON.parse(e.target.response); console.log(allData); // we don't want to have all the data, so we "massage" them // we create a new array with map() which contains only the information we need const data = allData.map(blu => { return { name: blu.name, url: blu.html_url, stars: blu.stargazers_count, }; });});Fetch API
Section titled “Fetch API”Die Fetch API ist eine neuere bzw. modernere Methode, um Ajax auszuführen.
Die Methode fetch() akzeptiert zwei Argumente:
- url: die Adresse, von der wir unsere Daten holen wollen
- options (opt.): ein JavaScript-Objekt, mit dem wir zusätzliche Optionen angeben können
fetch() schickt den Request sofort ab, im Unterschied zu XMLHpptRequest müssen wir das nicht extra machen. Um die Response zu sehen, benötigen wir ein then() Statement.
Die Response sieht ebenfalls anders aus als beim XMLHttpRequest. Sie ist im body als “readable stream” versteckt. Um diesen Stream zu nutzen, müssen wir ihn in JavaScript umwandeln. Das machen wir mit der Methode json(), die fetch() für uns bereitstellt.
fetch() benutzt Request und Response-Objekte sowie CORS und HTTP Origin Header Semantik. Es gibt ein Promise zurück, das mit der Response auf den Request aufgelöst wird.
const url = "https://my-api-endpoint.tld";fetch(url)// to read the response directly, we can log it to the console:.then(response => console.log(response))// remove the console.log to continue:.then(response => response.json()).then(data => console.log(data))async/await
Section titled “async/await”fetch() ist zwar schon um Längen besser als ein XMLHttpRequest, aber es ist irgendwie schwer zu lesen. Daher wandeln wir jetzt Schritt für Schritt die Funktion fetchData() in eine asynchrone Funktion um. Diese ist leichter zu lesen, da sie ein bisschen mehr wie eine normale, synchrone Funktion aussieht.
// fetch: so haben wir es bisher gemachtfunction fetchData() { fetch("https://dummyjson.com/users/1") .then((res) => res.json()) .then(console.log) .catch((err) => console.log(err)) .finally(() => console.log("finally"));}fetchData();Schritt 1:
Wir können einfach sagen: const data = fetch(...); … und dann versuchen wir mal, data in der Konsole auszugeben:
function fetchData() { const data = fetch("https://dummyjson.com/users/1"); console.log(data);}fetchData();
// Ausgabe in der Konsole:Promise { <state>: "pending" }Schritt 2:
Warum gibt die Konsole keine Daten aus? Weil der JavaScript-Compiler das macht, was er immer macht: er geht von Zeile zu Zeile und in diesem Fall wartet er die Antwort vom Server (Response) nicht ab. fetch() ist nur ein Promise mit ausstehender Antwort. Wir müssen JavaScript also sagen, dass es an dieser Stelle warten soll. Das machen wir mit async/await. Das Keyword async sagt JavaScript, dass die Funktion ein await enthält:
async function fetchData() { const data = await fetch("https://dummyjson.com/users/1"); console.log(data);}fetchData();
// Ausgabe in der Konsole:Response { type: "cors", url: "https://dummyjson.com/users/1", redirected: false, status: 200, ok: true, statusText: "", headers: Headers(1), body: ReadableStream, bodyUsed: false }Schritt 3:
Jetzt wandeln wir den JSON-String in ein JavaScript-Objekt um (wichtig ist hier auch wieder await):
async function fetchData() { const data = await fetch("https://dummyjson.com/users/1"); const finalData = await data.json(); console.log(finalData);}fetchData();
// Ausgabe in der Konsole:Object { id: 1, firstName: "Emily", lastName: "Johnson", maidenName: "Smith", age: 29, gender: "female", email: "emily.johnson@x.dummyjson.com", phone: "+81 965-431-3024", username: "emilys", password: "emilyspass", … }...Schritt 4:
Wir möchten auch ein Error-Handling, daher verwenden wir try ... catch, das ähnlich funktioniert wie if ... else:
async function fetchData() { try { const data = await fetch("https://dummyjson.com/users/1"); const finalData = await data.json(); } catch (error) { console.log(error); } finally { console.log("Finally!"); }}fetchData();Async Await vs. Fetch.then()
Section titled “Async Await vs. Fetch.then()”Video auf YouTube Artikel auf dev.to
More stuff
Section titled “More stuff”<script>// EXAMPLE RANDOM USER API https://randomuser.me/ const ol = document.querySelector('#authors'); const url = 'https://randomuser.me/api/?results=10';
fetch(url) // if (resolve) // .then(response => { // // response ist das an fetch() zurückgegebene Objekt: // console.log(response) // so sieht das aus // // das wir gleich nach JavaScript konvertieren: // response.json() // }) .then(response => response.json()) // jetzt wollen wir die Daten aus dem body/readable stream weiter verarbeiten .then(data => { console.log(data); // im Objekt sehen wir results - das ist ein Array mit den Daten, die für uns eigentlich interessant sind, also holen wir uns diese: const authors = data.results; console.log(authors); // und jetzt können diese Daten weiter verarbeitet werden: return authors.map(author => {}) }) // if (reject) .catch(function(error) { console.log(error) });</script>