← Wszystkie wpisy

API i helpers

Mockuj odpowiedzi API, przechwytując fetch i XHR

Backend nie jest gotowy. Albo jest gotowy, ale nie potrafisz zmusić go, aby na żądanie zwrócił pustą listę, błąd 500 i trzysekundowe opóźnienie. Ten artykuł pokazuje, jak przechwycić fetch i XMLHttpRequest bezpośrednio w przeglądarce za pomocą reguły JS w JustZix, zwracając fałszywy JSON, abyś mógł budować i testować frontend pod dowolny scenariusz, jaki tylko chcesz.

Po co w ogóle przechwytywać w przeglądarce

Zwykła odpowiedź na „potrzebuję fałszywych danych” to serwer mockujący — MSW, json-server, zaślepka w środowisku deweloperskim. Są świetne i dla całego zespołu to właściwy wybór. Ale czasem chcesz czegoś lżejszego:

Reguła JS w JustZix żyje w przeglądarce, stosuje się według wzorca URL i nie wymaga żadnych zmian w projekcie. To jej nisza: szybkie, chirurgiczne, łatwe do wyrzucenia mockowanie.

Owijanie window.fetch

Główna sztuczka to zastąpienie window.fetch własną funkcją, która decyduje, per żądanie, czy zamockować, czy przepuścić. Uruchom to na document_start, aby było zainstalowane zanim jakikolwiek kod aplikacji wywoła fetch:

// Save the original so we can fall through to the real network
const realFetch = window.fetch.bind(window);

// Your mock table: match by URL substring -> response factory
const mocks = [
  {
    match: '/api/user/profile',
    response: () => jsonResponse({ id: 1, name: 'Ada Lovelace', plan: 'pro' })
  },
  {
    match: '/api/orders',
    response: () => jsonResponse([])   // the empty-list edge case
  }
];

window.fetch = async (input, init) => {
  const url = typeof input === 'string' ? input : input.url;
  const hit = mocks.find(m => url.includes(m.match));
  if (hit) {
    console.log('[mock] intercepted', url);
    return hit.response();
  }
  return realFetch(input, init);   // not mocked -> real request
};

Budowanie syntetycznego Response

Twoja aplikacja oczekuje prawdziwego obiektu Response — wywoła na nim .json(), sprawdzi .ok, odczyta .status. Konstruktor Response daje Ci to wszystko za darmo:

// Helper: a 200 OK JSON response
function jsonResponse(data, status = 200) {
  return new Response(JSON.stringify(data), {
    status,
    headers: { 'Content-Type': 'application/json' }
  });
}

Ponieważ to autentyczny Response, kod, który robi const r = await fetch(...); if (r.ok) return r.json();, działa bez modyfikacji. O to właśnie chodzi — aplikacja nie potrafi zauważyć różnicy.

Symulowanie opóźnień

Puste listy i ścieżki szczęśliwe są łatwe. Błędy żyją w wolnej ścieżce: spinnery, które nigdy nie znikają, wyścigi, podwójne wysyłki. Dodaj opóźnienie przed rozwiązaniem:

// A small sleep helper
const sleep = (ms) => new Promise(r => setTimeout(r, ms));

// In the mock table, await it before returning
{
  match: '/api/search',
  response: async () => {
    await sleep(3000);            // 3 seconds of "loading..."
    return jsonResponse({ results: [] });
  }
}

Symulowanie kodów błędów

Teraz ścieżki nieszczęśliwe. 500, 404, 401, które powinno odbić Cię do logowania — zwróć je z właściwym statusem, aby Twoja obsługa błędów faktycznie się uruchomiła:

// 500 Internal Server Error
{
  match: '/api/checkout',
  response: () => jsonResponse(
    { error: 'payment_gateway_timeout' },
    500
  )
}

// A network failure (fetch rejects, not resolves)
{
  match: '/api/flaky',
  response: () => Promise.reject(new TypeError('Failed to fetch'))
}

Zwróć uwagę na różnicę: 500 nadal rozwiązuje się z r.ok === false, podczas gdy zerwane połączenie odrzuca się. Testuj oba — aplikacje często obsługują jeden, a wywalają się na drugim.

Owijanie XMLHttpRequest

Mnóstwo starszego kodu, a także biblioteki takie jak axios, wciąż używa XMLHttpRequest pod spodem. Przechwytywanie fetch ich nie dotyka. XHR jest bardziej toporny do podrobienia, ale cienka nakładka pokrywa typowy przypadek:

const RealXHR = window.XMLHttpRequest;

window.XMLHttpRequest = function () {
  const xhr = new RealXHR();
  const realOpen = xhr.open;
  let mockedUrl = null;

  xhr.open = function (method, url, ...rest) {
    if (url.includes('/api/legacy')) mockedUrl = url;
    return realOpen.call(this, method, url, ...rest);
  };

  const realSend = xhr.send;
  xhr.send = function (...args) {
    if (!mockedUrl) return realSend.apply(this, args);

    // Fake a successful response without hitting the network
    setTimeout(() => {
      Object.defineProperty(xhr, 'readyState', { value: 4 });
      Object.defineProperty(xhr, 'status', { value: 200 });
      Object.defineProperty(xhr, 'responseText', {
        value: JSON.stringify({ legacy: true })
      });
      xhr.onreadystatechange && xhr.onreadystatechange();
      xhr.onload && xhr.onload();
    }, 0);
  };

  return xhr;
};

Jest to celowo minimalne — pokrywa onload / onreadystatechange z tekstem JSON, czyli to, czego potrzebuje 90% kodu XHR. Jeśli biblioteka inspekcjonuje getAllResponseHeaders(), będziesz musiał zaślepić i to. W tym momencie, szczerze mówiąc, sięgnij po prawdziwy serwer mockujący.

Kiedy zamiast tego użyć prawdziwego serwera mockującego

Przechwytywanie w przeglądarce to właściwe narzędzie do szybkiej, ograniczonej, jednorazowej pracy. Przejdź na MSW lub json-server, gdy:

Zasada kciuka: jeśli mock ma trafić do repozytorium, użyj serwera. Jeśli ma zniknąć, gdy wyłączysz regułę, użyj JustZix.

Zobacz też

Przestań czekać na backend. Zainstaluj JustZix, wrzuć nakładkę na fetch do ograniczonej reguły JS i buduj frontend pod każdy scenariusz jeszcze dziś.

Oceń ten wpis

Brak ocen — oceń jako pierwszy.

Wypróbuj samodzielnie

Zainstaluj JustZix i wklej dowolny snippet z tego artykułu. Dwie minuty od zera do działającej reguły na wszystkich Twoich urządzeniach.

Pobierz JustZix

Funkcje · Jak to działa · Przykłady · Zastosowania