Uwaga! Trwają prace nad nową wersją serwisu. Mogą występować przejściowe problemy z jego funkcjonowaniem. Przepraszam za niedogodności!

🔥 Zgarnij PŁATNY STAŻ w 3 edycji kursu programowania front end (zapisy do 22.01) 🔥

Limity API w nauce programowania – obejdź to!

Jak tworzyć kod asynchroniczny bez ograniczeń API

Uczysz się obsługi kodu asynchronicznego w JavaScripcie, a tu nagle błąd: skończył Ci się limit zapytań! Spokojnie, da się to obejść – nawet na co najmniej dwa sposoby. Po lekturze tego artykułu będziesz wiedzieć, po co twórcy API nakładają limity i jak poradzić sobie z nimi podczas nauki programowania.

Spis treści

 Limity API – czym są?

 Co to jest API

API, czyli Application Programming Interface, to zestaw reguł określających sposób komunikacji między systemami komputerowymi. Dzięki nim możemy wysyłać żądania (zapytania) do zewnętrznych zasobów (np. serwera z danymi o pogodzie) i otrzymywać odpowiedzi.

 Dlaczego twórcy API ograniczają liczbę zapytań

Ograniczenia mogą być różne: konkretny limit zapytań na minutę, godzinę czy dobę. Czemu to służy? Celem jest ochrona systemu przed przeciążeniem – duża liczba zapytań spowodowałaby, że usługa działałaby wolniej lub wcale.

Nie zdziwi Cię pewnie również to, że limity służą do kontrolowania kosztów i wydajności usługi. Stworzenie płatnych planów z większym limitem zapytań to nie tylko biznes, ale możliwość dostosowania infrastruktury do wymagań klientów. Przykładowo: jeśli wzrasta liczba klientów opłacających usługę, możemy zaplanować zakup kolejnych serwerów.

 Jak obejść limity API

Kod, który odpytuje API, będzie się uruchamiał po każdym odświeżeniu strony (czyli po każdym zapisaniu pliku, gdy korzystamy z automatycznego odświeżania). Jeśli więc API w darmowym planie ogranicza zapytania np. do 50, to limit ten bardzo szybko się wyczerpie.

Możemy sobie z tym poradzić, tymczasowo tworząc „fake’owe API”, i dopiero na końcu, gdy nasz projekt jest gotowy, podmienić kod na właściwy. Są na to co najmniej dwa sposoby.

 Zwróć obiekt imitujący dane z API

Twoja funkcja odpytująca API może wyglądać mniej więcej tak:

async function get() {
  try {
    const response = await fetch('https://catfact.ninja/fact');
    if (response.ok) {
      const data = await response.json();
      return data;
    }
    throw new Error(response.statusText);
  } catch (error) {
    console.error(error);
  } finally {
    console.log('Odpytywanie API zakończone!');
  }
}

const response = await get();
console.log(response.fact);

Lub z wykorzystaniem metody then w ten sposób:

async function get() {
  const promise = fetch('https://catfact.ninja/fact');
  return promise
    .then(resp => {
      if (resp.ok) {
        return resp.json();
      }
      return Promise.reject(resp);
    })
    .catch(err => console.error(err))
    .finally(() => {
      console.log('Odpytywanie API zakończone!');
    });
}

get().then(response => {
  console.log(response.fact);
});

Tymczasowo zakomentuj część kodu (koniecznie pamiętaj zakomentować też linię z funkcją fetch!) i zwróć własną obietnicę z obiektem, który odpowiada temu, co dostajesz z API.

Dla zapisu z async…await będzie to wyglądać tak:

async function get() {
  try {
    //   const response = await fetch('https://catfact.ninja/fact');
    //   if (response.ok) {
    //     const data = await response.json();
    //     return data;
    //   }
    //   throw new Error(response.statusText);
    return {
      fact: 'A cat cannot see directly under its nose.',
      length: 41
    }
  } catch (error) {
    console.error(error);
  } finally {
    console.log('Odpytywanie API zakończone!');
  }
}

const response = await get();
console.log(response.fact);

Natomiast w wersji z then tak:

async function get() {
  //   const promise = fetch('https://catfact.ninja/fact');
  //   return promise
  //     .then(resp => {
  //       if (resp.ok) {
  //         return resp.json();
  //       }
  //       return Promise.reject(resp);
  //     })
  return new Promise(function (resolve) {
    resolve({
      fact: 'A cat cannot see directly under its nose.',
      length: 41,
    });
  })
    .catch(err => console.error(err))
    .finally(() => {
      console.log('Odpytywanie API zakończone!');
    });
}

get().then(resp => {
  console.log(resp.fact);
});

Jeśli chcesz rozbudować tymczasowy obiekt z danymi symulującym zwrot z API i jednocześnie nie „zaciemniać” sobie obrazu funkcji pobierającej dane, możesz po prostu zapisać obiekt w osobnej zmiennej w ten sposób:

const data = {
  fact: 'A cat cannot see directly under its nose.',
  length: 41
}

async function get() {
  try {
    //   const response = await fetch('https://catfact.ninja/fact');
    //   if (response.ok) {
    //     const data = await response.json();
    //     return data;
    //   }
    //   throw new Error(response.statusText);
    return data
  } catch (error) {
    console.error(error);
  } finally {
    console.log('Odpytywanie API zakończone!');
  }
}

const response = await get();
console.log(response.fact);

Zwróć uwagę, że w obecnej sytuacji dalsza część kodu (z .catch i .finally) nigdy się nie wykona, ponieważ wyżej zawsze zwracamy rozwiązaną obietnicę. Zostawiamy go jednak, ponieważ docelowo będzie nam potrzebny, gdy już przywrócimy fetchowanie danych z prawdziwego API.

To wszystko. Możesz „odpytywać” swoje fake’owe API do woli bez obaw o limity!

 Przełączaj tryby w klasie obsługującej API

Aby nie musieć cały czas zaglądać do kodu obsługującego API i zakomentowywać lub odkomentowywać danych fragmentów, możemy stworzyć klasę z „przełącznikiem”.

Zwróć uwagę, że poniżej przedstawiona metoda get spełnia tę samą rolę, co funkcja get we wcześniejszych przykładach. Jedyne, co zrobiliśmy to:

  • przenieśliśmy obsługę obietnicy do osobnej metody fetchData (żeby zwiększyć czytelność kodu),
  • w metodzie get dodaliśmy warunek, dzięki któremu albo zwracamy dane z prawdziwego API, albo naszą fake’ową obietnicę.

Przełączanie między fake’owym a prawdziwym API odbywa się dzięki właściwości fakeAPIActive. Domyślnie jest ona ustawiona na false – jeżeli więc nie zmienimy jej umyślnie, będziemy łączyć się z prawdziwym API.

class CatFactsProvider {
  constructor(url) {
    this.url = url;
    this.fakeAPIActive = false;
  }

  getFakeData() {
    return new Promise(function (resolve) {
      resolve({
        fact: 'A cat cannot see directly under its nose.',
        length: 41,
      });
    });
  }

  get() {
    if (this.fakeAPIActive) {
      return this.getFakeData();
    } else {
      return this.fetchData();
    }
  }

  fetchData() {
    const promise = fetch(this.url);
    return promise
      .then(resp => {
        if (resp.ok) {
          return resp.json();
        }
        return Promise.reject(resp);
      })
      .catch(err => console.error(err))
      .finally(() => {
        console.log('Odpytywanie API zakończone!');
      });
  }
}

export default CatFactsProvider;

Jeśli chcesz dowiedzieć się więcej o takim porządkowaniu kodu obsługującego API, zapraszam Cię do artykułu „CRUD w osobnym pliku – lepszy kod dla API”.

Importujemy teraz klasę CatFactsProvider do pliku index.js (bo tam chcemy skorzystać z API). Na jej podstawie tworzymy obiekt api (pamiętamy o przekazaniu adresu URL interesujących nas zasobów) oraz ustawiamy właściwość api.fakeAPIActive na true, ponieważ chcemy skorzystać z fake’owych danych.

import CatFactsProvider from './CatFactsProvider.js';

document.addEventListener('DOMContentLoaded', function () {
  const api = new CatFactsProvider('https://catfact.ninja/fact');
  api.fakeAPIActive = true; //uruchamiam fake'owe API

  api.get().then(function (response) {
    console.log(response.fact);
  });
});

Gotowe. Od teraz nie musisz zakomentowywać i odkomentowywać kodu fake’owej obietnicy, wystarczy zmienić true na false i odwrotnie!

 Wykorzystaj JSON Server

To rozwiązanie jest bardziej czasochłonne, więc póki zależy Ci tylko na pobieraniu danych z API, raczej bym się na nie nie decydował.

Warto jednak sięgnąć po JSON Server, gdy chcesz przećwiczyć pozostałe operacje: aktualizację, dodawanie i usuwanie danych przez API.

Wszystko, co jest potrzebne do rozpoczęcia pracy z tym serwerem lokalnym, znajdziesz w artykule „JSON Server – asynchroniczny JavaScript z lokalnym API”.

 

Od teraz nie musisz martwić się limitem zapytań. Pamiętaj tylko, aby przywrócić poprzedni kod realnie odpytujący API, gdy będziesz już wrzucać projekt do portfolio lub oddawać go do code review.

Udostępnij ten artykuł:

Mentoring to efektywna nauka pod okiem doświadczonej osoby, która:

  • przekazuje Ci swoją wiedzę i nadzoruje Twoje postępy w zdobywaniu umiejętności,
  • uczy Cię dobrych praktyk i wyłapuje złe nawyki,
  • wspiera Twój rozwój i zwiększa zaangażowanie w naukę.

Mam coś dla Ciebie!

W każdy piątek rozsyłam motywujący do nauki programowania newsletter!

Dodatkowo od razu otrzymasz ode mnie e-book o wartości 39 zł. To ponad 40 stron konkretów o nauce programowania i pracy w IT.

PS Zazwyczaj wysyłam 1-2 wiadomości na tydzień. Nikomu nie będę udostępniał Twojego adresu e-mail.