生命的意义在于折腾

Pont - 搭建前后端之桥,生成前端接口层代码

一、创建项目

bash

1yarn create vite my-react-app --template react

二、安装依赖

bash

1yarn add axios qs swr pont-engine

三、创建文件

3.1 创建src/utils/service.ts文件,内容如下

typescript

1import axios, {
2  AxiosInstance,
3  AxiosRequestConfig,
4  AxiosResponse,
5  AxiosError,
6  InternalAxiosRequestConfig,
7} from "axios";
8import qs from "qs";
9import useSwr, { SWRConfiguration ,SWRResponse} from "swr";
10
11/** 后端返回的数据类型 */
12type ResponseData<T> = T;
13// type ResponseData<T> = {
14//   code: number;
15//   data: T;
16//   message: string;
17// };
18
19/** 创建axios实例 */
20const axiosInstance: AxiosInstance = axios.create({
21  timeout: 60000,
22  baseURL:'http://localhost:3000'
23});
24
25/** 异常拦截处理器 */
26const errorHandler = (error: AxiosError) => {
27  if (error.response) {
28    switch (error.response.status) {
29      case 401:
30        // 登录过期错误处理
31        break;
32      case 500:
33        // 服务器错误处理
34        break;
35      default:
36    }
37  }
38  return Promise.reject(error);
39};
40/** 请求拦截处理器 */
41axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
42  // qs是axios自带的序列化参数方式
43  if (
44    config.headers &&
45    config.headers["Content-Type"] &&
46    (config.headers["Content-Type"] as string).includes(
47      "application/x-www-form-urlencoded"
48    )
49  ) {
50    config.params = qs.stringify(config.params);
51  }
52  return config;
53}, errorHandler);
54
55/** 响应拦截处理器 */
56axiosInstance.interceptors.response.use((response: AxiosResponse) => {
57  return response;
58}, errorHandler);
59
60/***
61 * @name axios 请求封装
62 * @config AxiosRequestConfig
63 * */
64export function service<T>(config: AxiosRequestConfig): Promise<T> {
65  return new Promise((resolve, reject) => {
66    axiosInstance
67      .request<T, AxiosResponse<ResponseData<T>>>(config)
68      .then((result: AxiosResponse<ResponseData<T>>) => {
69        const { data } = result;
70        resolve(data);
71        // if (data.code === 0) {
72        //   resolve(data.data);
73        // } else {
74        //   reject(data);
75        // }
76      })
77      .catch((err: AxiosError) => {
78        reject(err);
79      });
80  });
81}
82
83/***
84 * @name useService 请求封装
85 * @config AxiosRequestConfig
86 * @options SWRConfiguration
87 * SWRResponse
88 * */
89export function useService<T>(
90  config: AxiosRequestConfig,
91  options?: SWRConfiguration | null
92):SWRResponse<T> {
93  const { isLoading, error, ...other } = useSwr(
94    options
95      ? `${config.url}${qs.stringify(config.params || {})}${qs.stringify(
96          config.data || {}
97        )}`
98      : null,
99    () => service<T>(config),
100    options || {}
101  );
102  return { ...other, isLoading: error ? false : isLoading, error };
103}
104
105

3.2 创建config/pont-config.json文件,内容如下:

json

1{
2  "outDir": "../src/services",
3  "templatePath": "./pontTemplate",
4  "originType": "SwaggerV2",
5  "originUrl": "https://petstore.swagger.io/v2/swagger.json",
6  "prettierConfig": {
7    "useTabs": false,
8    "tabWidth": 2,
9    "printWidth": 100,
10    "singleQuote": true,
11    "trailingComma": "none",
12    "bracketSpacing": true,
13    "semi": false
14  }
15}
16

3.2 创建config/pontTemplate.ts文件,内容如下:

typescript

1import { CodeGenerator, Interface } from "pont-engine";
2
3export default class MyGenerator extends CodeGenerator {
4  getInterfaceContent(inter: Interface) {
5    const url = inter.path;
6    const method = inter.method.toUpperCase();
7    const paramsCode = inter.getParamsCode();
8    const description = inter.description.replace(/(\n|\s)/g, "");
9    return ` 
10    /***
11      * @description ${description}
12      * @name ${inter.name}
13      */
14    import { useService, service } from "@/utils/service"; 
15    import type { SWRConfiguration, SWRResponse } from "swr";
16
17    export ${paramsCode};
18
19    export type Response = ${inter.responseType};
20    ${
21      inter.getBodyParamsCode()
22        ? `export type Body = ${inter.getBodyParamsCode()};`
23        : ""
24    }
25    
26
27    export function request(params:Params${
28      inter.getBodyParamsCode() ? `,data:Body` : ""
29    },): Promise<Response> {
30      return service<Response>({
31        url:\`${url.replace(/{/g, "${params.")}\`,
32        method:"${method}",
33        params,
34        ${inter.getBodyParamsCode() ? `data` : ""}
35      })
36    }
37    export function useRequest(params:Params${
38      inter.getBodyParamsCode() ? `,data:Body` : ""
39    }, options?: SWRConfiguration | null):SWRResponse<Response> {
40      return useService<Response>({
41        url:\`${url.replace(/{/g, "${params.")}\`,
42        method:"${method}",
43        params,
44        ${inter.getBodyParamsCode() ? `data` : ""}
45      },options)
46    }
47   `;
48  }
49  /** 获取总的类型定义代码 */
50  getDeclaration() {
51    return `
52    type ObjectMap<Key extends string | number | symbol = any, Value = any> = {
53      [key in Key]: Value;
54    }
55   
56    declare type SWRConfiguration = import('swr').SWRConfiguration
57    declare type SWRResponse<T> = import('swr').SWRResponse<T>
58
59    ${this.getCommonDeclaration()}
60
61    ${this.getBaseClassesInDeclaration()}
62
63    ${this.getModsDeclaration()}
64  `;
65  }
66  getInterfaceContentInDeclaration(inter: Interface) {
67    const paramsCode = inter.getParamsCode();
68    const description = inter.description.replace(/(\n|\s)/g, "");
69    return ` 
70    /***
71      * @description ${description}
72      * @name ${inter.name}
73      */
74    
75    export ${paramsCode};
76
77
78    export type Response = ${inter.responseType};
79    ${
80      inter.getBodyParamsCode()
81        ? `export type Body = ${inter.getBodyParamsCode()};`
82        : ""
83    }
84    
85
86    export function request(params:Params${
87      inter.getBodyParamsCode() ? `,data:Body` : ""
88    },): Promise<Response>;
89    export function useRequest(params:Params${
90      inter.getBodyParamsCode() ? `,data:Body` : ""
91    }, options?: SWRConfiguration | null): SWRResponse<Response>;
92   `;
93  }
94  /** 获取所有模块的 index 入口文件 */
95  getModsIndex() {
96    let conclusion = `
97      export {
98        ${this.dataSource.mods.map((mod) => mod.name).join(", \n")}
99      };
100    `;
101
102    // dataSource name means multiple dataSource
103    if (this.dataSource.name) {
104      conclusion = `
105        export const ${this.dataSource.name} = {
106          ${this.dataSource.mods.map((mod) => mod.name).join(", \n")}
107        };
108      `;
109    }
110
111    return `
112      ${this.dataSource.mods
113        .map((mod) => {
114          return `import * as ${mod.name} from './${mod.name}';`;
115        })
116        .join("\n")}
117
118      ${conclusion}
119    `;
120  }
121
122  /** 获取接口类和基类的总的 index 入口文件代码 */
123  getIndex() {
124    let conclusion = `
125      import * as API from './mods';
126      window.API = API
127    `;
128    if (this.dataSource.name) {
129      conclusion = `
130      import { ${this.dataSource.name} } from './mods/';
131      window.API = ${this.dataSource.name}
132      `;
133    }
134    return conclusion;
135  }
136}
137
138

四、拉取接口生成文件

4.1 命令拉取

package.jsonscripts新增 "pont": "pont generate",

4.2 vs code 安装插件 pont

阅读量:1157发布日期:2023-08-29 11:00:30

博客描述

Pont - 搭建前后端之桥,生成前端接口层代码,解放生产力

留言板