Pont - 搭建前后端之桥,生成前端接口层代码
# 一、创建项目
```bash
yarn create vite my-react-app --template react
```
# 二、安装依赖
```bash
yarn add axios qs swr pont-engine
```
# 三、创建文件
## 3.1 创建`src/utils/service.ts`文件,内容如下
```typescript
import axios, {
AxiosInstance,
AxiosRequestConfig,
AxiosResponse,
AxiosError,
InternalAxiosRequestConfig,
} from "axios";
import qs from "qs";
import useSwr, { SWRConfiguration ,SWRResponse} from "swr";
/** 后端返回的数据类型 */
type ResponseData<T> = T;
// type ResponseData<T> = {
// code: number;
// data: T;
// message: string;
// };
/** 创建axios实例 */
const axiosInstance: AxiosInstance = axios.create({
timeout: 60000,
baseURL:'http://localhost:3000'
});
/** 异常拦截处理器 */
const errorHandler = (error: AxiosError) => {
if (error.response) {
switch (error.response.status) {
case 401:
// 登录过期错误处理
break;
case 500:
// 服务器错误处理
break;
default:
}
}
return Promise.reject(error);
};
/** 请求拦截处理器 */
axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
// qs是axios自带的序列化参数方式
if (
config.headers &&
config.headers["Content-Type"] &&
(config.headers["Content-Type"] as string).includes(
"application/x-www-form-urlencoded"
)
) {
config.params = qs.stringify(config.params);
}
return config;
}, errorHandler);
/** 响应拦截处理器 */
axiosInstance.interceptors.response.use((response: AxiosResponse) => {
return response;
}, errorHandler);
/***
* @name axios 请求封装
* @config AxiosRequestConfig
* */
export function service<T>(config: AxiosRequestConfig): Promise<T> {
return new Promise((resolve, reject) => {
axiosInstance
.request<T, AxiosResponse<ResponseData<T>>>(config)
.then((result: AxiosResponse<ResponseData<T>>) => {
const { data } = result;
resolve(data);
// if (data.code === 0) {
// resolve(data.data);
// } else {
// reject(data);
// }
})
.catch((err: AxiosError) => {
reject(err);
});
});
}
/***
* @name useService 请求封装
* @config AxiosRequestConfig
* @options SWRConfiguration
* SWRResponse
* */
export function useService<T>(
config: AxiosRequestConfig,
options?: SWRConfiguration | null
):SWRResponse<T> {
const { isLoading, error, ...other } = useSwr(
options
? `${config.url}${qs.stringify(config.params || {})}${qs.stringify(
config.data || {}
)}`
: null,
() => service<T>(config),
options || {}
);
return { ...other, isLoading: error ? false : isLoading, error };
}
```
## 3.2 创建`config/pont-config.json`文件,内容如下:
```json
{
"outDir": "../src/services",
"templatePath": "./pontTemplate",
"originType": "SwaggerV2",
"originUrl": "https://petstore.swagger.io/v2/swagger.json",
"prettierConfig": {
"useTabs": false,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"semi": false
}
}
```
## 3.2 创建`config/pontTemplate.ts`文件,内容如下:
```typescript
import { CodeGenerator, Interface } from "pont-engine";
export default class MyGenerator extends CodeGenerator {
getInterfaceContent(inter: Interface) {
const url = inter.path;
const method = inter.method.toUpperCase();
const paramsCode = inter.getParamsCode();
const description = inter.description.replace(/(\n|\s)/g, "");
return `
/***
* @description ${description}
* @name ${inter.name}
*/
import { useService, service } from "@/utils/service";
import type { SWRConfiguration, SWRResponse } from "swr";
export ${paramsCode};
export type Response = ${inter.responseType};
${
inter.getBodyParamsCode()
? `export type Body = ${inter.getBodyParamsCode()};`
: ""
}
export function request(params:Params${
inter.getBodyParamsCode() ? `,data:Body` : ""
},): Promise<Response> {
return service<Response>({
url:\`${url.replace(/{/g, "${params.")}\`,
method:"${method}",
params,
${inter.getBodyParamsCode() ? `data` : ""}
})
}
export function useRequest(params:Params${
inter.getBodyParamsCode() ? `,data:Body` : ""
}, options?: SWRConfiguration | null):SWRResponse<Response> {
return useService<Response>({
url:\`${url.replace(/{/g, "${params.")}\`,
method:"${method}",
params,
${inter.getBodyParamsCode() ? `data` : ""}
},options)
}
`;
}
/** 获取总的类型定义代码 */
getDeclaration() {
return `
type ObjectMap<Key extends string | number | symbol = any, Value = any> = {
[key in Key]: Value;
}
declare type SWRConfiguration = import('swr').SWRConfiguration
declare type SWRResponse<T> = import('swr').SWRResponse<T>
${this.getCommonDeclaration()}
${this.getBaseClassesInDeclaration()}
${this.getModsDeclaration()}
`;
}
getInterfaceContentInDeclaration(inter: Interface) {
const paramsCode = inter.getParamsCode();
const description = inter.description.replace(/(\n|\s)/g, "");
return `
/***
* @description ${description}
* @name ${inter.name}
*/
export ${paramsCode};
export type Response = ${inter.responseType};
${
inter.getBodyParamsCode()
? `export type Body = ${inter.getBodyParamsCode()};`
: ""
}
export function request(params:Params${
inter.getBodyParamsCode() ? `,data:Body` : ""
},): Promise<Response>;
export function useRequest(params:Params${
inter.getBodyParamsCode() ? `,data:Body` : ""
}, options?: SWRConfiguration | null): SWRResponse<Response>;
`;
}
/** 获取所有模块的 index 入口文件 */
getModsIndex() {
let conclusion = `
export {
${this.dataSource.mods.map((mod) => mod.name).join(", \n")}
};
`;
// dataSource name means multiple dataSource
if (this.dataSource.name) {
conclusion = `
export const ${this.dataSource.name} = {
${this.dataSource.mods.map((mod) => mod.name).join(", \n")}
};
`;
}
return `
${this.dataSource.mods
.map((mod) => {
return `import * as ${mod.name} from './${mod.name}';`;
})
.join("\n")}
${conclusion}
`;
}
/** 获取接口类和基类的总的 index 入口文件代码 */
getIndex() {
let conclusion = `
import * as API from './mods';
window.API = API
`;
if (this.dataSource.name) {
conclusion = `
import { ${this.dataSource.name} } from './mods/';
window.API = ${this.dataSource.name}
`;
}
return conclusion;
}
}
```
# 四、拉取接口生成文件
## 4.1 命令拉取
> 在`package.json`中`scripts`新增` "pont": "pont generate",`
## 4.2 vs code 安装插件 `pont`
博客描述
Pont - 搭建前后端之桥,生成前端接口层代码,解放生产力