Skip to content

Commit eb73421

Browse files
committed
fix: harden metadata loading failures
1 parent ad72480 commit eb73421

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

frontend/src/__tests__/App.contract.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,17 @@ describe('App contract', () => {
109109
expect(slashlessMetadataRequests).toBeGreaterThanOrEqual(1);
110110
expect(trailingSlashMetadataRequests).toBe(0);
111111
});
112+
113+
it('shows the metadata unavailable notice when /api/v1 responds with non-JSON content', async () => {
114+
server.use(
115+
http.get('/api/v1', () => HttpResponse.text('not-json', { status: 502 })),
116+
http.get('/api/v1/', () => HttpResponse.text('', { status: 404 }))
117+
);
118+
119+
render(<App />);
120+
121+
await screen.findByText('Instance metadata unavailable');
122+
123+
expect(screen.getByText('Invalid response format from API metadata')).toBeInTheDocument();
124+
});
112125
});

frontend/src/hooks/useApiMetadata.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ interface ApiMetadataState {
77
error: string | null;
88
}
99

10+
interface ApiMetadataPayload {
11+
success?: boolean;
12+
data?: unknown;
13+
}
14+
1015
export function useApiMetadata() {
1116
const [state, setState] = useState<ApiMetadataState>({
1217
metadata: null,
@@ -25,7 +30,7 @@ export function useApiMetadata() {
2530
signal: controller.signal,
2631
headers: { Accept: 'application/json' },
2732
});
28-
const payload = (await response.json()) as { success?: boolean; data?: unknown };
33+
const payload = await parseMetadataPayload(response);
2934
const metadata = payload.data as ApiMetadataRecord | undefined;
3035

3136
if (!response.ok || !payload.success || !metadata?.instance) {
@@ -54,3 +59,14 @@ export function useApiMetadata() {
5459

5560
return state;
5661
}
62+
63+
async function parseMetadataPayload(response: Response): Promise<ApiMetadataPayload> {
64+
const body = await response.text();
65+
if (!body.trim()) return {};
66+
67+
try {
68+
return JSON.parse(body) as ApiMetadataPayload;
69+
} catch {
70+
return {};
71+
}
72+
}

0 commit comments

Comments
 (0)