dodalem dokumentacje opisujaca dzialanie store dodalem services do komunikacji z directus dodalem opis dzialania services dodalem mocki danych przygotowania do refaktoryzacji
7.8 KiB
API Services I Mocki
Data: 2026-04-29
Cel dokumentu
Ten dokument opisuje warstwe API we frontendzie.
Warstwa API znajduje sie w:
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.:
fetchProducts(params)
a service powinien zajac sie reszta.
Aktualne pliki services
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:
komponent Vue
-> store Pinia
-> service API
-> mock JSON albo Axios
-> backend Directus
Przyklad:
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:
api.get('/mayo-api/products', { params })
Wtedy store zna:
- Axios,
- endpoint,
- strukture odpowiedzi HTTP.
To miesza odpowiedzialnosci.
Po wydzieleniu services store robi:
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:
frontend/src/services/apiMode.js
Zawiera przelacznik miedzy mock API i prawdziwym API:
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:
VITE_USE_MOCK_API=false npm run dev
Uruchomienie z mockami:
npm run dev
Mocki maja sztuczne opoznienie:
waitForMockApi()
Dzieki temu podczas pracy nad UI widac stany ladowania podobne do prawdziwego API.
Pliki mockow
Mocki sa zwyklymi plikami JSON:
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:
frontend/src/services/productsApi.js
Eksportuje:
fetchProducts(params)
Odpowiedzialnosc:
- pobranie listy produktow,
- obsluga filtrow,
- obsluga
limitioffset, - zwrocenie danych w formacie oczekiwanym przez
productsStore.
Zwraca:
{
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
limitioffset, - zwraca
itemsipageInfo.
W trybie prawdziwego API:
GET /mayo-api/products
z parametrami:
{
limit,
offset,
search,
model,
client,
finish,
productionList,
year,
}
productTimelineApi.js
Plik:
frontend/src/services/productTimelineApi.js
Eksportuje:
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:
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:
POST /mayo-api/products/:id/timeline/events
Zwracany format:
{
event: {},
timelinePreview: {
body: [],
neck: [],
},
}
To pozwala store od razu zaktualizowac:
- pelny timeline,
- preview na glownej karcie produktu.
productSpecificationApi.js
Plik:
frontend/src/services/productSpecificationApi.js
Eksportuje:
fetchProductSpecification(productId)
refreshProductSpecification(productId)
fetchProductSpecification
Pobiera specyfikacje produktu.
W trybie mock:
- czyta
frontend/src/mocks/specifications.json.
W trybie prawdziwego API:
GET /mayo-api/products/:id/specification
refreshProductSpecification
Odswieza specyfikacje produktu.
W trybie mock:
- zwraca dane z mocka,
- aktualizuje
lastFetchedAtna aktualny czas.
W trybie prawdziwego API:
POST /mayo-api/products/:id/specification/refresh
Normalizacja odpowiedzi
Ten plik zawiera funkcje:
normalizeSpecificationResponse(data)
Jej zadaniem jest zamiana odpowiedzi backendu na prosty format dla store:
{
productId,
orderId,
sourceUrl,
lastFetchedAt,
sections,
diff,
}
Service akceptuje dwa ksztalty:
data.specification.sections
albo:
data.sections
Dzieki temu store nie musi znac szczegolow odpowiedzi HTTP.
dictionariesApi.js
Plik:
frontend/src/services/dictionariesApi.js
Eksportuje:
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:
GET /mayo-api/dictionaries
Zwraca:
{
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:
frontend/src/services/productPhotosApi.js
W nim:
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:
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:
{
items: [],
pageInfo: {}
}
to mock tez powinien zwrocic:
{
items: [],
pageInfo: {}
}
Nie nalezy robic osobnych struktur danych tylko dla widoku, jesli nie beda zgodne z przyszlym API.
Co zostalo juz zrobione
Utworzono:
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:
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:
api
ani:
src/mocks/*.json
Komponent powinien uzywac store albo dostawac dane przez props.
Store powinien uzywac services.
Services powinny uzywac Axiosa albo mockow.