# API Services I Mocki Data: 2026-04-29 ## Cel dokumentu Ten dokument opisuje warstwe API we frontendzie. Warstwa API znajduje sie w: ```txt frontend/src/services/ ``` Jej zadaniem jest odseparowanie store od szczegolow komunikacji HTTP. Store nie powinien wiedziec: - jaki dokladnie jest URL endpointu, - czy komunikacja idzie przez Axios, - czy dane pochodza z prawdziwego backendu, - czy dane pochodza z mockow JSON. Store powinien wywolac funkcje domenowa, np.: ```js fetchProducts(params) ``` a service powinien zajac sie reszta. ## Aktualne pliki services ```txt frontend/src/services/apiMode.js frontend/src/services/productsApi.js frontend/src/services/productsHttpApi.js frontend/src/services/productTimelineApi.js frontend/src/services/productTimelineHttpApi.js frontend/src/services/productSpecificationApi.js frontend/src/services/productSpecificationHttpApi.js frontend/src/services/dictionariesApi.js frontend/src/services/dictionariesHttpApi.js ``` Pliki `*Api.js` sa fasadami. Wybieraja implementacje na podstawie `USE_MOCK_API`. Pliki `*HttpApi.js` sa implementacja prawdziwego API przez Axios. Implementacje mockow sa poza katalogiem `services`: ```txt frontend/src/mocks/api/productsMockApi.js frontend/src/mocks/api/productTimelineMockApi.js frontend/src/mocks/api/productSpecificationMockApi.js frontend/src/mocks/api/dictionariesMockApi.js ``` ## Przeplyw danych Docelowy przeplyw wyglada tak: ```txt komponent Vue -> store Pinia -> service API -> mock JSON albo Axios -> backend Directus ``` Przyklad: ```txt IndexPage.vue -> productsStore.fetchFirstPage() -> fetchProducts(params) -> productsMockApi albo productsHttpApi -> products.json albo GET /mayo-api/products ``` ## Dlaczego services sa osobna warstwa Bez services store musialby robic cos takiego: ```js api.get('/mayo-api/products', { params }) ``` Wtedy store zna: - Axios, - endpoint, - strukture odpowiedzi HTTP. To miesza odpowiedzialnosci. Po wydzieleniu services store robi: ```js const { items, pageInfo } = await fetchProducts(params) ``` To jest lepsze, bo: - store skupia sie na stanie aplikacji, - services skupiaja sie na komunikacji, - endpoint mozna zmienic w jednym miejscu, - latwiej dodac mocki, - latwiej testowac logike store. Po ostatnim porzadkowaniu services sa fasadami. Przyklad: ```js export const fetchProducts = USE_MOCK_API ? fetchProductsFromMock : fetchProductsFromHttp ``` Dzieki temu `productsStore` zawsze importuje to samo: ```js import { fetchProducts } from 'src/services/productsApi' ``` ale realna implementacja moze byc mockowa albo HTTP. ## `apiMode.js` Plik: ```txt frontend/src/services/apiMode.js ``` Zawiera przelacznik miedzy mock API i prawdziwym API: ```js export const USE_MOCK_API = import.meta.env.VITE_USE_MOCK_API !== 'false' ``` To oznacza: - domyslnie mocki sa wlaczone, - jesli ustawisz `VITE_USE_MOCK_API=false`, aplikacja uzyje prawdziwego backendu. Uruchomienie z prawdziwym backendem: ```bash VITE_USE_MOCK_API=false npm run dev ``` Uruchomienie z mockami: ```bash npm run dev ``` Mocki maja sztuczne opoznienie: ```js waitForMockApi() ``` Dzieki temu podczas pracy nad UI widac stany ladowania podobne do prawdziwego API. ## Pliki mockow Mocki sa zwyklymi plikami JSON: ```txt frontend/src/mocks/products.json frontend/src/mocks/timelines.json frontend/src/mocks/specifications.json frontend/src/mocks/dictionaries.json ``` Sa uzywane tylko przez implementacje mock API w `frontend/src/mocks/api/`. Komponenty, store i fasady `services/*Api.js` nie importuja plikow JSON bezposrednio. To jest wazne, bo komponent nie powinien wiedziec, skad przyszly dane. Dla komponentu dane z mocka i z backendu powinny wygladac identycznie. ## `productsApi.js` i `productsHttpApi.js` Plik: ```txt frontend/src/services/productsApi.js frontend/src/services/productsHttpApi.js ``` Eksportuje: ```js fetchProducts(params) ``` Odpowiedzialnosc: - pobranie listy produktow, - obsluga filtrow, - obsluga `limit` i `offset`, - zwrocenie danych w formacie oczekiwanym przez `productsStore`. `productsApi.js` jest fasada. `productsHttpApi.js` zna Axios i endpoint: ```http GET /mayo-api/products ``` Zwraca: ```js { items: [], pageInfo: { limit: 30, offset: 0, hasMore: true, total: 184, }, } ``` W trybie mock implementacja jest w: ```txt frontend/src/mocks/api/productsMockApi.js ``` W trybie mock: - czyta `frontend/src/mocks/products.json`, - filtruje po `orderSearch`, `finish`, `year`, `productionList`, - ucina wynik wedlug `limit` i `offset`, - zwraca `items` i `pageInfo`. W trybie prawdziwego API implementacja jest w `productsHttpApi.js`: ```http GET /mayo-api/products ``` z parametrami: ```js { limit, offset, search, orderSearch, model, client, finish, productionList, year, } ``` `orderSearch` powstaje w `productsStore` przez parser: ```txt frontend/src/utils/orderSearchParser.js ``` Do HTTP `orderSearch` jest serializowane jako JSON string, bo endpoint listy jest typu `GET`. ## `productTimelineApi.js` i `productTimelineHttpApi.js` Plik: ```txt frontend/src/services/productTimelineApi.js frontend/src/services/productTimelineHttpApi.js ``` Eksportuje: ```js fetchProductTimeline(productId) createProductTimelineEvent(productId, payload) ``` ### `fetchProductTimeline` Pobiera pelny timeline produktu. W trybie mock implementacja jest w: ```txt frontend/src/mocks/api/productTimelineMockApi.js ``` W trybie mock: - czyta `frontend/src/mocks/timelines.json`, - zwraca timeline dla `productId`, - jesli brak danych, zwraca pusty timeline. W trybie prawdziwego API implementacja jest w `productTimelineHttpApi.js`: ```http GET /mayo-api/products/:id/timeline ``` ### `createProductTimelineEvent` Dodaje event do timeline. W trybie mock: - tworzy sztuczny event, - dodaje go do pamieci mockow, - przelicza `timelinePreview`, - zwraca nowy event i nowy preview. W trybie prawdziwego API: ```http POST /mayo-api/products/:id/timeline/events ``` Zwracany format: ```js { event: {}, timelinePreview: { body: [], neck: [], }, } ``` To pozwala store od razu zaktualizowac: - pelny timeline, - preview na glownej karcie produktu. ## `productSpecificationApi.js` i `productSpecificationHttpApi.js` Plik: ```txt frontend/src/services/productSpecificationApi.js frontend/src/services/productSpecificationHttpApi.js ``` Eksportuje: ```js fetchProductSpecification(productId) refreshProductSpecification(productId) ``` ### `fetchProductSpecification` Pobiera specyfikacje produktu. W trybie mock implementacja jest w: ```txt frontend/src/mocks/api/productSpecificationMockApi.js ``` W trybie mock: - czyta `frontend/src/mocks/specifications.json`. W trybie prawdziwego API implementacja jest w `productSpecificationHttpApi.js`: ```http GET /mayo-api/products/:id/specification ``` ### `refreshProductSpecification` Odswieza specyfikacje produktu. W trybie mock: - zwraca dane z mocka, - aktualizuje `lastFetchedAt` na aktualny czas. W trybie prawdziwego API: ```http POST /mayo-api/products/:id/specification/refresh ``` ### Normalizacja odpowiedzi Ten plik zawiera funkcje: ```js normalizeSpecificationResponse(data) ``` Jej zadaniem jest zamiana odpowiedzi backendu na prosty format dla store: ```js { productId, orderId, sourceUrl, lastFetchedAt, sections, diff, } ``` Service akceptuje dwa ksztalty: ```js data.specification.sections ``` albo: ```js data.sections ``` Dzieki temu store nie musi znac szczegolow odpowiedzi HTTP. ## `dictionariesApi.js` i `dictionariesHttpApi.js` Plik: ```txt frontend/src/services/dictionariesApi.js frontend/src/services/dictionariesHttpApi.js ``` Eksportuje: ```js fetchDictionaries() ``` Odpowiedzialnosc: - pobranie slownikow do filtrow i formularzy, - normalizacja pustych pol do pustych tablic. W trybie mock implementacja jest w: ```txt frontend/src/mocks/api/dictionariesMockApi.js ``` W trybie mock: - czyta `frontend/src/mocks/dictionaries.json`. W trybie prawdziwego API implementacja jest w `dictionariesHttpApi.js`: ```http GET /mayo-api/dictionaries ``` Zwraca: ```js { models: [], clients: [], finishes: [], productionLists: [], operations: [], colors: [], } ``` ## Jak dodac nowy endpoint Przyklad: chcesz dodac API do zdjec produktu. Nie dodawaj Axiosa bezposrednio w komponencie ani w store. Zrob nowy service: ```txt frontend/src/services/productPhotosApi.js frontend/src/services/productPhotosHttpApi.js frontend/src/mocks/api/productPhotosMockApi.js ``` Fasada: ```js import { fetchProductPhotos as fetchProductPhotosFromHttp } from 'src/services/productPhotosHttpApi' import { fetchProductPhotos as fetchProductPhotosFromMock } from 'src/mocks/api/productPhotosMockApi' import { USE_MOCK_API } from 'src/services/apiMode' export const fetchProductPhotos = USE_MOCK_API ? fetchProductPhotosFromMock : fetchProductPhotosFromHttp ``` Implementacja HTTP: ```js import { api } from 'src/boot/axios' export async function fetchProductPhotos(productId) { const response = await api.get(`/mayo-api/products/${productId}/photos`) return response.data } ``` Dopiero potem store importuje: ```js import { fetchProductPhotos } from 'src/services/productPhotosApi' ``` ## Zasady pracy z mockami Mocki powinny miec taki sam ksztalt jak prawdziwe API. To jest najwazniejsza zasada. Jesli prawdziwy endpoint ma zwrocic: ```js { items: [], pageInfo: {} } ``` to mock tez powinien zwrocic: ```js { items: [], pageInfo: {} } ``` Nie nalezy robic osobnych struktur danych tylko dla widoku, jesli nie beda zgodne z przyszlym API. ## Co zostalo juz zrobione Utworzono: ```txt frontend/src/services/apiMode.js frontend/src/services/productsApi.js frontend/src/services/productsHttpApi.js frontend/src/services/productTimelineApi.js frontend/src/services/productTimelineHttpApi.js frontend/src/services/productSpecificationApi.js frontend/src/services/productSpecificationHttpApi.js frontend/src/services/dictionariesApi.js frontend/src/services/dictionariesHttpApi.js ``` Utworzono dane mockow: ```txt frontend/src/mocks/products.json frontend/src/mocks/timelines.json frontend/src/mocks/specifications.json frontend/src/mocks/dictionaries.json ``` Utworzono implementacje mock API: ```txt frontend/src/mocks/api/productsMockApi.js frontend/src/mocks/api/productTimelineMockApi.js frontend/src/mocks/api/productSpecificationMockApi.js frontend/src/mocks/api/dictionariesMockApi.js ``` Zaktualizowano store tak, aby uzywaly services zamiast Axiosa bezposrednio. Zaktualizowano widok glownej strony tak, aby pobieral dane ze store zamiast trzymac lokalne mocki w komponencie. ## Najwazniejsza regula Komponenty nie powinny importowac: ```js api ``` ani: ```js src/mocks/*.json ``` Komponent powinien uzywac store albo dostawac dane przez props. Store powinien uzywac services. Services powinny uzywac Axiosa albo mockow.