AJAX, aber einfacher: Die neue Fetch API

Tales from the Web side  –  1 Kommentare

AJAX-basierte Anfragen lassen sich, wenn man keine Hilfsbibliotheken wie jQuery hinzunimmt, eher umständlich formulieren. Die neue Fetch API verspricht hier eine einfach zu bedienende, auf Promises basierende Alternative.

Wer kennt das als Webentwickler nicht? Man will mal eben eine einfache AJAX-Anfrage formulieren, ohne auf jQuery oder Ähnliches zurückzugreifen, und merkt dann recht schnell, dass sich der benötigte Code doch nicht so einfach schreiben lässt, wie man denkt. Mehrere Callbacks wollen definiert, verschiedene Eigenschaften gesetzt und mehrere Methoden (in der richtigen Reihenfolge) aufgerufen werden:

var request = null;
request.responseType = 'json';
request.onload = function() {
console.log(request.response);
};
request.onerror = function() {
console.error('Fehler beim Laden der Projekte');
};
request.open('GET', './api/projects', true);
request.send(null);

Möchte man dann noch ältere Versionen des Internet Explorer mit einbeziehen, wird es ganz haarig:

if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e) {}
}
}

Genau dieses Problem adressiert die neue Fetch API, die sich – zumindest wenn man mit dem Konzept der Promises vertraut ist – recht komfortabel nutzen lässt.

Ausgangspunkt ist die globale (bzw. auf dem window-Objekt definierte) Funktion fetch(), die alle Arten asynchroner Anfragen (GET, POST etc.) abstrahiert und besagtes Promise-Objekt zurückgibt. Auf diesem lassen sich anschließend wie gewohnt die Methoden then() und catch() aufrufen, um Callbacks für Ergebnisbehandlung und Fehlerbehandlung zu definieren.

Das Beispiel von oben lässt sich unter Verwendung Fetch API beispielsweise wie folgt formulieren:

fetch('./api/projects')
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.error(error);
});

Der Aufruf von response.stream() erzeugt dabei einen sogenannten Stream, über den sich der Inhalt der HTTP-Antwort als JSON auslesen lässtn. Neben JSON-Streams stehen weitere Streams für Array-Buffer (arrayBuffer()), Binary Large Objects (blob()), Formulardaten (formData()) und reinen Text (text()) zur Verfügung.

Über die aus ES6 bekannten Arrow-Funktionen und die für ES7 geplanten Async Functions lässt sich die gezeigte Schreibweise sogar noch weiter komprimieren.

POST-Requests

Die Funktion fetch() lässt sich wie bereits erwähnt auch für POST-Anfragen verwenden. Dazu übergibt man ihr einfach zusätzlich zur URL ein entsprechendes Konfigurationsobjekt, über das sich HTTP-Methode, Headers und Inhalt angeben lassen. Folgendes Listing zeigt dazu ein Beispiel:

fetch('./api/projects',
{
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Beispielprojekt',
url: 'http://www.example.com',
})
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.error(error);
});

Die Fetch API vereinfacht das Absenden AJAX-basierter Anfragen. Kritik an der API gibt es momentan noch, weil derzeit keine Möglichkeit vorgesehen ist, eine Anfrage abbrechen zu können, wie das beispielsweise über die Methode abort() von XMLHttpRequest möglich ist. Ein entsprechendes Issue im Git-Repository der API existiert bereits und wird zurzeit ausgiebig diskutiert.

Momentan wird die Fetch API von Chrome (seit Version 42), von Firefox (seit Version 39) und von Opera (seit Version 29) unterstützt. Für ältere Browser steht ein Polyfill zur Verfügung.