shinkan-jinkendo/frontend/src/api/client.js
Lars e759076a6c
All checks were successful
Deploy Development / deploy (push) Successful in 41s
Test Suite / pytest-backend (push) Successful in 40s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m8s
chore(version): update version and changelog for release 0.8.136
- Bumped APP_VERSION to 0.8.136 and updated the changelog to reflect recent changes.
- Fixed the Mandanten-Header handling in `api/exercises.js` for improved API requests.
- Continued Frontend Phase 4 with the addition of the `exercises.js` module, enhancing the API structure.
- Updated architecture documentation to include details on the new `exercises.js` API and its integration with the existing client structure.
- Enhanced `utils/api.js` to re-export the new exercises module, streamlining API access.
2026-05-14 21:49:56 +02:00

80 lines
2.7 KiB
JavaScript

/**
* HTTP-Client: Token, Mandanten-Header, Fehler-Mapping.
* Alle API-Aufrufe laufen über request() — siehe utils/api.js (Facade) und Domänenmodule (planning.js, exercises.js).
*/
export const API_URL = import.meta.env.VITE_API_URL || ''
/** LocalStorage + Request-Header für Mandanten-Kontext */
export const ACTIVE_CLUB_STORAGE_KEY = 'shinkan_active_club_id'
export function mergeActiveClubHeader(headers = {}) {
const cid = localStorage.getItem(ACTIVE_CLUB_STORAGE_KEY)
if (cid && /^\d+$/.test(String(cid).trim())) {
return { ...headers, 'X-Active-Club-Id': String(cid).trim() }
}
return { ...headers }
}
/**
* Generischer API-Aufruf inkl. X-Auth-Token und X-Active-Club-Id.
*/
export async function request(endpoint, options = {}) {
const token = localStorage.getItem('authToken')
const method = (options.method || 'GET').toUpperCase()
const headers = mergeActiveClubHeader({
...options.headers,
})
if (method !== 'GET' && method !== 'HEAD') {
if (!headers['Content-Type'] && !headers['content-type']) {
headers['Content-Type'] = 'application/json'
}
}
if (token) {
headers['X-Auth-Token'] = token
}
const url = `${API_URL}${endpoint}`
try {
const response = await fetch(url, {
...options,
headers,
})
if (!response.ok) {
const text = await response.text()
let parsed = null
try {
parsed = JSON.parse(text)
} catch {
parsed = null
}
if (parsed?.detail != null) {
const d = parsed.detail
throw new Error(typeof d === 'string' ? d : JSON.stringify(d))
}
if (response.status === 502) {
throw new Error(
'HTTP 502 (Bad Gateway): Der Reverse-Proxy hat die API nicht korrekt erreicht. Ist `shinkan-api` aktiv (`docker compose ps`, `docker logs shinkan-api`)? Bei Host-Routing nur einen Weg verwenden — alles auf Port 3003 (Nginx nach `backend:8000`) oder sauber `/api` → Backend-Port.'
)
}
const snippet = (text || '').replace(/\s+/g, ' ').trim().slice(0, 180)
throw new Error(snippet ? `HTTP ${response.status}: ${snippet}` : `HTTP ${response.status}`)
}
return response.json()
} catch (e) {
if (e instanceof TypeError && (e.message === 'Failed to fetch' || e.message.includes('fetch'))) {
const hint =
API_URL && API_URL.length > 0
? `Verbindung zum API unter ${API_URL} fehlgeschlagen. Läuft das Backend (z. B. Port 8098) und ist CORS erlaubt?`
: 'Kein VITE_API_URL gesetzt: Anfragen gehen an die Frontend-URL und schlagen oft fehl. Setze in .env z. B. VITE_API_URL=http://localhost:8098 und starte Vite neu.'
throw new Error(`${hint} [Technisch: ${e.message}; URL war ${endpoint}]`)
}
throw e
}
}