API 请求

安装

npx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/make-api-request.json
yarn dlx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/make-api-request.json
pnpx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/make-api-request.json
bunx shadcn@latest add https://ssp-ui-registry-staging.sh3.agoralab.co/r/make-api-request.json

功能概览

  • makeApiRequest 封装了 fetch,支持基于 Zod 的路径参数、查询参数、请求体与响应数据校验,同时提供超时与外部 AbortController 组合能力。
  • wrapUrlByOptions 可根据路径参数替换 URL 中的占位符,并拼接查询字符串,内部依赖 generateQueryStr
  • keyStartsWith 用于判断缓存键是否匹配某个模板键,便于在 SWR 中执行批量刷新。
  • 默认超时时间为 DEFAULT_FETCH_TIMEOUT = 60000 毫秒,可在调用时通过 options.timeout 覆盖。

模板定义

示例位于 registry/ssp/item/make-api-request/example/index.template.ts,通过 Zod 定义 API 模板:

const getProducts = {
  key: [ERequestMethod.GET, 'product', 'list'],
  method: ERequestMethod.GET,
  url: '/api/product',
  query: z
    .object({
      page: z.number().min(1).default(1),
      pageSize: z.number().min(1).max(100).default(10)
    })
    .optional(),
  response: z.object({
    products: z.array(Product),
    total: z.number()
  })
}

模板字段说明:

  • key: SWR 缓存键的基础部分,推荐由请求方法与资源标识组成。
  • url: 支持 :id 形式的占位符,调用时可通过 pathParameter 替换。
  • method: 请求方法,使用 ERequestMethod 枚举约束。
  • pathParameterquerybody: 可选的 Zod Schema,用于在发出请求前校验参数。
  • response: 对响应数据做 Zod 校验,保证类型安全。

发起请求

example/index.ts 中演示了如何基于模板封装实际方法:

const TemplateCreateProduct = ProductApi.createProduct
export const createProduct = async (
  payload: z.infer<typeof TemplateCreateProduct.body>
) => {
  return makeApiRequest(TemplateCreateProduct, { payload })
}

常用调用选项:

  • payload: 将在发送前通过模板中的 body Schema 校验。
  • pathParameter: 替换 URL 中的占位符,例如 { id }
  • query: 生成查询字符串,可传入对象或 URLSearchParams
  • headers: 追加请求头,默认包含 Content-Type: application/json
  • ignoreResponse: 如果为 true,跳过响应校验并直接返回原始数据。

搭配 SWR

useCancelableSwr 示例展示了如何组合 SWR 与模板:

export const useProducts = (
  query?: z.infer<typeof TemplateGetProducts.query>
) => {
  const [{ data, error, isLoading, mutate }, controller] = useCancelableSwr(
    {
      url: wrapUrlByOptions(TemplateGetProducts.url, undefined, query),
      key: [...TemplateGetProducts.key, query]
    },
    { method: TemplateGetProducts.method }
  )

  return { data, error, isLoading, mutate, controller }
}
  • 通过 wrapUrlByOptions 构造最终请求 URL。
  • globalMutate 搭配 keyStartsWith 可批量刷新同一资源相关的缓存键:
globalMutate(
  (key) => keyStartsWith(TemplateGetProducts.key, key),
  undefined,
  { revalidate: true }
)

异常处理提示

  • 当响应状态为 204/205 或返回空内容时,会返回 null
  • 如果响应 Content-Typeapplication/json,会优先解析 JSON;否则会尝试按文本解析并尽力转换为 JSON。
  • 在调试模式下,会输出请求与响应的 console.debug 日志,便于排查。
  • 当响应状态为非 200 时,会抛出 Error 对象,包含原始响应数据。