Files
duck-prod-manager/notes/api_services.md
bartool 6e3d722e69 dodalem pinia store.
dodalem dokumentacje opisujaca dzialanie store
dodalem services do komunikacji z directus
dodalem opis dzialania services
dodalem mocki danych
przygotowania do refaktoryzacji
2026-04-30 16:49:50 +02:00

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 limit i offset,
  • 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 limit i offset,
  • zwraca items i pageInfo.

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 lastFetchedAt na 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.