Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking β€œSign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: customizable cache key #52

Merged
merged 4 commits into from
Sep 15, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: simplify cache option
johannschopplich committed Sep 15, 2023
commit c3215cfb2262dacc9106089bb89e459599514003
21 changes: 8 additions & 13 deletions docs/api/my-api.md
Original file line number Diff line number Diff line change
@@ -17,10 +17,11 @@ interface BaseApiFetchOptions {
*/
client?: boolean
/**
* Cache the response for the same request
* Cache the response for the same request.
* If set to `true`, the cache key will be generated from the request options.
* @default false
*/
cache?: boolean
cache?: string | boolean
}

type ApiFetchOptions = Omit<NitroFetchOptions<string>, 'body' | 'cache'> & {
@@ -32,24 +33,18 @@ function $Api<T = any>(
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions
): Promise<T>
function $Api<T = any>(
key: string,
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions
): Promise<T>
```

## Caching

By default, a [unique key for each request is generated](/guide/caching) to ensure that data fetching can be properly de-duplicated across requests. You can provide a custom key by passing a string as the first argument:
By default, a [unique key is generated](/guide/caching) based in input parameters for each request to ensure that data fetching can be properly de-duplicated across requests. You can provide a custom key by passing a string as the `cache` option:

```ts
const key = 'all-posts'
const route = useRoute()

const data = await $myApi(
key,
'posts'
)
const data = await $myApi('posts', {
cache: `posts-${route.params.id}`
})
```

## Example
12 changes: 5 additions & 7 deletions docs/api/use-my-api-data.md
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ type BaseUseApiDataOptions<T> = Omit<AsyncDataOptions<T>, 'watch'> & {
*/
client?: boolean
/**
* Cache the response for the same request
* Cache the response for the same request.
* @default true
*/
cache?: boolean
@@ -71,15 +71,13 @@ function UseApiData<T = any>(

## Caching

By default, a [unique key for each request is generated](/guide/caching) to ensure that data fetching can be properly de-duplicated across requests. You can provide a custom key by passing a string as the first argument, just like the native [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data):
By default, a [unique key is generated](/guide/caching) based in input parameters for each request to ensure that data fetching can be properly de-duplicated across requests. You can provide a custom key by passing a string as the first argument, just like the native [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data):

```ts
const key = 'all-posts'
const route = useRoute()
const key = computed(() => `posts-${route.params.id}`)

const { data } = await useMyApiData(
key,
'posts'
)
const { data } = await useMyApiData(key, 'posts')
```

::: tip
69 changes: 18 additions & 51 deletions src/runtime/composables/$api.ts
Original file line number Diff line number Diff line change
@@ -15,28 +15,22 @@ export interface BaseApiFetchOptions {
*/
client?: boolean
/**
* Cache the response for the same request
* Cache the response for the same request.
* If set to `true`, the cache key will be generated from the request options.
* @default false
*/
cache?: boolean
cache?: string | boolean
}

export type ApiFetchOptions = Omit<NitroFetchOptions<string>, 'body' | 'cache'> & {
pathParams?: Record<string, string>
body?: string | Record<string, any> | FormData | null
}

export interface $Api {
<T = any>(
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions,
): Promise<T>
<T = any>(
key: string,
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions,
): Promise<T>
}
export type $Api = <T = any>(
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions,
) => Promise<T>

export interface $OpenApi<Paths extends Record<string, PathItemObject>> {
<P extends GETPlainPaths<Paths>>(
@@ -51,42 +45,13 @@ export interface $OpenApi<Paths extends Record<string, PathItemObject>> {
path: P,
opts?: BaseApiFetchOptions & OpenApiRequestOptions<Paths[`/${P}`], M> & { method: M }
): Promise<OpenApiResponse<Paths[`/${P}`][Lowercase<M>]>>
// Support for custom unique key
<P extends GETPlainPaths<Paths>>(
key: string,
path: P,
opts?: BaseApiFetchOptions & Omit<OpenApiRequestOptions<Paths[`/${P}`]>, 'method'>
): Promise<OpenApiResponse<Paths[`/${P}`]['get']>>
<P extends GETPaths<Paths>>(
key: string,
path: P,
opts: BaseApiFetchOptions & Omit<OpenApiRequestOptions<Paths[`/${P}`]>, 'method'>
): Promise<OpenApiResponse<Paths[`/${P}`]['get']>>
<P extends AllPaths<Paths>, M extends IgnoreCase<keyof Paths[`/${P}`] & HttpMethod>>(
key: string,
path: P,
opts?: BaseApiFetchOptions & OpenApiRequestOptions<Paths[`/${P}`], M> & { method: M }
): Promise<OpenApiResponse<Paths[`/${P}`][Lowercase<M>]>>
}

export function _$api<T = any>(
endpointId: string,
path: string,
opts: ApiFetchOptions & BaseApiFetchOptions,
): Promise<T>
export function _$api<T = any>(
endpointId: string,
key: string,
path: string,
opts: ApiFetchOptions & BaseApiFetchOptions,
): Promise<T>
export function _$api<T = any>(
endpointId: string,
...args: [string, ApiFetchOptions & BaseApiFetchOptions] | [string, string, ApiFetchOptions & BaseApiFetchOptions]
opts: ApiFetchOptions & BaseApiFetchOptions = {},
): Promise<T> {
const [key = undefined] = args.length === 3 ? [args[0]] : []
const [path, opts = {}] = args.length === 3 ? [args[1], args[2]] : args

const nuxt = useNuxtApp()
const { apiParty } = useRuntimeConfig().public
const promiseMap = (nuxt._promiseMap = nuxt._promiseMap || new Map()) as Map<string, Promise<T>>
@@ -102,14 +67,16 @@ export function _$api<T = any>(
...fetchOptions
} = opts

const _key = key || `$party${hash([
endpointId,
path,
pathParams,
query,
method,
...(isFormData(body) ? [] : [body]),
])}`
const _key = typeof cache === 'string'
? cache
: `$party${hash([
endpointId,
path,
pathParams,
query,
method,
...(isFormData(body) ? [] : [body]),
])}`

if (client && !apiParty.allowClient)
throw new Error('Client-side API requests are disabled. Set "allowClient: true" in the module options to enable them.')
2 changes: 1 addition & 1 deletion src/runtime/composables/useApiData.ts
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ export type BaseUseApiDataOptions<T> = Omit<AsyncDataOptions<T>, 'watch'> & {
*/
client?: boolean
/**
* Cache the response for the same request
* Cache the response for the same request.
* @default true
*/
cache?: boolean