You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
3.3 KiB
95 lines
3.3 KiB
import { createUseFetch } from '#imports'
|
|
import type { AsyncData, UseFetchOptions } from '#app'
|
|
import type { KeysOf, PickFrom } from '#app/composables/asyncData'
|
|
import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod } from 'nitropack/types'
|
|
import type { FetchError } from 'ofetch'
|
|
import type { Ref } from 'vue'
|
|
|
|
/** 与 `R.success` / `R.error` 返回结构对齐 */
|
|
export type ApiResponse<T = unknown> = {
|
|
code: number
|
|
message: string
|
|
data: T
|
|
}
|
|
|
|
/** 从 Nitro 推断的响应体上剥离一层 `ApiResponse`,得到 `data` 字段类型 */
|
|
export type UnwrapApiResponse<T> = T extends ApiResponse<infer D> ? D : T
|
|
|
|
export function unwrapApiBody<T>(payload: ApiResponse<T>): T {
|
|
if (payload.code !== 0) {
|
|
throw new Error(payload.message)
|
|
}
|
|
return payload.data
|
|
}
|
|
|
|
export const request = $fetch.create({})
|
|
|
|
const httpFetchDefaults = {
|
|
retry: 0,
|
|
$fetch: request,
|
|
transform: unwrapApiBody,
|
|
}
|
|
|
|
const _useHttpFetch = createUseFetch(httpFetchDefaults)
|
|
const _useLazyHttpFetch = createUseFetch({
|
|
...httpFetchDefaults,
|
|
lazy: true,
|
|
})
|
|
|
|
type DefaultMethod<ReqT extends NitroFetchRequest> = 'get' extends AvailableRouterMethod<ReqT>
|
|
? 'get'
|
|
: AvailableRouterMethod<ReqT>
|
|
|
|
type HttpFetchOptions<
|
|
_ResT,
|
|
DataT,
|
|
PickKeys extends KeysOf<DataT>,
|
|
DefaultT,
|
|
ReqT extends NitroFetchRequest,
|
|
Method extends AvailableRouterMethod<ReqT>,
|
|
> = Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'transform'>
|
|
|
|
/**
|
|
* 带项目默认选项的 `useFetch`,并在类型上将 `data` 视为接口 `{ code, data, message }` 中的内层 `data`。
|
|
*
|
|
* 说明:Nuxt的 `createUseFetch` 在类型上不会把工厂里的 `transform` 的出参当作 `AsyncData['data']`,
|
|
* 因此这里用薄包装修正 `DataT`(见 `UnwrapApiResponse`)。
|
|
*/
|
|
export function useHttpFetch<
|
|
ResT = void,
|
|
ErrorT = FetchError,
|
|
ReqT extends NitroFetchRequest = NitroFetchRequest,
|
|
Method extends AvailableRouterMethod<ReqT> = ResT extends void
|
|
? DefaultMethod<ReqT>
|
|
: AvailableRouterMethod<ReqT>,
|
|
_ResT = ResT extends void ? TypedInternalResponse<ReqT, unknown, Lowercase<Method>> : ResT,
|
|
DataT = UnwrapApiResponse<_ResT>,
|
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
|
DefaultT = undefined,
|
|
>(
|
|
url: ReqT | Ref<ReqT, ReqT> | (() => ReqT),
|
|
opts?: HttpFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
|
): AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined> {
|
|
return _useHttpFetch(url, opts) as AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined>
|
|
}
|
|
|
|
export function useLazyHttpFetch<
|
|
ResT = void,
|
|
ErrorT = FetchError,
|
|
ReqT extends NitroFetchRequest = NitroFetchRequest,
|
|
Method extends AvailableRouterMethod<ReqT> = ResT extends void
|
|
? DefaultMethod<ReqT>
|
|
: AvailableRouterMethod<ReqT>,
|
|
_ResT = ResT extends void ? TypedInternalResponse<ReqT, unknown, Lowercase<Method>> : ResT,
|
|
DataT = UnwrapApiResponse<_ResT>,
|
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
|
DefaultT = undefined,
|
|
>(
|
|
url: ReqT | Ref<ReqT, ReqT> | (() => ReqT),
|
|
opts?: HttpFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
|
): AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined> {
|
|
return _useLazyHttpFetch(url, opts) as AsyncData<
|
|
DefaultT | PickFrom<DataT, PickKeys>,
|
|
ErrorT | undefined
|
|
>
|
|
}
|
|
|