Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 9s
Test / e2e-test (push) Has been cancelled
api.post/get/put/delete now throw Error with .message from response body (detail/message field), not raw Response object. Fixes login modal showing no feedback on auth failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
54 lines
1.6 KiB
JavaScript
54 lines
1.6 KiB
JavaScript
const API_BASE = '' // same origin, uses vite proxy in dev
|
|
|
|
export function getToken() {
|
|
return localStorage.getItem('oil_auth_token') || ''
|
|
}
|
|
|
|
export function setToken(token) {
|
|
if (token) localStorage.setItem('oil_auth_token', token)
|
|
else localStorage.removeItem('oil_auth_token')
|
|
}
|
|
|
|
function buildHeaders(extra = {}) {
|
|
const headers = { 'Content-Type': 'application/json', ...extra }
|
|
const token = getToken()
|
|
if (token) headers['Authorization'] = 'Bearer ' + token
|
|
return headers
|
|
}
|
|
|
|
async function request(path, opts = {}) {
|
|
const headers = buildHeaders(opts.headers)
|
|
const res = await fetch(API_BASE + path, { ...opts, headers })
|
|
return res
|
|
}
|
|
|
|
async function requestJSON(path, opts = {}) {
|
|
const res = await request(path, opts)
|
|
if (!res.ok) {
|
|
let msg = `${res.status}`
|
|
try {
|
|
const body = await res.json()
|
|
msg = body.detail || body.message || msg
|
|
} catch {}
|
|
const err = new Error(msg)
|
|
err.status = res.status
|
|
throw err
|
|
}
|
|
return res.json()
|
|
}
|
|
|
|
// api is callable as api(path, opts) → raw Response
|
|
// AND has convenience methods: api.get(), api.post(), api.put(), api.delete()
|
|
function apiFn(path, opts = {}) {
|
|
return request(path, opts)
|
|
}
|
|
|
|
apiFn.raw = request
|
|
apiFn.get = (path) => requestJSON(path)
|
|
apiFn.post = (path, body) => requestJSON(path, { method: 'POST', body: JSON.stringify(body) })
|
|
apiFn.put = (path, body) => requestJSON(path, { method: 'PUT', body: JSON.stringify(body) })
|
|
apiFn.del = (path) => requestJSON(path, { method: 'DELETE' })
|
|
apiFn.delete = (path) => requestJSON(path, { method: 'DELETE' })
|
|
|
|
export const api = apiFn
|