swagger-typescript-api
- 支持OpenAPI 3.0、2.0、JSON和YAML
- 从OpenAPI规范生成用于Fetch或Axios的API客户端
如有任何问题,可以在这里提问
示例
所有示例可以在这里找到
使用方法
用法: sta [选项]
用法: swagger-typescript-api [选项]
用法: swagger-typescript-api generate-templates [选项]
选项:
-v, --version 输出当前版本
-p, --path <string> swagger方案的路径/url
-o, --output <string> typescript api文件的输出路径 (默认: "./")
-n, --name <string> 输出的typescript api文件名称 (默认: "Api.ts")
-t, --templates <string> 包含模板的文件夹路径
-d, --default-as-success 也将"default"响应状态码视为成功响应。
某些swagger方案默认使用"default"响应状态码作为成功响应类型。(默认: false)
-r, --responses 生成有关请求响应的附加信息
同时为错误响应添加类型定义 (默认: false)
--union-enums 将所有"enum"类型生成为联合类型 (T1 | T2 | TN) (默认: false)
--add-readonly 生成只读属性 (默认: false)
--route-types 为API路由生成类型定义 (默认: false)
--no-client 不生成API类
--enum-names-as-values 使用'x-enumNames'中的值作为枚举值(不仅作为键) (默认: false)
--extract-request-params 将请求参数提取到数据契约中 (同时将路径参数和查询参数合并为一个对象) (默认: false)
--extract-request-body 将请求体类型提取到数据契约中 (默认: false)
--extract-response-body 将响应体类型提取到数据契约中 (默认: false)
--extract-response-error 将响应错误类型提取到数据契约中 (默认: false)
--modular 为http客户端、数据契约和路由生成单独的文件 (默认: false)
--js 生成带有声明文件的js api模块 (默认: false)
--module-name-index <number> 确定应该使用哪个路径索引进行路由分离 (例如: GET:/fruits/getFruit -> index:0 -> moduleName -> fruits) (默认: 0)
--module-name-first-tag 根据第一个标签拆分路由 (默认: false)
--disableStrictSSL 禁用严格SSL (默认: false)
--disableProxy 禁用代理 (默认: false)
--axios 生成axios http客户端 (默认: false)
--unwrap-response-data 从响应中解包数据项 (默认: false)
--disable-throw-on-error 当response.ok不为true时不抛出错误 (默认: false)
--single-http-client 能够将HttpClient实例发送到Api构造函数 (默认: false)
--silent 仅将错误输出到控制台 (默认: false)
--default-response <type> 空响应模式的默认类型 (默认: "void")
--type-prefix <string> 数据契约名称前缀 (默认: "")
--type-suffix <string> 数据契约名称后缀 (默认: "")
--clean-output 在生成api之前清理输出文件夹。警告:可能导致数据丢失 (默认: false)
--api-class-name <string> api类的名称 (默认: "Api")
--patch 修复swagger源定义中的小错误 (默认: false)
--debug 关于此工具内部进程的附加信息 (默认: false)
--another-array-type 将数组类型生成为Array<Type> (默认为Type[]) (默认: false)
--sort-types 对字段和类型进行排序 (默认: false)
--sort-routes 按字母顺序对路由进行排序 (默认: false)
--custom-config <string> 自定义配置:primitiveTypeConstructs, hooks, ... (默认: "")
--extract-enums 从内联接口\类型内容中提取所有枚举到typescript枚举构造 (默认: false)
-h, --help 显示命令帮助
命令:
generate-templates 生成生成api所需的".ejs"模板
-o, --output <string> 生成模板的输出路径
-m, --modular 生成用于分离http客户端、数据契约和路由文件的模板 (默认: false)
--http-client <string> http客户端类型 (可能的值: "fetch", "axios") (默认: "fetch")
-c, --clean-output 在生成模板之前清理输出文件夹。警告:可能导致数据丢失 (默认: false)
-r, --rewrite 重写现有模板中的内容 (默认: false)
--silent 仅将错误输出到控制台 (默认: false)
-h, --help 显示命令帮助
您也可以使用npx
:
npx swagger-typescript-api -p ./swagger.json -o ./src -n myApi.ts
您可以在nodejs中使用此包:
import fs from "node:fs";
import path from "node:path";
import { generateApi, generateTemplates } from "swagger-typescript-api";
/* 注意:除了`input`、`url`、`spec`之一外,所有字段都是可选的 */
generateApi({
name: "MySuperbApi.ts",
// 设置为`false`以防止工具写入磁盘
output: path.resolve(process.cwd(), "./src/__generated__"),
url: "http://api.com/swagger.json",
input: path.resolve(process.cwd(), "./foo/swagger.json"),
spec: {
swagger: "2.0",
info: {
version: "1.0.0",
title: "Swagger Petstore",
},
// ...
},
templates: path.resolve(process.cwd(), "./api-templates"),
httpClientType: "axios", // 或 "fetch"
defaultResponseAsSuccess: false,
generateClient: true,
generateRouteTypes: false,
generateResponses: true,
toJS: false,
extractRequestParams: false,
extractRequestBody: false,
extractEnums: false,
unwrapResponseData: false,
prettier: {
// 默认情况下,prettier配置从您的项目中加载
printWidth: 120,
tabWidth: 2,
trailingComma: "all",
parser: "typescript",
},
defaultResponseType: "void",
singleHttpClient: true,
cleanOutput: false,
enumNamesAsValues: false,
moduleNameFirstTag: false,
generateUnionEnums: false,
typePrefix: "",
typeSuffix: "",
enumKeyPrefix: "",
enumKeySuffix: "",
addReadonly: false,
sortTypes: false,
sortRouters: false,
extractingOptions: {
requestBodySuffix: ["Payload", "Body", "Input"],
requestParamsSuffix: ["Params"],
responseBodySuffix: ["Data", "Result", "Output"],
responseErrorSuffix: [
"Error",
"Fail",
"Fails",
"ErrorData",
"HttpError",
"BadResponse",
],
},
/** 允许使用这些额外模板生成额外文件,详见下文 */
extraTemplates: [],
anotherArrayType: false,
fixInvalidTypeNamePrefix: "Type",
fixInvalidEnumKeyPrefix: "Value",
codeGenConstructs: (constructs) => ({
...constructs,
RecordType: (key, value) => `MyRecord<key, value>`,
}),
primitiveTypeConstructs: (constructs) => ({
...constructs,
string: {
"date-time": "Date",
},
}),
hooks: {
onCreateComponent: (component) => {},
onCreateRequestParams: (rawType) => {},
onCreateRoute: (routeData) => {},
onCreateRouteName: (routeNameInfo, rawRouteInfo) => {},
onFormatRouteName: (routeInfo, templateRouteName) => {},
onFormatTypeName: (typeName, rawTypeName, schemaType) => {},
onInit: (configuration) => {},
onPreParseSchema: (originalSchema, typeName, schemaType) => {},
onParseSchema: (originalSchema, parsedSchema) => {},
onPrepareConfig: (currentConfiguration) => {},
},
})
.then(({ files, configuration }) => {
files.forEach(({ content, name }) => {
fs.writeFile(path, content);
});
})
.catch((e) => console.error(e));
generateTemplates({
cleanOutput: false,
output: PATH_TO_OUTPUT_DIR,
httpClientType: "fetch",
modular: false,
silent: false,
rewrite: false,
});
选项
--templates
当您不想使用默认的swagger-typescript-api
输出结构时,需要此选项
您可以创建带有.ejs
或.eta
扩展名的自定义模板
模板:
api.ejs
- (生成文件) Api 类模块(位置:/templates/default, /templates/modular)data-contracts.ejs
- (生成文件) swagger schema 中的所有类型(数据契约)(位置:/templates/base)http-client.ejs
- (生成文件) HttpClient 类模块(位置:/templates/base)procedure-call.ejs
- (子模板) Api 类中的路由(位置:/templates/default, /templates/modular)route-docs.ejs
- (生成文件) Api 类中路由的文档(位置:/templates/base)route-name.ejs
- (子模板) Api 类中路由的名称(位置:/templates/base)route-type.ejs
- (--route-types
选项) (子模板) (位置:/templates/base)route-types.ejs
- (--route-types
选项) (子模板) (位置:/templates/base)data-contract-jsdoc.ejs
- (子模板) 为数据契约生成 JSDOC(位置:/templates/base)
使用方法:
- 将
swagger-typescript-api
模板复制到项目中的指定位置- 从 /templates/default 复制单个 api 文件
- 从 /templates/modular 复制多个 api 文件(使用
--modular
选项) - 从 /templates/base 复制基础模板(默认和模块化都使用的模板)
- 添加
--templates PATH_TO_YOUR_TEMPLATES
选项 - 根据需要修改 ETA 模板
注意:
Eta 有一个特殊指令可以在 Eta 模板中渲染模板 - includeFile(pathToTemplate, payload)
如果你想使用此工具中的一些默认模板,可以使用路径前缀:@base
、@default
、@modular
。
@base
- 基础模板路径
@default
- 单个 api 文件模板路径
@modular
- 多个 api 文件模板路径
示例:
includeFile("@base/data-contracts.ejs", { ...yourData, ...it })
includeFile("@default/api.ejs", { ...yourData, ...it })
includeFile("@default/procedure-call.ejs", { ...yourData, ...it })
includeFile("@modular/api.ejs", { ...yourData, ...it })
includeFile("@modular/procedure-call.ejs", { ...yourData, ...it })
includeFile("@base/route-docs.ejs", { ...yourData, ...it })
includeFile("@base/route-name.ejs", { ...yourData, ...it })
includeFile("@base/route-type.ejs", { ...yourData, ...it })
includeFile("@base/route-types.ejs", { ...yourData, ...it })
--module-name-index
当你的 api 有一个全局前缀(如 /api
)时,应该使用此选项。
示例:
GET:/api/fruits/getFruits
POST:/api/fruits/addFruits
GET:/api/vegetables/addVegetable
使用 --module-name-index 0
时,Api 类将有一个属性 api
当我们将其更改为 --module-name-index 1
时,Api 类将有两个属性 fruits
和 vegetables
--module-name-first-tag
此选项将根据 API 操作的第一个标签对其进行分组 - 反映了 Swagger UI 如何对显示的操作进行分组
extraTemplates
(NodeJS 选项)
类型 (Record<string, any> & { name: string, path: string })[]
这允许你基于额外的模板生成额外的 ts\js 文件(一个额外的模板对应一个 ts\js 文件)
示例在此
generate-templates
命令
此命令允许你生成与 --templates
选项一起使用的源模板
使用 NodeJS API 修改内部代码生成结构:
你可以使用 generateApi
选项 codeGenConstructs
和 primitiveTypeConstructs
修改用于生成输出的 TypeScript 内部结构。
codeGenConstructs
此选项的类型为 (struct: CodeGenConstruct) => Partial<CodeGenConstruct>
。
generateApi({
// ...
codeGenConstructs: (struct) => ({
Keyword: {
Number: "number",
String: "string",
Boolean: "boolean",
Any: "any",
Void: "void",
Unknown: "unknown",
Null: "null",
Undefined: "undefined",
Object: "object",
File: "File",
Date: "Date",
Type: "type",
Enum: "enum",
Interface: "interface",
Array: "Array",
Record: "Record",
Intersection: "&",
Union: "|",
},
CodeGenKeyword: {
UtilRequiredKeys: "UtilRequiredKeys",
},
/**
* $A[] 或 Array<$A>
*/
ArrayType: (content) => {
if (this.anotherArrayType) {
return `Array<${content}>`;
}
return `(${content})[]`;
},
/**
* "$A"
*/
StringValue: (content) => `"${content}"`,
/**
* $A
*/
BooleanValue: (content) => `${content}`,
/**
* $A
*/
NumberValue: (content) => `${content}`,
/**
* $A
*/
NullValue: (content) => content,
/**
* $A1 | $A2
*/
UnionType: (contents) => _.join(_.uniq(contents), ` | `),
/**
* ($A1)
*/
ExpressionGroup: (content) => (content ? `(${content})` : ""),
/**
* $A1 & $A2
*/
IntersectionType: (contents) => _.join(_.uniq(contents), ` & `),
/**
* Record<$A1, $A2>
*/
RecordType: (key, value) => `Record<${key}, ${value}>`,
/**
* readonly $key?:$value
*/
TypeField: ({ readonly, key, optional, value }) =>
_.compact([
readonly && "readonly ",
key,
optional && "?",
": ",
value,
]).join(""),
/**
* [key: $A1]: $A2
*/
InterfaceDynamicField: (key, value) => `[key: ${key}]: ${value}`,
/**
* $A1 = $A2
*/
EnumField: (key, value) => `${key} = ${value}`,
/**
* $A0.key = $A0.value,
* $A1.key = $A1.value,
* $AN.key = $AN.value,
*/
EnumFieldsWrapper: (contents) =>
_.map(contents, ({ key, value }) => ` ${key} = ${value}`).join(",\n"),
/**
* {\n $A \n}
*/
ObjectWrapper: (content) => `{\n${content}\n}`,
/**
* /** $A *\/
*/
MultilineComment: (contents, formatFn) =>
[
...(contents.length === 1
? [`/** ${contents[0]} */`]
: ["/**", ...contents.map((content) => ` * ${content}`), " */"]),
].map((part) => `${formatFn ? formatFn(part) : part}\n`),
/**
* $A1<...$A2.join(,)>
*/
TypeWithGeneric: (typeName, genericArgs) => {
return `${typeName}${
genericArgs.length ? `<${genericArgs.join(",")}>` : ""
}`;
},
}),
});
例如,如果你需要生成 Record<string, any>
而不是 object
,你可以使用以下代码:
generateApi({
// ...
codeGenConstructs: (struct) => ({
Keyword: {
Object: "Record<string, any>",
},
}),
});
primitiveTypeConstructs
这是一个类型映射器或者说是 Swagger schema 对象的翻译器。primitiveTypeConstructs
将 schema 的 type
/format
字段翻译成 TypeScript 结构。
这个选项的类型如下:
type PrimitiveTypeStructValue =
| string
| ((
schema: Record<string, any>,
parser: import("./src/schema-parser/schema-parser").SchemaParser,
) => string);
type PrimitiveTypeStruct = Record<
"integer" | "number" | "boolean" | "object" | "file" | "string" | "array",
| string
| ({ $default: PrimitiveTypeStructValue } & Record<
string,
PrimitiveTypeStructValue
>)
>;
declare const primitiveTypeConstructs: (
struct: PrimitiveTypeStruct,
) => Partial<PrimitiveTypeStruct>;
generateApi({
// ...
primitiveTypeConstructs: (struct) => ({
integer: () => "number",
number: () => "number",
boolean: () => "boolean",
object: () => "object",
file: () => "File",
string: {
$default: () => "string",
/** formats */
binary: () => "File",
file: () => "File",
"date-time": () => "string",
time: () => "string",
date: () => "string",
duration: () => "string",
email: () => "string",
"idn-email": () => "string",
"idn-hostname": () => "string",
ipv4: () => "string",
ipv6: () => "string",
uuid: () => "string",
uri: () => "string",
"uri-reference": () => "string",
"uri-template": () => "string",
"json-pointer": () => "string",
"relative-json-pointer": () => "string",
regex: () => "string",
},
array: (schema, parser) => {
const content = parser.getInlineParseContent(schema.items);
return parser.safeAddNullToType(schema, `(${content})[]`);
},
}),
});
例如,如果你需要将 "string"/"date-time"
的默认输出从 string
改为 Date
,你可以使用以下代码:
generateApi({
primitiveTypeConstructs: (struct) => ({
string: {
"date-time": "Date",
},
}),
});
关于 swagger schema 的 type/format 数据的更多信息请点击这里
媒体报道
- 关于 swagger-typescript-api 的 5 个经验教训
- 为什么前端开发需要 Swagger 方案?
- 平稳迁移到 TypeScript(法语)
- swagger-typescript-api 的使用(日语)
许可证
基于 MIT 许可证 授权。