fix(api): support xsrf and backend error message
This commit is contained in:
+30
-1
@@ -17,6 +17,22 @@ async function readJsonBody(res: Response): Promise<unknown | null> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCookieValue(name: string): string | null {
|
||||||
|
if (typeof document === "undefined") return null
|
||||||
|
if (!document.cookie) return null
|
||||||
|
|
||||||
|
for (const part of document.cookie.split("; ")) {
|
||||||
|
if (part.startsWith(`${name}=`)) return part.slice(name.length + 1)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function isApiErrorWithMessage(value: unknown): value is { code: number; message: string } {
|
||||||
|
if (typeof value !== "object" || value === null) return false
|
||||||
|
const v = value as { code?: unknown; message?: unknown }
|
||||||
|
return typeof v.code === "number" && typeof v.message === "string"
|
||||||
|
}
|
||||||
|
|
||||||
export async function httpJson<T>(path: string, init?: JsonRequestInit): Promise<T> {
|
export async function httpJson<T>(path: string, init?: JsonRequestInit): Promise<T> {
|
||||||
if (/^https?:\/\//.test(path)) {
|
if (/^https?:\/\//.test(path)) {
|
||||||
throw new Error("Absolute URLs are not allowed")
|
throw new Error("Absolute URLs are not allowed")
|
||||||
@@ -33,6 +49,15 @@ export async function httpJson<T>(path: string, init?: JsonRequestInit): Promise
|
|||||||
headers.set("Content-Type", "application/json")
|
headers.set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const method = (rest.method ?? "GET").toUpperCase()
|
||||||
|
if (
|
||||||
|
(method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE") &&
|
||||||
|
!headers.has("XSRF-TOKEN")
|
||||||
|
) {
|
||||||
|
const xsrfToken = getCookieValue("__Host-XSRF-TOKEN")
|
||||||
|
if (xsrfToken) headers.set("XSRF-TOKEN", xsrfToken)
|
||||||
|
}
|
||||||
|
|
||||||
const res = await fetch(path, {
|
const res = await fetch(path, {
|
||||||
...rest,
|
...rest,
|
||||||
headers,
|
headers,
|
||||||
@@ -45,7 +70,11 @@ export async function httpJson<T>(path: string, init?: JsonRequestInit): Promise
|
|||||||
return data as T
|
return data as T
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiError = isApiError(data) ? data : null
|
const apiError: ApiError | null = isApiError(data)
|
||||||
|
? data
|
||||||
|
: isApiErrorWithMessage(data)
|
||||||
|
? { code: data.code, msg: data.message }
|
||||||
|
: null
|
||||||
if (res.status === 401 || apiError?.code === 401) {
|
if (res.status === 401 || apiError?.code === 401) {
|
||||||
throw new Error("UNAUTHORIZED")
|
throw new Error("UNAUTHORIZED")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user