API 客户端概述
@vafast/api-client 是专为 Vafast 框架设计的类型安全 API 客户端,基于中间件架构,支持 Eden 风格链式调用。
核心特性
- 🎯 类型安全 - 从 vafast 路由自动推断,或使用 CLI 同步类型
- 🧅 中间件架构 - Koa 风格洋葱模型,灵活组合
- 🔄 内置重试 - 支持指数退避、条件重试
- ⏱️ 超时控制 - 请求级别和全局超时
- 📡 SSE 支持 - 流式响应、自动重连
- 🎨 Go 风格错误 -
{ data, error }统一处理
安装
bash
npm install @vafast/api-client快速开始
typescript
import { createClient, eden, defineMiddleware } from '@vafast/api-client'
const tokenMiddleware = defineMiddleware(async (ctx, next) => {
const token = localStorage.getItem('token')
if (token) ctx.headers.set('Authorization', `Bearer ${token}`)
return next()
})
const client = createClient({
baseURL: 'http://localhost:3000',
timeout: 30_000,
}).use(tokenMiddleware)
const api = eden<Api>(client)
const { data, error } = await api.users.get({ page: 1 })
if (error) {
console.error(`${error.code}: ${error.message}`)
return
}
console.log(data.users)核心 API
createClient(config)
typescript
// 方式 1:只传 baseURL
const client = createClient('http://localhost:3000')
.timeout(30_000)
.use(tokenMiddleware)
// 方式 2:传配置对象(推荐)
const client = createClient({
baseURL: 'http://localhost:3000',
timeout: 30_000,
headers: { 'X-App-Id': 'my-app' },
}).use(tokenMiddleware)typescript
interface ClientConfig {
baseURL: string
timeout?: number // 默认 30000ms
headers?: Record<string, string>
}链式方法:.use(middleware) / .headers(headers) / .timeout(ms)
eden<T>(client)
typescript
import { createApiClient } from './api.generated' // CLI 生成
const api = createApiClient(client)
const { data, error } = await api.users.find.post({ current: 1, pageSize: 10 })中间件(基础)
typescript
import { defineMiddleware, retryMiddleware, loggerMiddleware } from '@vafast/api-client'
const auth = defineMiddleware(async (ctx, next) => {
const token = localStorage.getItem('token')
if (token) ctx.headers.set('Authorization', `Bearer ${token}`)
return next()
})
const client = createClient({ baseURL: '/api' })
.use(auth)
.use(retryMiddleware({ count: 3, delay: 1000 }))
.use(loggerMiddleware({ prefix: '[API]' }))多租户 app-id、token 刷新队列、多服务工厂见 高级用法。
Go 风格错误处理
所有请求返回 { data, error }:先判断 error,再使用 data,不要用 try/catch 处理 4xx/5xx 业务失败。
typescript
import { isValidationError, mapDetailsToFormFields } from '@vafast/api-client'
const { data, error } = await api.users.get()
if (error) {
if (isValidationError(error)) {
formRef.setFields(mapDetailsToFormFields(error.details))
return
}
switch (error.code) {
case 401: redirectToLogin(); break
case 403: showPermissionDenied(); break
default: showError(error.message)
}
return
}
console.log(data.users)SSE 流式响应
普通 HTTP 方法后接 .sse():
typescript
api.chat.stream.post({ messages: [{ role: 'user', content: '你好' }] }).sse({
onMessage: (data) => {
if (data.content) process.stdout.write(data.content)
},
onError: (error) => console.error(error),
onClose: () => console.log('done'),
})
const sub = api.events.get({ channel: 'live' }).sse({ onMessage: console.log })
sub.unsubscribe()请求取消
typescript
const controller = new AbortController()
const { data, error } = await api.users.get({ page: 1 }, { signal: controller.signal })
controller.abort()