import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios' import { Api } from 'nocodb-sdk' import type { Ref } from 'vue' import type { EventHook, MaybeRef } from '@vueuse/core' import { addAxiosInterceptors } from './interceptors' import { createEventHook, ref, unref, useGlobal } from '#imports' interface UseApiReturn { api: Api isLoading: Ref error: Ref | null> response: Ref | null> onError: EventHook>['on'] onResponse: EventHook>['on'] } interface CreateApiOptions { baseURL?: string } export function createApiInstance(options: CreateApiOptions = {}): Api { return addAxiosInterceptors( new Api({ baseURL: options.baseURL ?? 'http://localhost:8080', }), ) } interface UseApiProps { axiosConfig?: MaybeRef> apiOptions?: CreateApiOptions } export function useApi(props: UseApiProps = {}): UseApiReturn { const state = $(useGlobal()) const isLoading = ref(false) const error = ref(null) const response = ref(null) const errorHook = createEventHook>() const responseHook = createEventHook>() const api = createApiInstance(props.apiOptions) function addRequest() { state.runningRequests.push(state.runningRequests.length + 1) } function removeRequest() { state.runningRequests.pop() } api.instance.interceptors.request.use( (config) => { error.value = null response.value = null isLoading.value = true addRequest() return { ...config, ...unref(props), } }, (requestError) => { errorHook.trigger(requestError) error.value = requestError response.value = null isLoading.value = false removeRequest() return requestError }, ) api.instance.interceptors.response.use( (apiResponse) => { responseHook.trigger(apiResponse as AxiosResponse) // can't properly typecast response.value = apiResponse isLoading.value = false removeRequest() return apiResponse }, (apiError) => { errorHook.trigger(apiError) error.value = apiError isLoading.value = false removeRequest() return apiError }, ) return { api, isLoading, response, error, onError: errorHook.on, onResponse: responseHook.on } }