Endpoint-Guide/Невеличкий гайд по http сервісу та requestʼах.md

6.0 KiB
Raw Blame History

Пару важливих речей:

  • Метод = функція
  • Класс != тип - в TS є такі штуки як AxiosResponse<IResponse<T>, any> і потрібно розуміти що ці штуки працюють зовсім по другому. Навіть якщо я десь забув поправити - це важливо памʼятати
  • any = unknown - формально мені б любий Senior Typescript девелопер язика за таке відірвав, але в цілому тут воно має різницю тільки в тому що при використанні того чи іншого ESlint видає різні помилки які треба виправляти. Це typescript, розслабся і получай задоволення

загальний перелік інструментів та ліб:

  • tanstack query
  • axios

піду з кінця:

коли ти хочеш відправити реквест на сервак, чи то Get чи то Post, звичайно це робиться через створений hook:

import { useQuery } from "@tanstack/react-query";
import { gameService } from "@/shared/services/game.service";
import { transformApiDataToGames } from "../components/gamesSlider/gamesSlider.utils";

export const useGetGames = () => {
  const query = useQuery({
    queryKey: ["games"],
    queryFn: gameService.getGames,
  });

  const games =
    query.data && query.data.length > 0
      ? transformApiDataToGames(query.data)
      : [];

  return { games, ...query };
};

тут можна побачити декілька речей:

  • хук використовує tanstack query для реквесту
  • танстак використовує допоміжну функцію класу GameService визначену в папці shared/services/
  • Після отримання даних, воно перетворюється на локальний класс Game, достатньо незручний спосіб, краще його не використовувати, але в цьому випадку було необхідно

тепер як видно по цим речам, нам треба допоможна сервісна функція, яка використовує не просто fetch(), а повноцінний написаний Діаною http service:

import { HttpService } from "./http.service";
import { axiosClient } from "./axios-client";
import { IGameApiResponse } from "../types/game.types";

export class GameService extends HttpService {
  getGames = async () => {
    const response = await this.get<IGameApiResponse[]>(`rpg-events`);
    return response;
  };
}

export const gameService = new GameService(axiosClient);

тут можна побачити що достає з сервака цей реквест, і що воно привʼязана до клієнта аксіоса, який і дозволяє використовувати http протокол.

подивившись ближче, можна побачити що в файлі https.service.ts є імплементація axiosClient - НЕ ДИВИСЬ НА НЕЇ - це дефолт, і він в нашому випадку на самий крайній випадок, справжня імплементація axiosClient яка використовується ось тут:

export const gameService = new GameService(axiosClient);

виходить з файлу axios-client.ts (я потратив не одну годину шукаючи і розбираючись що і де)

Отже, axiosClient є імплементацією яка повністю повинна замінити fetch(), та з досвіду - працює набагато краще

Те що найголовніше для фетчингу ігор є в цій функції get:

public async get<T>(
    url: string,
    config?: IHttpConfig,
  ): Promise<AxiosResponse<IResponse<T>, any>> {
    const response = await this.axiosInstance.get<IResponse<T>>(
      url,
      config as AxiosRequestConfig,
    );

    return response;
  }

звідси треба розуміти тільки те що Promise<AxiosResponse<IResponse<T>, any>> це тип, який проходить через ще один шар, що є в класі HttpService.

 public async get<T>(url: string, config?: IHttpConfig): Promise<T> {
    return this.fetchingService
      .get<AxiosResponse<IResponse<T>, unknown>>(this.getFullApiUrl(url), {
        ...config,
        headers: {
          ...config?.headers,
          ...this.populateContentTypeHeaderConfig(),
        },
      })
      .then((result) => {
        this.checkResponseStatus(result);
        return result.data as T;
      });
  }

// допоміжна функція для знаходження повного url
// працює дивно коли в url є localhost, але якщо вписати в NEXT_PUBLIC_BACKEND_URL=https://inrium.org.ua/api то буде працювати бездоганно
  private getFullApiUrl(url: string): string {
    return `${this.baseUrl}/${url}`;
  }

ось це і є та самий метод який є тут, та який тобі і вертає T напряму звідси:

// rpg-events - частина повної url: http[s]://[NEXT_PUBLIC_BACKEND_URL | BASE_URL]/api/rpg-events. 
const response = await this.get<IGameApiResponse[]>(`rpg-events`);
return response

тому response в цьому випадку має тип IGameApiResponse[].

В загальному це виглядає так:

request by hook -> http.service -> axios-client axios-client фетчить потрібні дані з сервака, і якщо помилок немає то передає на const response

Не бійся задавати найпростіші та найтупіші питання, відповім на все