Fetch API
Fetch API - nowy interfejs, a także następca XMLHttpRequest, który podobnie do swego brata pozwala pracować z dynamicznymi połączeniami. Głównymi cechami odróżniającymi Fetch od starszego brata jest to, że fetch zwraca nam obietnicę, przez co praca z nim w wielu przypadkach jest zwyczajnie przyjemniejsza.
Pobieranie danych
Podstawowa składnia fetch ma postać:
fetch(url, [options]);Jedynym wymaganym parametrem jest adres na ktory się łączymy. Jeżeli pominiemy dodatkowe opcje, domyślnie będzie wykonywane połączenie typu GET, które będzie służyć do pobrania danych. Po odpaleniu, fetch zwraca obietnicę, więc tak samo jak w tamtym rozdziale, możemy je skonsumować za pomocą dostępnych metod - then(), catch(), all() itp. reagując tym samym na zakończenie połączenia:
fetch("https://restcountries.com/v3.1/name/Poland")
.then(res => {
console.log(res);
})lub korzystając ze składni async/await:
(async () => {
const res = await fetch("https://restcountries.com/v3.1/name/Poland");
console.log(res);
})();Kliknij i sprawdź w konsoli
Po zwróceniu odpowiedzi mamy dostęp do obiektu Response, które zawiera informacje o wykonanym połączeniu:
status
statusy połączenia (200, 404, 301 itp.)
statusText
status połączenia w formie tekstowej (np. Not found)
type
typ połączenia (1)
url
adres na jaki się łączyliśmy
body
właściwe ciało odpowiedzi
Właściwa odpowiedź jest przetrzymywana pod właściwością body. W konsoli debuggera odwołanie się do tej właściwości wyświetli nam obiekt ReadableStream. Obiekt ten zawiera naszą odpowiedź, ale nie zawsze będzie ona w pełnej postaci.
Aby uzyskać pełną odpowiedź w interesującym nas formacie powinniśmy zastosować odpowiednią funkcję. W naszym przypadku oczekujemy formatu JSON, więc zastosujmy response.json(). Dla innych typów danych trzeba by użyć innych metod:
response.json()
zwraca odpowiedź jako JSON
response.formData()
zwraca odpowiedź jako FormData
response.blob()
zwraca odpowiedź jako blob (dane binarne z tytułem)
response.arrayBuffer()
zwraca odpowiedź jako ArrayBuffer
Kliknij i sprawdź w konsoli
Błędy w połączeniu
Jeżeli łączymy się na poprawny adres i dostajemy poprawną odpowiedź, powyżej wymieniona właściwość ok ma wartość true, status takiego połączenia wynosi 200, a my możemy za pomocą then() działać na zwróconych danych.
Nie zawsze jednak będziemy mieli pewność, że adres na który wykonujemy połączenie zwróci nam prawidłowe dane. Serwer może paść (status 500), albo dany adres może nie istnieć (status 404).
Aby to sprawdzić spróbujmy połączyć się na błędny adres:
Kliknij i sprawdź w konsoli
Teoretycznie wystąpił błąd, więc powinna odpalić się funkcja catch().
Nic takiego jednak się nie stało - w konsoli debuggera otrzymaliśmy odpowiedź prawie taką samą jak przy naszym pierwszym połączeniu. Różnice są w niektórych właściwościach:

Jak widzimy, status zmienił się na 404, statusText na "Not Found", a właściwość ok zmieniła się na false.
Wynika to z tego, że nasze połączenie zakończyło się powodzeniem (serwer odpowiedział nam jakimiś nagłówkami) - po prostu zrobiliśmy je na adres, który nie istnieje. Jeżeli takiego połączenia w ogóle nie udało by się nawiązać (np. wystąpił błąd sieci), wtedy faktycznie zwrócony by został reject(), a co za tym idzie - zadziałał by catch().
Jeżeli czytałeś rozdział o XMLHttpRequest, nie powinno cię to w zasadzie dziwić. Dla tamtego obiektu używaliśmy zdarzeń load i error. Load oznaczało zakończenie połączenia. Tak czy siak musieliśmy dodatkowo sprawdzić czy status połączenia równał się 200. Zdarzenie error natomiast odpalane było w przypadku błędu połączenia.
Podobnie działa to w przypadku fetch.
Idąc więc za krokiem - aby dodatkowo obsłużyć potencjalne błędy przy naszych połączeniach, powinniśmy wykonać dodatkowe testy:
Kliknij i sprawdź w konsoli
Ale trzeba tu zaznaczyć, że nawet z powyższym uwzględnieniem błędów, w wielu sytuacjach nie powinno się tego traktować jako w pełni wystarczający kod. Czego tu brakuje? Mikro interakcji. A to pokazania i schowania loading. A to pokazania użytkownikowi komunikatu o błędzie wczytywania czy zbyt długim wczytywaniu. Jako dobry programista nigdy nie powinieneś pomijać takich detali.
Dodatkowe opcje dla fetch
Drugim parametrem fetch jest obiekt, który pozwala nam przekazywać dodatkowe opcje.
W większości przypadków interesować nas będzie głównie właściwość headers, za pomocą której będziemy ustawiać odpowiednie nagłówki oraz właściwość body, do której przekażemy przesyłaną treść.
Nagłówki
Jeżeli chcemy ustawić jakiś nagłówek wysyłając dane, powinniśmy ustawić je dla klucza headers:
Nagłówki takie możemy ustawiać jak powyżej (i zapewne tak będziemy robić najczęściej), ale możemy też skorzystać z interfejsu Headers(), który udostępnia nam dodatkowe metody do manipulacji pojedynczymi nagłówkami:
delete(key)
Usuwa wartość o danym kluczu
entries()
Zwraca iterator, który umożliwia zrobienie pętli po wszystkich parach klucz/wartość
get(key)
Zwraca pierwszy nagłówek o danym kluczu
getAll(key)
Zwraca tablicę wszystkich nagłówki o danym kluczu
has(key)
Sprawdza czy w zbiorze istnieje wartość o danym kluczu
set(key)
Ustawia nową wartość dla danego klucza
keys()
Zwraca listę kluczy z danego FormData
values()
Zwraca listę wartości z danego FormData
Możemy też skorzystać z bardziej skróconego zapisu:
Nie wszystkie nagłówki będziemy mogli ustawić w ten sposób.
Do nagłówków, które przyszły wraz z odpowiedzią (response headers) mamy dostęp przez właściwość response.headers:
Wysyłanie danych
Żeby wysłać dane musimy je ustawić we właściwości body oraz ustawić odpowiedni dla nich nagłówek za pomocą właściwości headers.
Działanie jest tutaj podobne jak w przypadku wysyłania danych za pomocą XMLHttpRequest.
Ponownie format danych zależny jest od metody kodowania jaką wybierzemy, ale też od danych jakie wysyłamy.
Jeżeli więc chcemy wysłać proste dane tekstowe, możemy zakodować je do formatu application/x-www-form-urlencoded (oraz ustawić odpowiedni nagłówek):
Jeżeli wysyłane dane są czymś więcej niż tylko prostymi parami klucz-wartość (np. zawierają pliki), powinniśmy skorzystać z kodowania multipart/form-data), a dane zakodować korzystając z interfejsu FormData():
Najczęściej w komunikacji z wszelakimi API będziemy wysyłać dane w postaci JSON.
W takim przypadku musimy ustawić odpowiedni nagłówek, a same dane zakodować za pomocą JSON.stringify():
Dodatkowe materiały
Dodatkowy mikro tutorial z używania fetch:
Last updated