104 lines
3.0 KiB
TypeScript
104 lines
3.0 KiB
TypeScript
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
|
|
}
|