工具 | 自动生成api接口

简介: 这是一个将swagger接口文档自动生成TypeScript的api接口以及interface定义。

这是一个将swagger接口文档自动生成TypeScript的api接口以及interface定义。

说明

  • 该示例的url是apifox接口文档导出的url
  • 命名:接口分组的目录需要是对应的tag

  • 参数说明:在接口请求参数中,需要按照实际规定来写,不管是在 params 还是 body 中,如果是必填项,请设置必填,这样会得到 required:true , 那么在 interface 中就没有可选,否则会得到 required:false,那么在 interface 中会有可选操作符。

  • 结果示例:

使用

  • 直接node这个文件,即可生成api文件

代码

/**
 * 说明:此文件是基于apifox创建,如果是swagger也应该是适用的,api获取是从项目设置的中的打开url获取,我这里是选择的是swagger2.0
 * fun api函数名称
 * funArr api定义的约束数组
 * oldTag 上一组tag
 * srcFolder 生产的api文件夹
 * url 需要生产api的链接
 */
const fs = require("fs");
const path = require("path");
const http = require("http");

let fun = "";
let funArr = [];
let oldTag = "";
const srcFolder = "./src/server";
const typeFolder = "./types/server";
const url = "http://127.0.0.1:4523/export/openapi?projectId=603885&version=2.0";

const mkdirsSync = (dirname) => {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
};

const getPath = (pathUrl) => {
  return path.resolve(__dirname, pathUrl);
};

const generateTemplate = (tagName) => {
  let str = "";
  funArr.forEach((v) => {
    str += `${v}Type,`;
  });
  return `import request from '../../request'
import {${str} } from '../../types/server/${tagName}.types'
`;
};
const generateFunc = (url, summary, type = "post") => {
  const arr = url.slice(1).split("/");
  fun = arr[arr.length - 1].replace(/^\S/, (s) => s.toUpperCase());
  funArr.push(fun);
  return `
// ${summary || ""}
export const  ${fun} = (${
    type === "get" ? `params:${fun}Type` : `data:${fun}Type`
  }):Promise<any> =>{
  return request({
    url:'${url}',
    method: '${type}',
    ${type === "get" ? "params" : "data"},
  })
}
`;
};

const generateTypeFunc = (typeName, str) => {
  return `
export interface ${typeName}Type {
${str}
}
`;
};

const httpgetJson = (url) => {
  return new Promise((resolve, reject) => {
    http
      .get(url, (res) => {
        const { statusCode } = res;
        const contentType = res.headers["content-type"];
        let error;
        if (statusCode !== 200) {
          error = new Error("请求失败。" + `状态码: ${statusCode}`);
        } else if (!contentType.includes("application/json")) {
          error = new Error(
            "无效的 content-type." +
              `期望 application/json 但获取的是 ${contentType}`
          );
        }
        if (error) {
          console.error(error.message);
          // 消耗响应数据以释放内存
          res.resume();
          return;
        }

        res.setEncoding("utf8");
        let rawData = "";
        res.on("data", (chunk) => {
          rawData += chunk;
        });
        res.on("end", () => {
          try {
            const parsedData = JSON.parse(rawData);
            resolve(parsedData);
          } catch (e) {
            reject(`错误: ${e.message}`);
          }
        });
      })
      .on("error", (e) => {
        reject(`错误: ${e.message}`);
      });
  });
};

const main = async () => {
  console.log("正在获取apifox文件...");
  const { paths } = await httpgetJson(url);
  console.log("获取成功,正在生成api文件...");
  const obj = {};
  const typeObj = {};
  for (const name in paths) {
    const path = paths[name];
    let folder = "";
    if (path.post) {
      const tag = path.post.tags[0];
      if (!tag) continue;
      const urlArray = name.slice(1).split("/");
      const typeName = urlArray[1] ? urlArray[1] : urlArray[0];
      if (name.slice(1).split("/").length === 4) {
        folder = urlArray[1];
      } else {
        if (name.slice(1).split("/")[0] !== tag) continue;
      }

      if (obj[path.post.tags[0]]) {
        obj[path.post.tags[0]].push({
          summary: path.post.summary,
          tag,
          name,
          type: "post",
          folder,
        });
      } else {
        obj[path.post.tags[0]] = [
          { summary: path.post.summary, tag, name, type: "post", folder },
        ];
      }
      if (typeObj[path.post.tags[0]]) {
        path.post.parameters.forEach((v) => {
          typeObj[path.post.tags[0]].push({
            ...v,
            tag: tag.replace(/^\S/, (s) => s.toUpperCase()),
            folder: urlArray[0],
            typeName: urlArray[1] ? urlArray[1] : urlArray[0],
          });
        });
      } else {
        typeObj[path.post.tags[0]] = [];
        path.post.parameters.forEach((v) => {
          typeObj[path.post.tags[0]].push({
            ...v,
            tag: tag.replace(/^\S/, (s) => s.toUpperCase()),
            folder: urlArray[0],
            typeName: urlArray[1] ? urlArray[1] : urlArray[0],
          });
        });
      }
    } else if (path.get) {
      const tag = path.get.tags[0];

      if (!tag) continue;
      const urlArray = name.slice(1).split("/");
      const typeName = urlArray[1] ? urlArray[1] : urlArray[0];
      if (name.slice(1).split("/").length === 4) {
        folder = urlArray[1];
      } else {
        if (name.slice(1).split("/")[0] !== tag) continue;
      }

      if (obj[path.get.tags[0]]) {
        obj[path.get.tags[0]].push({
          summary: path.get.summary,
          tag,
          name,
          type: "get",
          folder,
        });
      } else {
        obj[path.get.tags[0]] = [
          { summary: path.get.summary, tag, name, type: "get", folder },
        ];
      }
      if (typeObj[path.get.tags[0]]) {
        path.get.parameters.forEach((v) => {
          typeObj[path.get.tags[0]].push({
            ...v,
            tag: tag.replace(/^\S/, (s) => s.toUpperCase()),
            folder: urlArray[0],
            typeName: urlArray[1] ? urlArray[1] : urlArray[0],
          });
        });
      } else {
        typeObj[path.get.tags[0]] = [];
        path.get.parameters.forEach((v) => {
          typeObj[path.get.tags[0]].push({
            ...v,
            tag: tag.replace(/^\S/, (s) => s.toUpperCase()),
            folder: urlArray[0],
            typeName: urlArray[1] ? urlArray[1] : urlArray[0],
          });
        });
      }
    }
  }
  // 创建api文件
  for (const tagName in obj) {
    let jsString = "";
    const requestTypes = [];
    let folder = "";
    for (const item of obj[tagName]) {
      if (item.tag !== oldTag) {
        funArr = [];
      }
      oldTag = item.tag;
      const requestType = requestTypes.filter((o) => o === item.type);
      if (requestType.length === 0) requestTypes.push(item.type);
      jsString += generateFunc(item.name, item.summary, item.type);
      folder = item.folder;
    }
    jsString = generateTemplate(tagName) + jsString;
    mkdirsSync(getPath(`${srcFolder}/${folder}`));
    fs.writeFileSync(getPath(`${srcFolder}/${folder}/${tagName}.ts`), jsString);
  }
  // 创建types文件
  mkdirsSync(getPath(`${typeFolder}`));
  for (const typeName in typeObj) {
    let typeStr = "";
    let typeNameStr = "";
    let index = 0;
    let beginIndex = 0;
    let endIndex = 0;
    const currentTypeItemNameList = typeObj[typeName].map((v) => {
      return v.typeName;
    });
    for (const item of typeObj[typeName]) {
      console.log("item", item.name);
      typeStr += `${item.name}${item.required ? "" : "?"}:${item.type},`;
      index++;
      if (index === typeObj[typeName].length) {
        const newStrList = typeStr.split(",");
        currentTypeItemNameList.forEach((v, i) => {
          if (v != currentTypeItemNameList[i + 1]) {
            endIndex = i + 1;
            typeNameStr += generateTypeFunc(
              v.replace(/^\S/, (s) => s.toUpperCase()),
              newStrList.slice(beginIndex, endIndex).join(",\n ")
            );
            beginIndex = i + 1;
          }
        });
      }
    }

    fs.writeFileSync(
      getPath(`${typeFolder}/${typeName}.types.ts`),
      typeNameStr
    );
  }
  console.log("api文件生成完毕!");
};

main();

注:思路参考网络,加上自己思考以及功能需求,最终形成这样的版本代码!

相关文章
|
19天前
|
API 数据库 决策智能
基于百炼平台qwen-max的api 打造一套 检索增强 图谱增强 智能工具调用决策的智能体
本文介绍了一种基于阿里云百炼平台的`qwen-max` API构建的智能体方案,该方案集成了检索增强、图谱增强及智能工具调用决策三大模块,旨在通过结合外部数据源、知识图谱和自动化决策提高智能回答的准确性和丰富度。通过具体代码示例展示了如何实现这些功能,最终形成一个能灵活应对多种查询需求的智能系统。
99 11
|
19天前
|
自然语言处理 NoSQL API
基于百炼平台qwen-max的api 打造一套 检索增强 图谱增强 基于指令的智能工具调用决策 智能体
基于百炼平台的 `qwen-max` API,设计了一套融合检索增强、图谱增强及指令驱动的智能工具调用决策系统。该系统通过解析用户指令,智能选择调用检索、图谱推理或模型生成等工具,以提高问题回答的准确性和丰富性。系统设计包括指令解析、工具调用决策、检索增强、图谱增强等模块,旨在通过多种技术手段综合提升智能体的能力。
101 5
|
11天前
|
人工智能 自然语言处理 API
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
谷歌推出的Multimodal Live API是一个支持多模态交互、低延迟实时互动的AI接口,能够处理文本、音频和视频输入,提供自然流畅的对话体验,适用于多种应用场景。
59 3
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
|
6天前
|
前端开发 API 数据库
Next 编写接口api
Next 编写接口api
|
13天前
|
XML JSON 缓存
阿里巴巴商品详情数据接口(alibaba.item_get) 丨阿里巴巴 API 实时接口指南
阿里巴巴商品详情数据接口(alibaba.item_get)允许商家通过API获取商品的详细信息,包括标题、描述、价格、销量、评价等。主要参数为商品ID(num_iid),支持多种返回数据格式,如json、xml等,便于开发者根据需求选择。使用前需注册并获得App Key与App Secret,注意遵守使用规范。
|
12天前
|
JSON API 开发者
淘宝买家秀数据接口(taobao.item_review_show)丨淘宝 API 实时接口指南
淘宝买家秀数据接口(taobao.item_review_show)可获取买家上传的图片、视频、评论等“买家秀”内容,为潜在买家提供真实参考,帮助商家优化产品和营销策略。使用前需注册开发者账号,构建请求URL并发送GET请求,解析响应数据。调用时需遵守平台规定,保护用户隐私,确保内容真实性。
|
12天前
|
搜索推荐 数据挖掘 API
淘宝天猫商品评论数据接口丨淘宝 API 实时接口指南
淘宝天猫商品评论数据接口(Taobao.item_review)提供全面的评论信息,包括文字、图片、视频评论、评分、追评等,支持实时更新和高效筛选。用户可基于此接口进行数据分析,支持情感分析、用户画像构建等,同时确保数据使用的合规性和安全性。使用步骤包括注册开发者账号、创建应用获取 API 密钥、发送 API 请求并解析返回数据。适用于电商商家、市场分析人员和消费者。
|
22天前
|
JSON API 开发工具
淘宝实时 API 接口丨淘宝商品详情接口(Taobao.item_get)
淘宝商品详情接口(Taobao.item_get)允许开发者获取商品的详细信息,包括基本信息、描述、卖家资料、图片、属性及销售情况等。开发者需注册账号、创建应用并获取API密钥,通过构建请求获取JSON格式数据,注意遵守平台规则,合理使用接口,确保数据准确性和时效性。
|
23天前
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
103 5
|
23天前
|
JSON 缓存 监控
淘宝商品详情接口(Taobao.item_get)丨淘宝API接口指南
淘宝商品详情接口(Taobao.item_get)允许开发者通过HTTP GET方法获取淘宝商品的详细信息,包括商品ID、价格、库存等。请求需包含key、secret、num_iid等必选参数,支持缓存及多种返回格式。此接口广泛应用于电商数据分析、商品选品、价格监控等领域,提升商家运营效率。