Swagger/OpenAPI 类型化 API 客户端生成指南

本教程将指导你如何使用 swagger-typescript-api 和 SWR 从 Swagger/OpenAPI 规范生成类型化的 API 客户端,并创建高效的 React 数据获取钩子。

目录

基础方案:swagger-typescript-api + 自定义 SWR 钩子

1. 安装依赖

npm install -g swagger-typescript-api
npm install swr  # 如果你还没有安装 SWR

2. 生成 API 客户端

从 Swagger/OpenAPI 规范生成 TypeScript 客户端:

npx swagger-typescript-api -p ./openapi.yaml -o src/api -n api.ts

参数说明:

  • -p: OpenAPI 规范文件路径(可以是本地文件或远程 URL)
  • -o: 输出目录
  • -n: 输出文件名

3. 创建自定义 SWR 钩子

// src/hooks/useApi.ts
import useSWR from 'swr';

const fetcher = async (url: string, init?: RequestInit) => {
  const res = await fetch(url, {
    ...init,
    headers: {
      'Content-Type': 'application/json',
      ...init?.headers,
    },
  });
  
  if (!res.ok) {
    throw new Error(await res.text());
  }
  
  return res.json();
};

export function useApi<T>(url?: string, enabled = true) {
  const shouldFetch = enabled && !!url;
  const { data, error, isLoading, mutate } = useSWR<T>(
    shouldFetch ? url : null, 
    fetcher
  );
  
  return { 
    data, 
    error, 
    isLoading, 
    mutate,
    isError: !!error,
  };
}

4. 使用生成的 API 与自定义钩子

import { TradingApi } from '@/api/api'; // 生成的 API 客户端
import { useApi } from '@/hooks/useApi';

export function useUserInfo() {
  const url = TradingApi.user.getUserInfo.path(); // 使用生成的路径方法
  return useApi<UserInfo>(url);
}

// 在组件中使用
function UserProfile() {
  const { data: user, isLoading, error } = useUserInfo();
  
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

进阶方案:使用 orval 自动生成 SWR 钩子

1. 安装依赖

npm install -D orval

2. 配置 orval

创建 orval.config.ts 配置文件:

// orval.config.ts
export default {
  trading: {
    output: {
      mode: 'tags-split', // 每个 tag 一个文件
      target: './src/api/trading-api.ts',
      schemas: './src/api/schema',
      client: 'fetch',
      mock: false,
      override: {
        mutator: {
          path: './src/api/fetcher.ts',
          name: 'customFetcher',
        },
        useHooks: true, // 启用 SWR hooks 生成
      },
    },
    input: {
      target: './openapi.yaml',
    },
  },
};

3. 创建自定义请求器

// src/api/fetcher.ts
export const customFetcher = async <TData>(
  url: string,
  options?: RequestInit,
): Promise<TData> => {
  const res = await fetch(url, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${localStorage.getItem('token') || ''}`,
      ...options?.headers,
    },
  });

  if (!res.ok) {
    throw new Error(await res.text());
  }

  return res.json();
};

4. 生成 API 客户端和钩子

npx orval

5. 使用生成的钩子

生成的文件结构:

src/
├── api/
│   ├── trading-api/
│   │   ├── alarm.ts              # 包含 useAlarmFindAlertPolicyList 等 hook
│   │   ├── auth.ts               # 其他模块
│   ├── schema/                   # 所有类型定义
│   └── fetcher.ts                # 自定义请求器

使用示例:

import { useAlarmFindAlertPolicyList } from '@/api/trading-api/alarm';

function AlertPolicyList() {
  const { data: policies, isLoading, error } = useAlarmFindAlertPolicyList({
    query: {
      offset: '0',
      limit: '10',
    },
  });

  if (isLoading) return <div>Loading policies...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <ul>
      {policies?.map(policy => (
        <li key={policy.id}>{policy.name}</li>
      ))}
    </ul>
  );
}

两种方案对比

特性 swagger-typescript-api + 自定义 SWR orval 自动生成 SWR 钩子
安装复杂度 较低 中等(需要额外配置)
自定义灵活性 高(完全控制钩子实现) 中等(通过配置调整)
生成代码量 较少(只生成 API 客户端) 较多(生成完整钩子)
维护成本 较高(需要手动维护钩子) 低(自动生成)
适合场景 需要高度自定义的简单项目 大型项目,快速开发
类型安全
自动生成请求/响应类型

推荐选择

选择基础方案 如果:
  • 项目较小
  • 需要高度自定义的请求逻辑
  • 已经有一套自己的数据获取模式
选择进阶方案 如果:
  • 项目较大,API 接口多
  • 希望快速实现标准化 API 调用
  • 需要减少样板代码

两种方案都能提供良好的类型安全性和开发体验,根据项目需求选择最适合的方式即可。

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐