handle backend errors
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 10s
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 10s
This commit is contained in:
@@ -188,7 +188,7 @@ export default function SignUpForm() {
|
|||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>Atolls</SelectLabel>
|
<SelectLabel>Atolls</SelectLabel>
|
||||||
{atolls?.data.map((atoll) => (
|
{(atolls?.data ?? []).map((atoll) => (
|
||||||
<SelectItem key={atoll.id} value={atoll.id.toString()}>
|
<SelectItem key={atoll.id} value={atoll.id.toString()}>
|
||||||
{atoll.name}
|
{atoll.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@@ -29,6 +29,25 @@ apiClient.interceptors.request.use((config) => {
|
|||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Normalise non-JSON error pages. Django (DisallowedHost / DEBUG tracebacks),
|
||||||
|
// nginx (502/504), etc. return an HTML body on 4xx/5xx instead of the JSON
|
||||||
|
// envelope callers expect. Left as-is, the raw HTML string flows into consumers
|
||||||
|
// and crashes things like `atolls.data.map(...)`. Rewrite it into a JSON error
|
||||||
|
// body so `handleApiResponse` and action code read a clean `{ message, detail }`.
|
||||||
|
apiClient.interceptors.response.use((response) => {
|
||||||
|
const contentType = String(response.headers?.["content-type"] ?? "");
|
||||||
|
const isHtml = !contentType.includes("application/json");
|
||||||
|
if (response.status >= 400 && isHtml && typeof response.data === "string") {
|
||||||
|
const title = response.data.match(/<title>([\s\S]*?)<\/title>/i)?.[1]?.trim();
|
||||||
|
response.data = {
|
||||||
|
message: `Server error (${response.status})`,
|
||||||
|
detail:
|
||||||
|
title || `The server returned a non-JSON ${response.status} response.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
// On 401 the token is dead — clear it and bounce to signin (once).
|
// On 401 the token is dead — clear it and bounce to signin (once).
|
||||||
apiClient.interceptors.response.use((response) => {
|
apiClient.interceptors.response.use((response) => {
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import type { ApiResponse, Atoll } from "@/lib/backend-types";
|
import type { ApiResponse, Atoll } from "@/lib/backend-types";
|
||||||
import apiClient from "@/lib/api-client";
|
import apiClient from "@/lib/api-client";
|
||||||
|
import { handleApiResponse } from "@/utils/tryCatch";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atoll list (with nested islands) for the signup atoll/island dropdowns.
|
* Atoll list (with nested islands) for the signup atoll/island dropdowns.
|
||||||
* The endpoint is paginated, so this returns the `{ meta, links, data }`
|
* The endpoint is paginated, so this returns the `{ meta, links, data }`
|
||||||
* envelope — consumers read `.data`.
|
* envelope — consumers read `.data`.
|
||||||
|
*
|
||||||
|
* Runs through `handleApiResponse` so a 4xx/5xx (e.g. DisallowedHost 400)
|
||||||
|
* throws a clean error for React Query to surface, instead of returning a
|
||||||
|
* non-envelope body that crashes `atolls.data.map(...)`.
|
||||||
*/
|
*/
|
||||||
export async function getAtolls() {
|
export async function getAtolls() {
|
||||||
const response = await apiClient.get("/api/auth/atolls/");
|
const response = await apiClient.get("/api/auth/atolls/");
|
||||||
return response.data as ApiResponse<Atoll>;
|
return handleApiResponse<ApiResponse<Atoll>>(response, "getAtolls");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user