Custom useFetch in Nuxt
When working with Nuxt, you might be making the frontend and fetching an external API, and you might want to set some default options for fetching from your API.
The $fetch utility function (used by the useFetch composable) is intentionally not globally configurable. This is important so that fetching behavior throughout your application remains consistent, and other integrations (like modules) can rely on the behavior of core utilities like $fetch.
However, Nuxt provides a way to create a custom fetcher for your API (or multiple fetchers if you have multiple APIs to call).
Recipe: API Client with Auth
Let's say you have an external API at https://api.nuxt.com that requires JWT authentication via nuxt-auth-utils, and you want to redirect to /login on 401 responses.
export const useAPI = createUseFetch({
baseURL: 'https://api.nuxt.com',
onRequest ({ options }) {
const { session } = useUserSession()
if (session.value?.token) {
options.headers.set('Authorization', `Bearer ${session.value.token}`)
}
},
async onResponseError ({ response }) {
if (response.status === 401) {
await navigateTo('/login')
}
},
})
Now every call to useAPI automatically includes the auth header and handles 401 redirects:
<script setup lang="ts">
const { data: profile } = await useAPI('/me')
const { data: orders } = await useAPI('/orders')
</script>
Recipe: Custom $fetch Instance
If you need lower-level control, you can create a custom $fetch instance with a Nuxt plugin and either use it with useAsyncData directly or pass it to createUseFetch.
$fetch is a configured instance of ofetch which supports adding the base URL of your Nuxt server as well as direct function calls during SSR (avoiding HTTP roundtrips).export default defineNuxtPlugin((nuxtApp) => {
const { session } = useUserSession()
const api = $fetch.create({
baseURL: 'https://api.nuxt.com',
onRequest ({ request, options, error }) {
if (session.value?.token) {
options.headers.set('Authorization', `Bearer ${session.value?.token}`)
}
},
async onResponseError ({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})
return {
provide: {
api,
},
}
})
You can then use the custom $fetch instance directly:
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncDataavoids double data fetching when doing server-side rendering (server & client on hydration).