api-integration.md 4.05 KB

API 集成指南

本文档介绍如何在项目中添加和调用 API。

API 定义模式

步骤 1:在 src/api/index.js 中定义 API

export const getProductListAPI = (params) => {
    return buildApiUrl('product_list', params)
}

export const getProductDetailAPI = (params) => {
    return buildApiUrl('product_detail', params)
}

步骤 2:在页面中使用

import { getProductListAPI } from '@/api'
import { fn } from '@/api/fn'

const fetchProducts = async () => {
  try {
    const res = await fn(getProductListAPI({ page: 1 }))
    if (res.code === 1) {
      products.value = res.data
    }
  } catch (err) {
    console.error('获取产品失败:', err)
  }
}

请求包装器(fn.js)

所有 API 调用都应通过 src/api/fn.js 的包装器:

  • ✅ 处理常见错误场景
  • ✅ 统一错误提示
  • 始终检查 res.code === 1 判断成功

完整示例

带加载状态的 API 调用

import { ref } from 'vue'
import { getProductListAPI } from '@/api'
import { fn } from '@/api/fn'

const products = ref([])
const loading = ref(false)
const error = ref(null)

const fetchProducts = async (page = 1) => {
  loading.value = true
  error.value = null

  try {
    const res = await fn(getProductListAPI({ page, limit: 20 }))

    if (res.code === 1) {
      products.value = res.data.list
    } else {
      error.value = res.msg || '获取失败'
    }
  } catch (err) {
    console.error('API 错误:', err)
    error.value = '网络错误,请重试'
  } finally {
    loading.value = false
  }
}

带分页的 API 调用

const page = ref(0)
const hasMore = ref(true)
const loading = ref(false)

const loadMore = async () => {
  if (loading.value || !hasMore.value) return

  loading.value = true
  try {
    const res = await fn(getProductListAPI({ page: page.value, limit: 20 }))

    if (res.code === 1) {
      products.value.push(...res.data.list)
      page.value++
      hasMore.value = res.data.list.length >= 20
    }
  } catch (err) {
    console.error('加载更多失败:', err)
  } finally {
    loading.value = false
  }
}

错误处理

网络错误

try {
  const res = await fn(yourAPI(params))
  // ...
} catch (err) {
  if (is_network_error(err)) {
    // 网络错误
    Taro.showToast({ title: '网络错误', icon: 'none' })
  } else if (is_timeout_error(err)) {
    // 超时
    Taro.showToast({ title: '请求超时', icon: 'none' })
  } else {
    // 其他错误
    Taro.showToast({ title: '请求失败', icon: 'none' })
  }
}

业务错误

const res = await fn(yourAPI(params))

if (res.code === 1) {
  // 成功
} else if (res.code === 401) {
  // 未登录(通常会被拦截器自动处理)
} else {
  // 业务错误
  Taro.showToast({ title: res.msg || '操作失败', icon: 'none' })
}

API 规范

请求格式

// 查询列表
yourAPI({ page: 1, limit: 20, keyword: '搜索词' })

// 获取详情
detailAPI({ id: 123 })

// 提交表单
submitAPI({ field1: 'value1', field2: 'value2' })

响应格式

// 成功
{
  code: 1,
  msg: 'success',
  data: { /* 业务数据 */ }
}

// 失败
{
  code: 0,  // 或其他错误码
  msg: '错误信息',
  data: null
}

最佳实践

✅ 推荐做法

// 1. 使用 async/await
const res = await fn(yourAPI(params))

// 2. 检查 res.code === 1
if (res.code === 1) {
  // 成功处理
}

// 3. 使用 try/catch
try {
  const res = await fn(yourAPI(params))
} catch (err) {
  // 错误处理
}

// 4. 显示加载状态
loading.value = true
// ... API 调用
loading.value = false

❌ 避免做法

// 1. 不要只检查 res.code
if (res.code) { }  // ❌

// 2. 不要忽略错误
const res = await fn(yourAPI(params))  // ❌ 无 try/catch

// 3. 不要硬编码 API URL
fetch('/srv/?a=your_action')  // ❌

参考文档