Fetch API

Nowe przeglądarki udostępniają nam Fetch API - nowy interfejs do dynamicznego pobierania zasobów.

Jako, że fetch jest dość nowy, w poniższych skryptach będziemy wykorzystywać nowe rozwiązania takie jak funkcja strzałkowa, template string itp.

Pobieranie danych

Do naszych testów skorzystamy z darmowego API mieszczącego się pod adresem https://jsonplaceholder.typicode.com/.

Po wejściu na tą stronę widzimy, że aby pobrać użytkowników, musimy połączyć się na adres https://jsonplaceholder.typicode.com/users.

Wykonajmy podstawowe połączenie w celu pobrania danych:


fetch('https://jsonplaceholder.typicode.com/users')
    .then(resp => {
        console.log(resp);
    })

Po odpaleniu fetch zwraca Promise, więc tak samo jak w tamtym rozdziale, możemy je obsłużyć za pomocą dostępnych dla Promisow metod - then, all i catch.

Po wywołaniu powyższego skryptu naszym oczom w konsoli pokaże się mniej więcej coś takiego:

response fetch

Czyli dostaliśmy odpowiedź. Jak widzisz, wśród właściwości mamy status 200, statusText, url itp.

Właściwa odpowiedź jest przetrzymywana pod właściwością body. Aby ją odczytać musimy zastosować odpowiednią metodę, która skonwertuje tą właściwość na odpowiedni format. W naszym przypadku oczekujemy json, więc zastosujmy metodę response.json(). Dla innych typów danych trzeba by użyć innych metod - np. dla tekstu response.text(), a dla grafik response.blob()


fetch('https://jsonplaceholder.typicode.com/users')
    .then(resp => resp.json())
    .then(resp => {
        console.log("Przykład 2:");
        console.log(resp);
    })

Naszym oczom w konsoli debugera ukaże się lista użytkowników. Zróbmy więc po niej prostą pętlę:


fetch('https://jsonplaceholder.typicode.com/users')
    .then(resp => resp.json())
    .then(resp => {
        console.log(resp);
        resp.forEach(user => {
            console.groupCollapsed(`Użytkownik ${user.id}`)
            console.log(`Nazwa: ${user.name}`);
            console.log(`Nazwa użytkownika: ${user.username}`);
            console.log(`Email: ${user.email}`);
            console.log(`Adres: ${user.address.city} ${user.address.street} ${user.address.zipcode}`);
            console.log(`WWW: ${user.website}`);
            console.groupEnd();
        })
    })

Wysyłanie danych

Wysyłanie danych jest równie proste. Po wejściu na stronę https://jsonplaceholder.typicode.com/posts, widzimy, że każdy post składa się z id, title, userId i body. ID jest automatycznie zwiększane, więc musimy wysłać tylko pozostałe właściwości:


const ob = {
    title: 'Nazwa posta',
    body: 'Lorem ipsum dolor sit amet consectetur...',
    userId: 1
};

fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(ob)
    })
    .then(res => res.json())
    .then(res => {
        console.log('Dodałem użytkownika:');
        console.log(res);
    })

Jak widzisz aby wysłać json za pomocą fetch musimy zrobić klasyczne czynności. Po pierwsze musimy poinformować serwer, że wysyłamy mu json. Robimy to za pomocą nagłówka 'Content-Type': 'application/json'. Po drugie musimy zamienić nasz obiekt na odpowiedni zapis. Wykorzystujemy tutaj JSON.stringify(). Podobną metodę stosowaliśmy do zapisu obiektów do customowych atrybutów

Api do którego się łączymy nie zapisuje realnie użytkowników, ale tylko symuluje. W odpowiedzi dostaliśmy użytkownika o id:101, co oznacza, że zostało symulowane dodanie do bazy nowego użytkownika (normalnie było ich 100).

Błędy w połączeniu

Spróbujmy na początek połączyć się na błędny adres:


fetch('https://jsonplaceholder.typicode.com/kaszanka')
    .then(resp => {
        console.log('Odpowiedź:');
        console.dir(resp)
    })
    .catch(error => console.log('Błąd: ', error));

Teoretycznie wystąpił błąd, więc powinien się odpalić catch. Nic takiego jednak się nie stało, bo w konsoli debugera otrzymaliśmy odpowiedź prawie jak przy naszym pierwszym połączeniu. Różnice są w niektórych właściwościach:

response 404

Jak widzimy, status zmienił się na 404, statusText na "Not Found", a właściwość ok zmieniła się na false.

Aby obsłużyć błędne zapytania, musimy w then() obsłużyć powyższe właściwości:


fetch('https://jsonplaceholder.typicode.com/kaszanka')
    .then(resp => {
        if (resp.ok) {
            return response.json()
        } else {
            throw new Error('Wystąpił błąd połączenia!')
        }
    })
    .then(resp => {
        console.log(resp)
    })
    .catch(error => console.dir('Błąd: ', error));

Żeby jeszcze dokładniej poinformować użytkownika o wynikłym błędzie, możemy skorzystać z Promise, który po zwróceniu reject przeskoczy do catch:


fetch('https://jsonplaceholder.typicode.com/kaszanka')
    .then(resp => {
        .then(resp => {
            if (resp.ok) {
                return response.json()
            } else {
                return Promise.reject(resp)
            }
        })
        .then(resp => {
            console.log(resp)
        })
        .catch(error => {
            if (error.status === 404) {
                console.log('Błąd: żądany adres nie istnieje');
            }
        });
    });

Trening czyni mistrza

Poniżej zamieszczam kilka zadań, które w ramach ćwiczenia możesz wykonać:

  1. Przejdź na stronę http://mailtest.in/documentation/

    Twoim zadaniem jest:
    - stwórz formularz, który będzie miał jedno pole na email oraz button submit
    - podepnij się pod wysyłanie formularza i przerwij domyślną akcję.
    Za pomocą fetch wyślij dane na odpowiedni adres. Sprawdź na powyższej stronie jak ma on wyglądać. W zależności od odpowiedzi wyświetl w konsoli stosowny komunikat.

  2. Przejdź na stronę https://developers.google.com/books/docs/v1/using#WorkingVolumes
    Za pomocą fetch pobierz liste książek o tematyce "wiedzmin".

    Zrób pętlę po wynikach i wrzuć ładnie sformatowane dane do html. Dane niech zawierają:
    - tytuł książki
    - autorzy
    - liczbę podstron
    - link do poglądu
    - czy dostępne w formie pdf

    Do formatowania danych użyj template strings