# 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/productTimelineApi.js frontend/src/services/productSpecificationApi.js frontend/src/services/dictionariesApi.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) -> 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. ## `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 warstwe `services`. Komponenty i store nie importuja mockow 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` Plik: ```txt frontend/src/services/productsApi.js ``` Eksportuje: ```js fetchProducts(params) ``` Odpowiedzialnosc: - pobranie listy produktow, - obsluga filtrow, - obsluga `limit` i `offset`, - zwrocenie danych w formacie oczekiwanym przez `productsStore`. Zwraca: ```js { items: [], pageInfo: { limit: 30, offset: 0, hasMore: true, total: 184, }, } ``` W trybie mock: - czyta `frontend/src/mocks/products.json`, - filtruje po `search`, `finish`, `year`, `productionList`, - ucina wynik wedlug `limit` i `offset`, - zwraca `items` i `pageInfo`. W trybie prawdziwego API: ```http GET /mayo-api/products ``` z parametrami: ```js { limit, offset, search, model, client, finish, productionList, year, } ``` ## `productTimelineApi.js` Plik: ```txt frontend/src/services/productTimelineApi.js ``` Eksportuje: ```js fetchProductTimeline(productId) createProductTimelineEvent(productId, payload) ``` ### `fetchProductTimeline` Pobiera pelny timeline produktu. W trybie mock: - czyta `frontend/src/mocks/timelines.json`, - zwraca timeline dla `productId`, - jesli brak danych, zwraca pusty timeline. W trybie prawdziwego API: ```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` Plik: ```txt frontend/src/services/productSpecificationApi.js ``` Eksportuje: ```js fetchProductSpecification(productId) refreshProductSpecification(productId) ``` ### `fetchProductSpecification` Pobiera specyfikacje produktu. W trybie mock: - czyta `frontend/src/mocks/specifications.json`. W trybie prawdziwego API: ```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` Plik: ```txt frontend/src/services/dictionariesApi.js ``` Eksportuje: ```js fetchDictionaries() ``` Odpowiedzialnosc: - pobranie slownikow do filtrow i formularzy, - normalizacja pustych pol do pustych tablic. W trybie mock: - czyta `frontend/src/mocks/dictionaries.json`. W trybie prawdziwego API: ```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 ``` W nim: ```js import { api } from 'src/boot/axios' import { USE_MOCK_API, waitForMockApi } from 'src/services/apiMode' export async function fetchProductPhotos(productId) { if (USE_MOCK_API) { await waitForMockApi() return [] } 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/productTimelineApi.js frontend/src/services/productSpecificationApi.js frontend/src/services/dictionariesApi.js ``` Utworzono mocki: ```txt frontend/src/mocks/products.json frontend/src/mocks/timelines.json frontend/src/mocks/specifications.json frontend/src/mocks/dictionaries.json ``` 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.