Files

104 lines
3.0 KiB
TypeScript
Raw Permalink Normal View History

2026-02-05 13:16:05 +08:00
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<any>): 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
}