request.ts 1.33 KB
import axios, { type AxiosError, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios'
import type { ApiResponse } from './types'

export const TOKEN_KEY = 'erp.accessToken'

const instance = axios.create({
  baseURL: '/api',
  timeout: 15000,
})

instance.interceptors.request.use((cfg: InternalAxiosRequestConfig) => {
  const token = sessionStorage.getItem(TOKEN_KEY)
  if (token) cfg.headers.set('Authorization', `Bearer ${token}`)
  return cfg
})

let onUnauthorized: (() => void) | null = null
export function setUnauthorizedHandler(fn: () => void) {
  onUnauthorized = fn
}

instance.interceptors.response.use(
  (res: AxiosResponse<ApiResponse<unknown>>) => res,
  (err: AxiosError) => {
    if (err.response?.status === 401) onUnauthorized?.()
    return Promise.reject(err)
  },
)

/** Throws BizError when code !== 200; returns data on success. */
export class BizError extends Error {
  code: number
  payload: unknown
  constructor(code: number, message: string, payload: unknown) {
    super(message)
    this.code = code
    this.payload = payload
  }
}

export async function call<T>(req: () => Promise<AxiosResponse<ApiResponse<T>>>): Promise<T> {
  const res = await req()
  const body = res.data
  if (body.code !== 200) {
    throw new BizError(body.code, body.message, body.data)
  }
  return body.data
}

export default instance