nuxt-advanced-fetch
v2.0.0
Published
Enhances Nuxt 3 $fetch with lifecycle handlers, dynamic management, and custom fetch instances for modular API requests.
Maintainers
Readme
nuxt-advanced-fetch
A Nuxt module (Nuxt 3 & 4) that extends $fetch with global interceptors, multiple lifecycle handlers per stage, and isolated API client instances.
Native Nuxt $fetch allows only one handler per lifecycle hook and no shared interceptors across calls. This module adds a $api client with pluggable global handlers, ordered execution, and the ability to create separate fetch instances (e.g. per backend) with their own handler sets—without touching the global $fetch.
Features
- Multiple handlers per lifecycle — Register several handlers for
onRequest,onRequestError,onResponse, andonResponseError; they run in a defined order (globals first, then per-call). - Ordered execution — Control handler order via an
orderoption (lower runs first) for both global and per-call handlers. - Isolated instances — Create dedicated API clients with
$api.create({ baseURL, ... }); each has its own handlers and does not inherit global ones. - Type-safe — Full TypeScript typings for handlers, options, and the
$apiclient (e.g.ApiClient,ApiFetchOptions,HandlerContextTypes). - Nuxt 3 & 4 — Built as a Nuxt module; works with Nuxt 3 and Nuxt 4. Injects
$apiviauseNuxtApp()and uses Nitro/ofetch under the hood.
Installation
npm install nuxt-advanced-fetchyarn add nuxt-advanced-fetchpnpm add nuxt-advanced-fetchAdd the module to your Nuxt config:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-advanced-fetch'],
})Quick Start
Use the injected $api client (same call signature as $fetch) and attach global handlers:
const { $api } = useNuxtApp()
// Optional: global request interceptor
$api.addHandler('onRequest', (ctx) => {
ctx.options.headers.set('X-Request-Id', crypto.randomUUID())
})
// Optional: global error handling
$api.addHandler('onResponseError', ({ response }) => {
console.error('API error', response?.status, response?._data)
})
// Use like $fetch
const data = await $api<{ id: number; title: string }>('/api/todos/1', {
method: 'GET',
})Per-call hooks still work and run after global handlers (you can pass a function or an object with handler and order):
const item = await $api('/api/items/1', {
onResponse: (ctx) => {
console.log('Fetched', ctx.response?._data)
},
})API Reference
Client: $api (type ApiClient)
Injected via useNuxtApp().$api. Callable like $fetch; accepts the same request options plus extended hook types.
| Method / signature | Description |
|--------------------|-------------|
| $api<T>(url: string, options?: ApiFetchOptions): Promise<T> | Performs a request. Runs global handlers first, then per-call hooks. Returns parsed response body. |
| addHandler<K>(type: K, handler: (ctx: HandlerContextTypes[K]) => void, options?: GlobalHandlerOptions): void | Registers a global handler for onRequest, onRequestError, onResponse, or onResponseError. Use options.order (default 0); lower runs first. |
| removeHandler<K>(type: K, handler: (ctx: HandlerContextTypes[K]) => void): void | Unregisters a global handler by reference. |
| create(defaultOptions?, customGlobalOptions?): ApiClient | Returns a new API client (e.g. with baseURL) with its own handler list. Does not inherit global handlers from $api. |
Types
| Type | Description |
|------|-------------|
| ApiClient | Type of $api and instances returned by $api.create(). |
| ApiFetchOptions | Request options for $api(); extends Nitro fetch options. Hook fields (onRequest, etc.) accept a function or LocalHandlerOptions (or array of either). |
| LocalHandlerOptions<K> | { handler: (ctx) => void, order?: number } for per-call hooks. Lower order runs first within the same phase. |
| GlobalHandlerOptions | { order?: number } for addHandler(). |
| HandlerContextTypes | Maps hook name to context type (onRequest → FetchContext, onResponseError → context with response, etc.). |
Handler execution order
- All global handlers for that hook, sorted by
order(ascending). - All per-call handlers for that hook (from
options.onRequestetc.), sorted byorder(ascending).
Examples
Multiple API backends with isolated handlers
Create one client per backend; each has its own interceptors (e.g. auth, logging) and base URL:
// plugins/api-clients.ts
export default defineNuxtPlugin(() => {
const { $api } = useNuxtApp()
const todosApi = $api.create({
baseURL: 'https://api.example.com/todos',
})
todosApi.addHandler('onRequest', (ctx) => {
ctx.options.headers.set('X-Client', 'todos-app')
})
const usersApi = $api.create({
baseURL: 'https://api.example.com/users',
})
usersApi.addHandler('onResponseError', ({ response }) => {
if (response?.status === 401) {
// e.g. redirect to login
}
})
return {
provide: {
todosApi,
usersApi,
},
}
})// Usage in a component
const { todosApi, usersApi } = useNuxtApp()
const tasks = await todosApi<Todo[]>('/')
const profile = await usersApi<User>('/me')Ordered global handlers (auth then logging)
Control the order of global handlers with the order option:
$api.addHandler('onRequest', (ctx) => {
ctx.options.headers.set('Authorization', `Bearer ${getToken()}`)
}, { order: 0 })
$api.addHandler('onRequest', (ctx) => {
console.log('[API]', ctx.request, ctx.options)
}, { order: 10 })Per-call handlers can use the same shape:
await $api('/api/data', {
onRequest: [
{ handler: (ctx) => { /* first */ }, order: 0 },
{ handler: (ctx) => { /* second */ }, order: 5 },
],
})Repository
GitHub — Daisigu/nuxt-advanced-fetch
