import { ApiResponse } from "apisauce" // Base problem types without error details type BaseProblem = /** * Times up. */ | { kind: "timeout"; temporary: true } /** * Cannot connect to the server for some reason. */ | { kind: "cannot-connect"; temporary: true } /** * The server experienced a problem. Any 5xx error. */ | { kind: "server" } /** * We're not allowed because we haven't identified ourself. This is 401. */ | { kind: "unauthorized" } /** * We don't have access to perform that request. This is 403. */ | { kind: "forbidden" } /** * Unable to find that resource. This is a 404. */ | { kind: "not-found" } /** * All other 4xx series errors. */ | { kind: "rejected" } /** * Something truly unexpected happened. Most likely can try again. This is a catch all. */ | { kind: "unknown"; temporary: true } /** * The data we received is not in the expected format. */ | { kind: "bad-data" } // Extended problem type that includes optional error code and message from API response export type GeneralApiProblem = BaseProblem & { errorCode?: string errorMessage?: string } /** * Extracts error code from API response data. * Handles both { code: "E001" } and { error: { code: "E001" } } formats. */ function extractErrorCode(data: any): string | undefined { if (!data) return undefined return data.code || data.error?.code } /** * Extracts error message from API response data. * Handles both { message: "..." } and { error: { message: "..." } } formats. */ function extractErrorMessage(data: any): string | undefined { if (!data) return undefined return data.message || data.error?.message } /** * Attempts to get a common cause of problems from an api response. * * @param response The api response. */ export function getGeneralApiProblem(response: ApiResponse): GeneralApiProblem | null { // Extract error details from response data (if available) const errorCode = extractErrorCode(response.data) const errorMessage = extractErrorMessage(response.data) switch (response.problem) { case "CONNECTION_ERROR": return { kind: "cannot-connect", temporary: true, errorCode, errorMessage } case "NETWORK_ERROR": return { kind: "cannot-connect", temporary: true, errorCode, errorMessage } case "TIMEOUT_ERROR": return { kind: "timeout", temporary: true, errorCode, errorMessage } case "SERVER_ERROR": return { kind: "server", errorCode, errorMessage } case "UNKNOWN_ERROR": return { kind: "unknown", temporary: true, errorCode, errorMessage } case "CLIENT_ERROR": switch (response.status) { case 401: return { kind: "unauthorized", errorCode, errorMessage } case 403: return { kind: "forbidden", errorCode, errorMessage } case 404: return { kind: "not-found", errorCode, errorMessage } default: return { kind: "rejected", errorCode, errorMessage } } case "CANCEL_ERROR": return null } return null }