Pivot 不仅提供了丰富的组件,还内置了一套强大的 React Hooks 和 工具函数,专门用于处理 OpenAPI 规范数据。这些工具让您能够轻松地解析、处理和操作 OpenAPI 数据结构。
🎣 React Hooks
useOpenApi
最核心的 Hook,提供了处理 OpenAPI 规范的完整功能。
import { useOpenApi } from "@/hooks/use-openapi";
import type { OpenAPIV3 } from "openapi-types";
function ApiComponent({ spec }: { spec: OpenAPIV3.Document }) {
const openApi = useOpenApi(spec);
// 获取按标签分组的操作
const operationsByTag = openApi.getOperationsByTag();
// 解析引用
const resolved = openApi.resolve(someReference);
// 获取模式类型
const type = openApi.getSchemaType(schema);
// 处理参数
const processedParams = openApi.processParameters(parameters);
return (
<div>
{Object.entries(operationsByTag).map(([tag, operations]) => (
<div key={tag}>
<h3>{tag}</h3>
{operations.map((op) => (
<div key={op.path + op.method}>
{op.method} {op.path}
</div>
))}
</div>
))}
</div>
);
}
主要功能
- 操作处理:
getOperationsByTag()
、getOperation(path, method)
- 模式处理:
getSchemaType()
、getSchemaProperties()
、getSchemaConstraints()
- 引用解析:
resolve()
- 参数处理:
processParameters()
、getRequestBodySchema()
- 响应处理:
processResponse()
- 基本信息:
getInfo()
、getServers()
、getTags()
、getComponents()
useOpenApiLoader
智能的 OpenAPI 数据加载器,支持多种数据源。
import { useOpenApiLoader } from "@/hooks/use-openapi-loader";
function ApiComponent() {
// 从 URL 加载
const { spec, loading, error } = useOpenApiLoader({
type: "url",
data: "https://api.example.com/openapi.json",
});
// 从字符串加载
const { spec: specFromString } = useOpenApiLoader({
type: "string",
data: yamlString,
});
// 从对象加载
const { spec: specFromObject } = useOpenApiLoader({
type: "object",
data: openapiObject,
});
if (loading) return <div>加载中...</div>;
if (error) return <div>加载失败: {error}</div>;
if (!spec) return <div>无数据</div>;
return <ApiExplorer spec={spec} />;
}
功能特性
- 多数据源支持:URL、字符串、对象
- 自动格式检测:JSON 和 YAML
- 错误处理:网络错误、解析错误
- 加载状态:loading、error 状态管理
- 缓存机制:避免重复加载
useOpenApiCombined
结合了加载和解析功能的综合 Hook。
import { useOpenApiCombined } from "@/hooks/use-openapi-combined";
function ApiDocumentation({ url }) {
const {
spec,
loading,
error,
openApi, // 已初始化的 useOpenApi 实例
operations,
tags,
} = useOpenApiCombined({ type: "url", data: url });
if (loading) return <div>加载 API 规范中...</div>;
if (error) return <div>错误: {error}</div>;
return (
<div>
<h1>{spec.info.title}</h1>
{Object.entries(operations).map(([tag, ops]) => (
<div key={tag}>
<h2>{tag}</h2>
{ops.map((op) => (
<OperationCard key={`${op.path}-${op.method}`} {...op} />
))}
</div>
))}
</div>
);
}
特性优势
- 一体化解决方案:加载 + 解析合二为一
- 预处理数据:operations、tags 数据已预处理
- 性能优化:内置缓存和防抖处理
- 类型安全:完整的 TypeScript 支持
useOperation
专门处理单个 API 操作的 Hook。
import { useOperation } from "@/hooks/use-operation";
function OperationComponent({ operation, path, method }) {
const op = useOperation(operation, path, method);
const operationId = op.getOperationId();
const tags = op.getTags();
const parameters = op.getParameters();
const requestBody = op.getRequestBody();
const responses = op.getResponses();
const security = op.getSecurity();
return (
<div>
<h3>{operationId}</h3>
<div>Tags: {tags.join(", ")}</div>
<div>Parameters: {parameters.length}</div>
<div>Has Request Body: {!!requestBody}</div>
<div>Response Count: {Object.keys(responses).length}</div>
</div>
);
}
主要方法
- 基本信息:
getOperationId()
、getSummary()
、getDescription()
- 分类标签:
getTags()
- 参数处理:
getParameters()
、getParametersByIn()
- 请求体:
getRequestBody()
、getRequestBodySchema()
- 响应处理:
getResponses()
、getSuccessResponses()
- 安全设置:
getSecurity()
、isSecured()
- 外部文档:
getExternalDocs()
useSchema
处理 OpenAPI Schema 对象的专用 Hook。
import { useSchema } from "@/hooks/use-schema";
function SchemaComponent({ schema, components }) {
const schemaData = useSchema(schema, components);
const type = schemaData.getType();
const properties = schemaData.getProperties();
const required = schemaData.getRequired();
const isNameRequired = schemaData.isRequired("name");
const isEmailRequired = schemaData.isRequired("email");
return (
<div>
<div>Type: {type}</div>
<div>Required Fields: {required.join(", ")}</div>
<div>Properties:</div>
{Object.entries(properties).map(([key, prop]) => (
<div key={key} className="ml-4">
{key}: {schemaData.isRequired(key) ? "Required" : "Optional"}
</div>
))}
</div>
);
}
主要功能
- 类型处理:
getType()
、isObject()
、isArray()
- 属性处理:
getProperties()
、getProperty(name)
- 必填检查:
getRequired()
、isRequired(name)
- 约束处理:
getConstraints()
、getEnum()
- 示例数据:
getExample()
、getExamples()
- 描述信息:
getDescription()
、getTitle()
🛠️ 工具函数
resolveRef
解析 OpenAPI 中的 $ref
引用。
import { resolveRef } from "@/lib/resolve-ref";
import type { OpenAPIV3 } from "openapi-types";
// 解析 Schema 引用
const resolvedSchema = resolveRef<OpenAPIV3.SchemaObject>(
{ $ref: "#/components/schemas/User" },
components
);
// 解析参数引用
const resolvedParam = resolveRef<OpenAPIV3.ParameterObject>(
{ $ref: "#/components/parameters/PageSize" },
components
);
// 解析响应引用
const resolvedResponse = resolveRef<OpenAPIV3.ResponseObject>(
{ $ref: "#/components/responses/NotFound" },
components
);
// 处理深层嵌套引用
const nestedRef = { $ref: "#/components/schemas/NestedUser" };
const resolved = resolveRef(nestedRef, components);
特性
- 自动解析嵌套引用:支持引用的引用
- 类型安全:完整的 TypeScript 类型支持
- 错误处理:优雅处理无效引用
- 智能缓存:避免重复解析相同引用
generateExample
根据 OpenAPI Schema 自动生成示例数据。
import { generateExample } from "@/lib/generate-example";
// 基本用法
const example = generateExample(schema, components);
// 高级配置
const example = generateExample(schema, components, {
maxDepth: 3, // 最大递归深度
includeReadOnly: false, // 是否包含只读属性
includeWriteOnly: true, // 是否包含只写属性
useExamples: true, // 优先使用 schema 中的示例
locale: "zh", // 生成本地化示例
});
支持的数据类型
- 基础类型:string、number、integer、boolean
- 复杂类型:object、array
- 复合模式:allOf、oneOf、anyOf
- 格式化字符串:date、date-time、email、uuid、url 等
- 约束条件:enum、pattern、min/max 等
智能生成
根据属性名自动生成合适的示例:
// 自动识别常见字段
{
"name": "张三", // 识别姓名字段
"email": "user@example.com", // 识别邮箱字段
"phone": "+86-138-0013-8000", // 识别电话字段
"address": "北京市朝阳区", // 识别地址字段
"company": "某某科技有限公司", // 识别公司字段
"website": "https://example.com", // 识别网站字段
"birthday": "1990-01-01", // 识别生日字段
"avatar": "https://avatar.example.com/user.jpg" // 识别头像字段
}
schema-utils
Schema 处理的辅助工具函数。
import {
isReferenceObject,
isSchemaObject,
getSchemaType,
mergeSchemas,
flattenAllOf,
extractEnumValues,
getSchemaConstraints,
} from "@/lib/schema-utils";
// 类型检查
if (isReferenceObject(obj)) {
console.log("这是一个引用对象");
}
if (isSchemaObject(obj)) {
console.log("这是一个 Schema 对象");
}
// 获取类型
const type = getSchemaType(schema); // "object", "array", "allOf" 等
// 处理复合 Schema
const merged = mergeSchemas([schema1, schema2]);
const flattened = flattenAllOf(allOfSchema);
// 提取枚举值
const enumValues = extractEnumValues(enumSchema);
// 获取约束条件
const constraints = getSchemaConstraints(schema);
主要功能
- 类型检查:
isReferenceObject
、isSchemaObject
- 类型提取:
getSchemaType
、getSchemaFormat
- Schema 合并:
mergeSchemas
、flattenAllOf
- 约束处理:
getSchemaConstraints
、extractEnumValues
- 递归处理:
walkSchema
、transformSchema
type-utils
类型处理的工具函数。
import {
getSchemaType,
isPrimitiveType,
isComplexType,
normalizeType,
getTypeHierarchy,
formatTypeDisplay,
} from "@/lib/type-utils";
// 类型判断
const type = getSchemaType(schema);
const isPrimitive = isPrimitiveType(type);
const isComplex = isComplexType(type);
// 类型规范化
const normalized = normalizeType(rawType);
// 获取类型层次
const hierarchy = getTypeHierarchy(schema);
// 格式化类型显示
const displayType = formatTypeDisplay(type, format);
核心功能
- 类型判断:
isPrimitiveType
、isComplexType
、isNumericType
- 类型转换:
normalizeType
、formatTypeDisplay
- 类型分析:
getTypeHierarchy
、getCompatibleTypes
- 验证工具:
validateType
、isValidFormat
🌍 国际化系统
useI18n Hook
完整的国际化支持,内置中英文翻译。
import { useI18n } from "@/lib/i18n";
function MyComponent() {
const { t, locale, setLocale, availableLocales } = useI18n();
return (
<div>
<h1>{t("api.title")}</h1>
<p>{t("operation.parameters")}</p>
<p>{t("schema.required")}</p>
<div className="space-x-2">
{availableLocales.map((loc) => (
<button
key={loc}
onClick={() => setLocale(loc)}
className={locale === loc ? "font-bold" : ""}
>
{loc === "zh" ? "中文" : "English"}
</button>
))}
</div>
<div>Current locale: {locale}</div>
</div>
);
}
API 说明
- t(key, params?):翻译函数,支持参数插值
- locale:当前语言设置
- setLocale(locale):切换语言
- availableLocales:可用语言列表
I18nProvider
国际化上下文提供者,在应用根部使用。
import { I18nProvider } from "@/lib/i18n";
function App() {
return (
<I18nProvider defaultLocale="zh">
<YourAppComponents />
</I18nProvider>
);
}
翻译键值对
常用操作术语
{
"operation": {
"parameters": "参数",
"requestBody": "请求体",
"responses": "响应",
"security": "安全",
"deprecated": "已废弃",
"callbacks": "回调",
"summary": "摘要",
"description": "描述",
"operationId": "操作ID",
"tags": "标签"
}
}
Schema 相关
{
"schema": {
"type": "类型",
"format": "格式",
"required": "必填",
"optional": "可选",
"properties": "属性",
"items": "数组项",
"additionalProperties": "额外属性",
"example": "示例",
"examples": "示例",
"enum": "枚举值",
"default": "默认值",
"pattern": "正则模式",
"constraints": "约束条件"
}
}
HTTP 相关
{
"http": {
"method": "方法",
"path": "路径",
"status": "状态码",
"headers": "请求头",
"query": "查询参数",
"body": "请求体",
"form": "表单数据",
"file": "文件"
}
}
操作按钮
{
"action": {
"copy": "复制",
"expand": "展开",
"collapse": "收起",
"tryItOut": "在线测试",
"generate": "生成",
"download": "下载",
"share": "分享",
"edit": "编辑"
}
}
扩展翻译
您可以通过修改 registry/default/lib/i18n/locales/
目录下的文件来扩展翻译:
// 添加新语言支持
// registry/default/lib/i18n/locales/es.ts
export const es = {
operation: {
parameters: "Parámetros",
requestBody: "Cuerpo de Solicitud",
// ... 更多翻译
},
};
📦 批量安装
安装所有 Hooks
安装工具库
单独安装
# 安装单个 Hook
npx shadcn@latest add https://pivotkit.vercel.app/r/use-openapi.json
npx shadcn@latest add https://pivotkit.vercel.app/r/use-openapi-loader.json
# 安装单个工具函数
npx shadcn@latest add https://pivotkit.vercel.app/r/resolve-ref.json
npx shadcn@latest add https://pivotkit.vercel.app/r/generate-example.json
💡 使用建议
1. 组合使用 Hooks
// 推荐的组合使用模式
function ApiExplorer({ url }) {
// 使用组合 Hook 一次性获取所有数据
const { spec, openApi, operations, loading, error } = useOpenApiCombined({
type: "url",
data: url,
});
// 对特定操作使用专用 Hook
const currentOp = useOperation(selectedOperation, path, method);
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
return <ApiInterface spec={spec} operations={operations} />;
}
2. 错误处理
// 完善的错误处理
function ApiComponent() {
const { spec, loading, error } = useOpenApiLoader({
type: "url",
data: apiUrl,
});
if (loading) return <div>正在加载 API 规范...</div>;
if (error) {
return (
<div className="error">
<h3>加载失败</h3>
<p>{error}</p>
<button onClick={() => window.location.reload()}>重试</button>
</div>
);
}
return <ApiDocumentation spec={spec} />;
}
3. 性能优化
// 使用 React.memo 优化渲染
const OperationCard = React.memo(({ operation, path, method }) => {
const op = useOperation(operation, path, method);
// ... 渲染逻辑
});
// 使用 useMemo 缓存计算结果
function ParametersList({ parameters, components }) {
const processedParams = useMemo(
() =>
parameters.map((param) => ({
...param,
resolved: resolveRef(param, components),
})),
[parameters, components]
);
return <ParameterList items={processedParams} />;
}
通过这些强大的 Hooks 和工具函数,您可以轻松构建复杂的 OpenAPI 文档界面,同时保持代码的简洁和可维护性。