Skip to content

$fetch-Like Composable

Returns the raw API response. Intended for actions inside methods, e.g. when sending form data on submit.

Placeholder

$myApi is a placeholder. The composable is generated based on your API endpoint ID. For example, endpoint jsonPlaceholder generates $jsonPlaceholder.

Type Declarations

ts
export interface SharedFetchOptions {
  /**
   * Skip the Nuxt server proxy and fetch directly from the API.
   * Requires `client` set to `true` in the module options.
   * @remarks
   * If Nuxt SSR is disabled, client-side requests are enabled by default.
   * @default false
   */
  client?: boolean
  /**
   * The browser cache behavior.
   *
   * @remarks
   * This option is forwarded to the `fetch` API as the `cache` option.
   *
   * @default 'default'
   * @see https://developer.mozilla.org/en-US/docs/Web/API/Request/cache
   * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
   */
  cache?: RequestInit['cache']
  /**
   * Serve a repeated request from the Nuxt payload instead of sending it again.
   *
   * @remarks
   * A response fetched during SSR is always handed to the client through the payload. This option decides whether
   * the client keeps caching on its own afterwards. Requires the module option of the same name.
   *
   * @default false
   */
  payloadCache?: boolean
  /**
   * Cache key, generated from the request options by default.
   */
  key?: string
  /**
   * A custom `$fetch` function to use.
   *
   * @remarks
   * Implementers supporting server-side should wrap `useRequestFetch()`.
   *
   * @default useRequestFetch()
   * @example
   * ```ts
   * async (request, options) => {
   *   return await useRequestFetch()(request, options)
   * }
   * ```
   */
  $fetch?: H3Event$Fetch
}

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

export type ApiClient = <T = unknown>(
  path: string,
  opts?: ApiClientFetchOptions & SharedFetchOptions,
) => Promise<T>

Caching

Payload caching is off by default here; payloadCache: true turns it on. The cache option controls the browser's HTTP cache separately:

ts
const data = await $myApi('posts', {
  cache: 'no-store' // or 'default', 'reload', 'no-cache', 'force-cache', 'only-if-cached'
})

The cache option needs server.proxyMode set to 'passthrough', or the request sent from the client. The default 'wrapped' mode turns every call into a POST, and a POST is never served from the browser's HTTP cache.

TIP

See the caching guide for more information on caching.

Examples

Demo Setup

These examples assume that you have set up an API endpoint called jsonPlaceholder:

ts
export default defineNuxtConfig({
  modules: ['nuxt-api-party'],

  apiParty: {
    endpoints: {
      jsonPlaceholder: {
        url: 'https://jsonplaceholder.typicode.com'
      }
    }
  }
})
vue
<script setup lang="ts">
const data = await $jsonPlaceholder(
  'posts',
  {
    method: 'POST',
    body: {
      foo: 'bar'
    },
    async onRequest({ request }) {
      console.log(request)
    },
    async onResponse({ response }) {
      console.log(response)
    },
    async onRequestError({ error }) {
      console.log(error)
    },
    async onResponseError({ error }) {
      console.log(error)
    }
  }
)
</script>

<template>
  <div>
    <h1>{{ data?.title }}</h1>
  </div>
</template>

Using With useAsyncData

Nuxt Context Issue

Calling $myApi multiple times sequentially inside useAsyncData causes server-side errors related to Nuxt context loss. This happens because async operations break the context chain that Nuxt uses to track composable calls.

When you need to make multiple API calls inside useAsyncData, use one of these workarounds:

Option 1: Use callWithNuxt Helper

Wrap subsequent calls with callWithNuxt to restore the Nuxt context:

ts
import { callWithNuxt } from '#app'

const { data } = await useAsyncData(async (nuxt) => {
  const firstResult = await $myApi('/path1')

  // Wrap the second call to restore context
  const secondResult = await callWithNuxt(nuxt!, async () =>
    await $myApi('/path2'))

  return { firstResult, secondResult }
})

Option 2: Use useMyApiData Instead

For reactive data fetching within components, prefer useMyApiData composables which handle Nuxt context automatically:

ts
// Instead of using $myApi inside useAsyncData...
const { data: posts } = await useMyApiData('posts')
const { data: comments } = await useMyApiData('comments')

Client Requests

WARNING

Authorization credentials will be publicly visible. Also, possible CORS issues ahead if the backend is not configured properly.

INFO

If Nuxt SSR is disabled, all requests are made on the client-side by default.

To fetch data directly from your API and skip the Nuxt server proxy, set the apiParty module option client to true:

ts
export default defineNuxtConfig({
  modules: ['nuxt-api-party'],

  apiParty: {
    endpoints: {
      // ...
    },
    client: true
  }
})

Now you can make client-side requests by setting the client option to true in the composable.

ts
const data = await $jsonPlaceholder(
  'posts',
  { client: true }
)
ts
const { data } = await useJsonPlaceholderData(
  'posts',
  { client: true }
)

INFO

Set the client module option to always to make all requests on the client-side.

Custom Fetch

Pass a custom fetch function for different HTTP clients or custom caching logic:

ts
const data = await $jsonPlaceholder('posts', {
  $fetch(request, options) {
    // Wrapping `useRequestFetch()` keeps local routes fetchable during SSR
    return useRequestFetch()(request, options)
  }
})

WARNING

Custom fetch functions interfere with fetching local routes during SSR, which is required for the proxy to function. Either wrap useRequestFetch() as shown, or use custom fetch only for client-side requests.

Released under the MIT License.