Harden API client against stale-backend HTML fallback
When the running backend is missing a route, the SPA fallback serves index.html with a 200, and the api helper returned undefined — which crashed pages on .map/.length (the Delivery pipeline white-screened against an old build). Now a non-JSON 2xx on an /api call throws a clear 'API is running an older build' error instead, and PipelinePage defensively coerces its lists to arrays. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+12
-1
@@ -21,7 +21,18 @@ async function request<T>(method: string, url: string, body?: unknown): Promise<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contentType = response.headers.get('content-type') ?? ''
|
const contentType = response.headers.get('content-type') ?? ''
|
||||||
return contentType.includes('application/json') ? ((await response.json()) as T) : (undefined as T)
|
if (contentType.includes('application/json')) {
|
||||||
|
return (await response.json()) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
// A non-JSON 2xx on an /api call is almost always the SPA fallback (index.html) — i.e. the route
|
||||||
|
// doesn't exist on the backend that's running (a stale build). Fail loudly so callers surface it,
|
||||||
|
// instead of returning undefined and letting the page crash on `.map`/`.length`.
|
||||||
|
if (url.startsWith('/api') && contentType.includes('text/html')) {
|
||||||
|
throw new Error(`Unexpected HTML from ${url}. The API is likely running an older build — restart the server.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined as T
|
||||||
}
|
}
|
||||||
|
|
||||||
export const api = {
|
export const api = {
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ export function PipelinePage() {
|
|||||||
api.get<ChangeSummary[]>(`/api/orgboard/change-requests?organizationId=${organizationId}`),
|
api.get<ChangeSummary[]>(`/api/orgboard/change-requests?organizationId=${organizationId}`),
|
||||||
api.get<Division[]>(`/api/orgboard/divisions?organizationId=${organizationId}`).catch(() => []),
|
api.get<Division[]>(`/api/orgboard/divisions?organizationId=${organizationId}`).catch(() => []),
|
||||||
])
|
])
|
||||||
setRequests(list)
|
setRequests(Array.isArray(list) ? list : [])
|
||||||
setDivisions(divs)
|
setDivisions(Array.isArray(divs) ? divs : [])
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast.error((err as Error).message)
|
toast.error((err as Error).message)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user