$api

View source
由 api.factory 插件创建的增强型 $fetch 实例,支持认证注入、数据解包、业务检查和多端点切换。

介绍

$api 是通过 Nuxt 插件注入的全局 $fetch 实例,内置完整的拦截器链(认证注入、业务状态码检查、数据解包、Toast 提示)。它是所有 API composable(useApiFetchuseLazyApiFetch 等)的底层引擎。

基础用法

const { $api } = useNuxtApp()

// GET 请求(数据已自动解包)
const users = await $api<User[]>('/users')

// POST 请求
const user = await $api<User>('/users', {
  method: 'POST',
  body: { name: 'test', email: 'test@example.com' }
})

// PUT 请求
const updated = await $api<User>(`/users/${id}`, {
  method: 'PUT',
  body: { name: 'new-name' }
})

// DELETE 请求
await $api(`/users/${id}`, { method: 'DELETE' })
$api 返回的数据已经过拦截器自动解包(提取 dataKey 字段),泛型 T 直接对应业务数据类型。

多端点切换

使用 $api.use(endpoint) 切换到指定端点:

const { $api } = useNuxtApp()

// 使用默认端点
const users = await $api('/users')

// 切换到 admin 端点
const adminUsers = await $api.use('admin')('/users')

// 保存端点引用,避免重复 use()
const adminApi = $api.use('admin')
const config = await adminApi('/config')
const stats = await adminApi('/stats')

端点实例内部有缓存机制,多次调用 $api.use('admin') 返回同一实例。

了解如何配置多个 API 端点

在事件处理器中使用

事件处理器中使用 $api 是最常见的场景:

<script setup lang="ts">
const { $api } = useNuxtApp()

// 表单提交
async function handleCreate(formData: CreateUserRequest) {
  try {
    const user = await $api<User>('/users', {
      method: 'POST',
      body: formData
    })
    // Toast 已自动显示,无需手动处理
    navigateTo(`/users/${user.id}`)
  }
  catch (error) {
    // 业务错误 Toast 已自动显示
    // 此处可做额外逻辑(如表单字段高亮)
  }
}

// 删除确认
async function handleDelete(id: string) {
  await $api(`/users/${id}`, { method: 'DELETE' })
  await refreshNuxtData() // 刷新页面缓存数据
}
</script>

在 useAsyncData 中使用

当需要聚合多个接口或做复杂数据处理时,在 useAsyncData 中使用 $api

const { $api } = useNuxtApp()

// 聚合多个接口
const { data: dashboard } = await useAsyncData('dashboard', async () => {
  const [users, stats, recent] = await Promise.all([
    $api<User[]>('/users'),
    $api<Stats>('/stats'),
    $api<Activity[]>('/activity/recent')
  ])
  return { users, stats, recent }
})

封装自定义 composable

composables/useDashboard.ts
export function useDashboard() {
  const { $api } = useNuxtApp()

  return useAsyncData('dashboard', async () => {
    const [users, stats] = await Promise.all([
      $api<User[]>('/users'),
      $api<Stats>('/stats')
    ])
    return { users, stats }
  })
}

业务操作 composable

对于删除、审批等写操作,将 $api 调用封装到独立的 composable 中,保持页面文件精简:

composables/useUserActions.ts
export function useUserActions() {
  const { $api } = useNuxtApp()

  async function remove(id: string) {
    await $api(`/users/${id}`, { method: 'DELETE' })
    await refreshNuxtData()
  }

  async function create(data: CreateUserRequest) {
    return await $api<User>('/users', {
      method: 'POST',
      body: data,
    })
  }

  async function updateRole(id: string, role: UserRole) {
    return await $api<User>(`/users/${id}/role`, {
      method: 'PUT',
      body: { role },
      context: { toast: { successMessage: '角色已更新' } },
    })
  }

  return { remove, create, updateRole }
}
pages/users/index.vue
<script setup lang="ts">
// 数据获取用 useApiFetch
const { data: users, refresh } = await useApiFetch<User[]>('/users')

// 写操作用 $api composable
const { remove, updateRole } = useUserActions()
</script>
了解完整的 Composable 层设计模式和薄 View 层理念

请求级配置

通过 context 字段传递请求级配置:

const { $api } = useNuxtApp()

// 禁用 Toast
await $api('/users', {
  context: { toast: false }
})

// 自定义 Toast 消息
await $api('/users', {
  method: 'POST',
  body: formData,
  context: {
    toast: { successMessage: '创建成功' }
  }
})

// 跳过业务状态码检查(直接返回原始解包数据)
const raw = await $api('/external-api/data', {
  context: { skipBusinessCheck: true }
})
context 字段通过 ofetch 的 FetchOptions 扩展传递,仅 Movk Nuxt 的 $api 实例识别此字段。原生 $fetch 不会处理这些选项。

API

ApiInstance

$api 的类型定义:

type ApiInstance = $Fetch & {
  use: (endpoint: string) => ApiInstance
}
$api(url, options)
Promise<T>
发送 API 请求。支持所有 ofetch 的选项,额外支持 context 字段。
$api.use(endpoint)
ApiInstance
切换到指定端点,返回该端点的 $api 实例。端点实例内部有缓存,多次调用返回同一实例。

ApiFetchContext

通过 options.context 传递的扩展配置:

toast
RequestToastOptions | false
Toast 提示配置。设为 false 禁用所有 Toast。
skipBusinessCheck
boolean
跳过业务状态码检查。设为 true 时不抛出 ApiError,但仍会解包 dataKey 字段。
Copyright © 2025 - 2026 YiXuan - MIT License