使用swagger-typescript-api

引言

前后端分离大致是这样的

  • 后端:控制层 / 业务层 / 数据操作层
  • 前端:控制层 / 视图层

前后端的控制层,实际上就是前后端接口的对接
前后端分离,实现了更好地解耦合,但也引入了接口对接的过程,这个过程常常是繁琐,容易产生错误的

于是引入了api接口文档,来解决这个事情,如果有一份事先约定好的接口文档,双方都按照这个来,就能实现完美的对接。(但这通常很难实现,无法预先知道需要什么接口,接口的参数,是一个反复修改的过程)

现在后端广泛采用swagger技术,能够在开发时,就能生成接口文档,并能便捷地测试接口

对前端来说,就可以根据后端项目的swagger文档,来设计前端的控制层,也就是通常的根目录下的api文件夹,将对接口的请求封装为功能函数(也是为了与视图层解耦)

// user.ts
export const getUserList = () => request.get('/user/list')

但其实,一个api函数也就是对应的一个后端接口,已经有了接口文档,为什么不能直接生成前端的控制层?

前端控制层函数看似简单,其实做到类型完备,函数提示清晰(参数类型,返回值类型,各种注释),是一个十分繁琐的过程

所以,just relax,这个过程交由swagger-typescript-api来完成吧

swagger-typescript-api

我并不是讲swagger-typescript-api教程,可以去github上看它的所有用法,我只是讲述一下我是如何使用它的

我的项目并不是一个大型前后端分离项目,仅仅是作为练手,用前后端分离的方式自己开发。如果适用于您,您可以往下看

swagger-typescript-api有两种使用方式:命令行 & node脚本程序
优缺点显然:前者方便,后者易定制

我将以命令行的方式

进入我的前端项目中,在shell中输入

npx swagger-typescript-api -p http://localhost:8080/v2/api-docs?group=Manager -o ./src/api --axios --modular --module-name-index 1 --single-http-client
  • http://localhost:8080/v2/api-docs?group=Manager 我的swagger api文档地址
  • -o ./src/api 将生成的文件输出到src下的api目录下
  • --axios 采用axios客户端,默认fetch
  • --modular 分离http client, data constracts, 和routes,否则只会生成一个大文件
    • http client 这里就是axios客户端,对其进行了一定的封装
    • data constracts api接口中,用到的参数,或者返回值类型
  • --module-name-index 1 分离routes,意思是按api路径.split('/')[1]拆分接口文件

比如我有两个controller,UserController和DishController,访问UserController下的api,都是以/admin/user开头的,而访问DishController下的api,是以/admin/dish开头,所以这样做后,也就是按照后端的controller分离api接口文件了

  • --single-http-client 意为只有一个http客户端,稍后解释

于是在api文件夹下,生成了
在这里插入图片描述
这里swagger-typescript-api替我生成了除API.ts外的所有文件

如果直接使用的话,还是不太方便,因为每个controller都是一个http客户端

意味着我需要这么调用接口
new Category().getCategoryList()
new Dish().addDish()
当然,最重要的是,我们还需要对axios进行配置!

  • 比如添加baseUrl,当然它生成的http客户端默认为localhost:8080,但我们通常都会配置为环境变量,以便切换不同环境下的后端
  • 比如添加请求拦截器,向后端请求自动携带token认证信息
  • 比如添加响应拦截器,对产生的http错误,进行捕获和反馈(如show error message,告知unauthorized)

如果没有设置--single-http-client,产生的controller是这样的

class Employee<SecurityDataType = unknown> extends HttpClient<SecurityDataType>{...}

这样,你需要为每个controller的http客户端进行相同的配置,so dity!!!

但是,设置之后,产生controller是这样的

class Employee<SecurityDataType = unknown> {
  http: HttpClient<SecurityDataType>;

  constructor(http: HttpClient<SecurityDataType>) {
    this.http = http;
  }
  ...
}

可以看到,前者是继承,后者是组合,也叫委派

但是,我们仍然需要为每个controller委派相同的http-client,所以我引入了API.ts来解决这个问题(这只是一个简单的示例)

class API<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
  public category = new Category(this);
  public common = new Common(this);
  public dish = new Dish(this);
  public employee = new Employee(this);
}

export const api = new API({
  paramsSerializer: (params) => qs.stringify(params, { indices: false }),
  baseURL: import.meta.env.VITE_APP_API_URL,
});

api.instance.interceptors.request.use(
  (config) => {
    if (getToken()) {
      config.headers["token"] = getToken();
    }
    return config;
  },
  (error) => {
    console.log(error);
    Promise.reject(error);
  }
);

api.instance.interceptors.response.use(
  (res) => {
    const code = res.data.code;
    const msg = res.data.msg || "系统未知错误,请反馈给管理员";
    if (
      res.request.responseType === "blob" ||
      res.request.responseType === "arraybuffer"
    ) {
      return res;
    }
    if (code !== 1) {
      message.error(msg);
      return Promise.reject(new Error(msg));
    } else {
      return res;
    }
  },
  (error) => {
    console.log("err" + error);
    let { message: msg } = error;
    if (msg === "Network Error") {
      msg = "后端接口连接异常";
    } else if (msg.includes("timeout")) {
      msg = "系统接口请求超时";
    } else if (msg.includes("Request failed with status code")) {
      // 获得异常http状态码
      const statusCode = +msg.substr(msg.length - 3);
      if (statusCode === 401) {
        Modal.confirm({
          title: "系统提示",
          content: "登录状态已过期,请重新登录",
          okText: "确定",
          onOk() {
            removeToken();
            location.href = "/";
          },
        });
        return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
      }
      msg = "系统接口" + statusCode + "异常";
    }
    message.error(msg);
    return Promise.reject(error);
  }
);

进行封装后,我们可以更为优雅地调用api
api.category.getCategoryList()

Is it elegant ?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/121187.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ STL - map 与 multimap用法和区别

目录 一、概述 二、用法 2.1、插入 2.2、拷贝与赋值 2.3、查找 2.4、删除 2.5、完整代码 三、其他成员类型 一、概述 map 与 multimap是存储key-value&#xff08;键-值 对&#xff09;类型的容器。不同之处在于&#xff1a;map只允许key与 value一一对应&#xff1b;…

asp.net core mvc之路由

一、默认路由 &#xff08;Startup.cs文件&#xff09; routes.MapRoute(name: "default",template: "{controllerHome}/{actionIndex}/{id?}" ); 默认访问可以匹配到 https://localhost:44302/home/index/1 https://localhost:44302/home/index https:…

PTL货位指引标签为仓储管理打开新思路

PTL货位指引标签是一种新型的仓储管理技术&#xff0c;它通过LED灯光指引和数字显示&#xff0c;为仓库管理带来了全新的管理思路和效率提升&#xff0c;成为现代物流仓库管理中的重要工具。 首先&#xff0c;PTL货位指引标签为仓储管理业务带来了管理新思路。传统的仓库管理中…

OFDM深入学习及MATLAB仿真

文章目录 前言一、OFDM 基本原理及概念1、OFDM 简介2、子载波3、符号4、子载波间隔与符号长度之间的关系 二、涉及的技术1、保护间隔2、交织3、信道编码4、扩频5、导频6、RF&#xff08;射频&#xff09;调制7、信道估计 三、变量间的关系四、IEEE 802.11a WLAN PHY 层标准五、…

matlab中的mapminmax函数初步理解和应用

matlab中的mapminmax函数初步认识 一、mapminmax 顾名思义&#xff1a;映射最大最小 二、语法及举例 2.1 语法1 [Y,PS] mapminmax(X) 将矩阵X映射形成矩阵Y, Y中每行中的最小值对应-1&#xff0c;最大值对应1。PS是一个包含映射信息的结构体。 举例&#xff1a; clc cle…

Jupyter Notebook 闪退

造成这个的原因非常非常多&#xff01; 比如什么环境变量没有配置&#xff0c;或者说jupyter和python版本不兼容&#xff0c;库不兼容等等。 但是我呢&#xff0c;以上都不是。 我是因为手残&#xff0c;删掉了不该删的文件&#xff1a; 这个操作就是打开"Anaconda Prom…

在react中组件间过渡动画如何实现?

一、是什么 在日常开发中&#xff0c;页面切换时的转场动画是比较基础的一个场景 当一个组件在显示与消失过程中存在过渡动画&#xff0c;可以很好的增加用户的体验 在react中实现过渡动画效果会有很多种选择&#xff0c;如react-transition-group&#xff0c;react-motion&…

Vb6 TCP Server服务端监听多个RFID读卡器客户端上传的刷卡数据

本示例使用设备介绍&#xff1a;WIFI无线4G网络RFID云读卡器远程网络开关物流网阅读器TTS语音-淘宝网 (taobao.com) Option ExplicitConst BUSY As Boolean False 定义常量 Const FREE As Boolean TrueDim ConnectState() As Boolean 定义连接状态 Dim ServerSendbuf(…

Kubernetes实战(四)-部署docker harbor私有仓库

1 Docker原生私有仓库Registry 1.1 原生私有仓库Registry概述 Docker的仓库主要分两类&#xff1a; 私有仓库公有仓库 共有仓库只要在官方注册用户&#xff0c;登录即可使用。但对于仓库的使用&#xff0c;企业还是会有自己的专属镜像&#xff0c;所以私有库的搭建也是很有…

数字化广告运营,小迈科技的关键一步

数据驱动广告运营是小迈科技提升整体经营效率、构建竞争优势的重要选择。 截止目前&#xff0c;小迈科技已经完成了数据驱动的广告运营体系的搭建&#xff0c;并通过与神策数据的深入合作&#xff0c;借力神策客户旅程分析平台&#xff0c;在广告投放、运营活动等各个环节实现了…

网络安全从业者用于学习和了解可以访问的顶级黑客论坛

黑客论坛目前已经成为了网络犯罪者的数字聚集地。在这些论坛上我们可以看见最新的数据泄露事件,软件的漏洞,以及黑客教程。下面我将向大家分享目前还可以访问的顶级黑客论坛,网络安全从业者用于学习和了解。 1.XSS.is(俄罗斯黑客论坛) 推出时间:2013年,2018年9月重新推出…

Jdk 1.8 for mac 详细安装教程(含版本切换)

Jdk 1.8 for mac 详细安装教程&#xff08;含版本切换&#xff09; 官网下载链接 https://www.oracle.com/cn/java/technologies/downloads/#java8-mac 一、选择我们需要安装的jdk版本&#xff0c;这里以jdk8为例&#xff0c;下载 macOS 版本&#xff0c;M芯片下载ARM64版本…

centos7安装docker容器

卸载老版本&#xff1a; $ sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine/var/lib/docker/路径下存在镜像、数据卷、容器等&#xff0c;在卸载的时候是不会自动删除…

不同规模的企业如何借助宁盾LDAP统一用户认证实现安全和效率需求?

中小企业要解决安全和业务效率问题&#xff0c;须提前规划软件基础设施&#xff0c;其中最基础的部分是建立统一账号和统一用户身份认证体系。这个体系相当于在软件系统之间建立了一套统一的身份标准&#xff0c;基于这套标准创建的账号让员工方便、高效地访问公司内的大部分软…

【解密ChatGPT】:从过去到未来,揭示其发展与变革

&#x1f38a;专栏【ChatGPT】 &#x1f33a;每日一句&#xff1a;天行健,君子以自强不息,地势坤,君子以厚德载物 ⭐欢迎并且感谢大家指出我的问题 文章目录 一、ChatGPT的发展历程 二、ChatGPT的技术原理 三、ChatGPT的应用场景 四、ChatGPT的未来趋势 五、总结 引言:随着…

基于SSM的高校疫情防控出入信息管理系统(有报告)。Javaee项目。

演示视频&#xff1a; 基于SSM的高校疫情防控出入信息管理系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Sprin…

三天打鱼两天晒网

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 前言 本系列为选择结构编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 二、题目分析 三、解题 程序运行代码 #include<stdio.h> int main(){int n;scanf("%d",&n);i…

开发常用的 3种 API 监控报告- Eolink Apikit

API 监控报告是一种监测 API 异常的工具。在 API 管理中&#xff0c;查看 API 异常监控的监控报告&#xff0c;是 Eolink Apikit 常用的功能。Eolink Apikit 的监控报告有3种&#xff1a; 单接口监控报告 流程监控报告 项目监控报告 1、单接口监控报告 单接口监控报告通常关…

jira Licenses更新步骤

有时候我们不想花钱使用jira,那么只有通过一个月以续期的方式来使用jira。下面提供下自己实测的方式 1、获取License Key 登录地址&#xff1a;https://my.atlassian.com 登录自己的Google账号&#xff0c;进入到下面账号&#xff0c;然后点击“New Trial License” product上…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发004:游戏核心消息处理 - 玩家类的实现

文章目录 0 代码仓库1 需求2 AOI设计2.1 AOI算法简介2.2 AOI数据结构及实现2.2.1 玩家2.2.2 网格对象2.2.3 游戏世界矩形2.2.4 获取周围玩家的实现2.2.5 代码测试 2.3 GameRole结合AOI创建玩家2.3.1 创建游戏世界全局对象-GameRole继承AOIWorld的Player2.3.2 把玩家到游戏世界的…