Project Icon

swagger-typescript-api

生成TypeScript API客户端的OpenAPI工具

swagger-typescript-api是一款从OpenAPI规范生成TypeScript API客户端的工具。支持OpenAPI 3.0和2.0,兼容JSON和YAML格式。可生成适用于Fetch或Axios的API类。提供模板定制、模块化输出和枚举处理等自定义选项。通过命令行或Node.js API轻松集成,有助于提升API开发效率。

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扩展名的自定义模板

模板:

使用方法:

  1. swagger-typescript-api 模板复制到项目中的指定位置
  2. 添加 --templates PATH_TO_YOUR_TEMPLATES 选项
  3. 根据需要修改 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 类将有两个属性 fruitsvegetables

--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 选项 codeGenConstructsprimitiveTypeConstructs 修改用于生成输出的 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 数据的更多信息请点击这里

媒体报道

许可证

基于 MIT 许可证 授权。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号