refactor: migrate all page.server.ts files to typed API client

All server-side fetch calls now go through createApiClient() from
$lib/api.server.ts, which wraps openapi-fetch with the generated OpenAPI
types. This means backend changes are reflected in the frontend after
running npm run generate:api.

- Add stub src/lib/generated/api.ts (replaced by generate:api output)
- Fix GroupController: missing /api prefix and ResponseStatusException
- Root, conversations, persons, documents pages all use typed client
- Error handling uses apiError.code directly (no parseBackendError needed)
- Edit page load uses typed client; PUT action keeps raw fetch (multipart)
- Login keeps raw fetch (explicit Authorization header, not cookie auth)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-15 13:39:15 +01:00
parent 5d356cd694
commit d76248cffd
11 changed files with 220 additions and 259 deletions

View File

@@ -1,62 +1,61 @@
import { env } from '$env/dynamic/private';
import { createApiClient } from '$lib/api.server';
export async function load({ url, fetch }) {
const baseUrl = env.API_INTERNAL_URL || 'http://localhost:8080';
// 1. Parameter auslesen
const senderId = url.searchParams.get('senderId') || '';
const receiverId = url.searchParams.get('receiverId') || '';
const from = url.searchParams.get('from') || '';
const to = url.searchParams.get('to') || '';
const dir = url.searchParams.get('dir') || 'DESC';
let documents = [];
const api = createApiClient(fetch);
let documents: unknown[] = [];
let senderName = '';
let receiverName = '';
// 2. Fetch-Requests vorbereiten
const requests = [];
const requests: Promise<void>[] = [];
// Dokumente laden (nur wenn beide IDs da sind)
if (senderId && receiverId) {
const query = new URLSearchParams({ senderId, receiverId, dir });
if (from) query.set('from', from);
if (to) query.set('to', to);
requests.push(
fetch(`${baseUrl}/api/documents/conversation?${query}`)
.then(r => r.ok ? r.json() : [])
.then(data => documents = data)
api.GET('/api/documents/conversation', {
params: {
query: {
senderId,
receiverId,
dir,
from: from || undefined,
to: to || undefined
}
}
}).then(({ data }) => { documents = data ?? []; })
);
}
// Namen auflösen für Typeahead Initial Value
if (senderId) {
requests.push(
fetch(`${baseUrl}/api/persons/${senderId}`)
.then(r => r.ok ? r.json() : null)
.then(p => senderName = p ? `${p.firstName} ${p.lastName}` : '')
api.GET('/api/persons/{id}', { params: { path: { id: senderId } } })
.then(({ data }) => {
const p = data as { firstName: string; lastName: string } | undefined;
if (p) senderName = `${p.firstName} ${p.lastName}`;
})
);
}
if (receiverId) {
requests.push(
fetch(`${baseUrl}/api/persons/${receiverId}`)
.then(r => r.ok ? r.json() : null)
.then(p => receiverName = p ? `${p.firstName} ${p.lastName}` : '')
api.GET('/api/persons/{id}', { params: { path: { id: receiverId } } })
.then(({ data }) => {
const p = data as { firstName: string; lastName: string } | undefined;
if (p) receiverName = `${p.firstName} ${p.lastName}`;
})
);
}
// Alles parallel abfeuern
await Promise.all(requests);
return {
documents,
initialValues: {
senderName,
receiverName
},
initialValues: { senderName, receiverName },
filters: { senderId, receiverId, from, to, dir }
};
}