-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
useApiData.ts
119 lines (103 loc) 路 2.82 KB
/
useApiData.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { computed, reactive, unref } from 'vue'
import { hash } from 'ohash'
import type { FetchError, FetchOptions } from 'ofetch'
import type { Ref } from 'vue'
import type { AsyncData, AsyncDataOptions } from 'nuxt/app'
import { headersToObject, resolveUnref } from '../utils'
import type { EndpointFetchOptions, MaybeComputedRef } from '../utils'
import { useAsyncData, useNuxtApp } from '#imports'
type ComputedOptions<T extends Record<string, any>> = {
[K in keyof T]: T[K] extends Function
? T[K]
: T[K] extends Record<string, any>
? ComputedOptions<T[K]> | Ref<T[K]> | T[K]
: Ref<T[K]> | T[K];
}
export type UseApiDataOptions<T> = Pick<
AsyncDataOptions<T>,
| 'server'
| 'lazy'
| 'default'
| 'watch'
| 'immediate'
> & Pick<
ComputedOptions<FetchOptions>,
| 'onRequest'
| 'onRequestError'
| 'onResponse'
| 'onResponseError'
// Pick from `globalThis.RequestInit`
| 'query'
| 'headers'
| 'method'
> & {
body?: Record<string, any>
}
export type UseApiData = <T = any>(
path: MaybeComputedRef<string>,
opts?: UseApiDataOptions<T>,
) => AsyncData<T, FetchError | null | true>
export function _useApiData<T = any>(
endpointId: string,
path: MaybeComputedRef<string>,
opts: UseApiDataOptions<T> = {},
) {
const nuxt = useNuxtApp()
const _path = computed(() => resolveUnref(path))
const key = `$party${hash([endpointId, _path.value, unref(opts.query)])}`
const {
server,
lazy,
default: defaultFn,
immediate,
watch,
query,
headers,
method,
body,
...fetchOptions
} = opts
const _fetchOptions = reactive(fetchOptions)
const endpointFetchOptions: EndpointFetchOptions = reactive({
query,
headers: headersToObject(unref(headers)),
method,
body,
})
const asyncDataOptions: AsyncDataOptions<T> = {
server,
lazy,
default: defaultFn,
immediate,
watch: [
_path,
endpointFetchOptions,
...(watch || []),
],
}
let controller: AbortController
return useAsyncData<T, FetchError>(
key,
async () => {
controller?.abort?.()
if (key in nuxt.payload.data)
return Promise.resolve(nuxt.payload.data[key])
if (key in nuxt.static.data)
return Promise.resolve(nuxt.static.data[key])
controller = typeof AbortController !== 'undefined'
? new AbortController()
: ({} as AbortController)
const result = await $fetch<T>(`/api/__api_party/${endpointId}/${_path.value}`, {
..._fetchOptions,
signal: controller.signal,
method: 'POST',
body: endpointFetchOptions,
}) as T
// Workaround to persist response client-side
// https://github.com/nuxt/framework/issues/8917
nuxt.static.data[key] = result
return result
},
asyncDataOptions,
) as AsyncData<T, FetchError | null | true>
}