├── .eslintignore
├── .npmrc
├── .prettierignore
├── .prettierrc.js
├── Dockerfile
├── README.md
├── docker-compose.yml
├── package.json
├── pnpm-lock.yaml
├── src
├── cli.ts
├── index.ts
├── log.ts
├── mockGenerator.ts
├── openAPIParserMock
│ ├── index.ts
│ ├── primitives.ts
│ └── utils.ts
├── serviceGenerator.ts
└── util.ts
├── swagger.json
├── templates
├── interface.njk
├── serviceController.njk
└── serviceIndex.njk
├── test
├── apispe
│ └── api
│ │ ├── api0.ts
│ │ ├── index.ts
│ │ └── typings.d.ts
├── example-files
│ ├── apispec_1.json
│ ├── swagger-custom-hook.json
│ ├── swagger-empty.json
│ ├── swagger-file-convert.json
│ ├── swagger-get-method-params-convert-obj.json
│ ├── swagger-schema-contain-blank-symbol.json
│ └── swgger3.0.1.json
├── genSwagger.js
├── java-api.json
├── morse-api.json
├── oc-swagger.json
├── openapi.json
├── swagger-allof.json
├── test-allof-api.json
├── test.js
└── test.locale.js
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | /lambda/
2 | /scripts
3 | /config
4 | .history
5 | public
6 | dist
7 | .umi
8 | mock
9 | servers
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.svg
2 | package.json
3 | .umi
4 | .umi-production
5 | /dist
6 | .dockerignore
7 | .DS_Store
8 | .eslintignore
9 | *.png
10 | *.toml
11 | docker
12 | .editorconfig
13 | Dockerfile*
14 | .gitignore
15 | .prettierignore
16 | LICENSE
17 | .eslintcache
18 | *.lock
19 | yarn-error.log
20 | .history
21 | CNAME
22 | /build
23 | /public
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | singleQuote: true,
3 | trailingComma: 'all',
4 | printWidth: 100,
5 | proseWrap: 'never',
6 | endOfLine: 'lf',
7 | overrides: [
8 | {
9 | files: '.prettierrc',
10 | options: {
11 | parser: 'json',
12 | },
13 | },
14 | ],
15 | };
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine
2 | RUN npm install pnpm@^8.15.7 -g
3 | RUN pnpm config set store-dir /path/to/.pnpm-store
4 | WORKDIR /code
5 | EXPOSE 8080
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenAPI to TypeScript Generator (OpenAPI TypeScript 生成器)
2 |
3 | [](https://github.com/chenshuai2144/openapi2typescript) [](https://www.npmjs.com/package/@umijs/openapi) 
4 |
5 | [English](#english) | [中文](#chinese)
6 |
7 |
8 | ## English
9 |
10 | ### Introduction
11 | A powerful tool that generates TypeScript request code from [OpenAPI 3.0](https://swagger.io/blog/news/whats-new-in-openapi-3-0/) documentation. If you're using [umi](https://umijs.org), you might want to check out [@umijs/plugin-openapi](https://www.npmjs.com/package/@umijs/plugin-openapi) plugin instead.
12 |
13 | ### Installation
14 |
15 | ```bash
16 | npm i --save-dev @umijs/openapi
17 | # or
18 | pnpm add -D @umijs/openapi
19 | # or
20 | yarn add -D @umijs/openapi
21 | ```
22 |
23 | ### Usage
24 |
25 | 1. Create a configuration file in your project root directory. You can name it either `openapi2ts.config.ts` or `.openapi2tsrc.ts`:
26 |
27 | ```typescript
28 | export default {
29 | schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
30 | serversPath: './servers',
31 | }
32 | ```
33 |
34 | For multiple API sources, you can use an array configuration:
35 |
36 | ```typescript
37 | export default [
38 | {
39 | schemaPath: 'http://app.swagger.io/v2/swagger.json',
40 | serversPath: './servers/app',
41 | },
42 | {
43 | schemaPath: 'http://auth.swagger.io/v2/swagger.json',
44 | serversPath: './servers/auth',
45 | }
46 | ]
47 | ```
48 |
49 | 2. Add the generation script to your `package.json`:
50 |
51 | ```json
52 | {
53 | "scripts": {
54 | "openapi2ts": "openapi2ts"
55 | }
56 | }
57 | ```
58 |
59 | 3. Generate the API code:
60 |
61 | ```bash
62 | npm run openapi2ts
63 | ```
64 |
65 | ### Configuration Options
66 |
67 | | Property | Required | Description | Type | Default |
68 | |----------|----------|-------------|------|---------|
69 | | requestLibPath | No | Custom request method path | string | - |
70 | | requestOptionsType | No | Custom request options type | string | {[key: string]: any} |
71 | | requestImportStatement | No | Custom request import statement | string | - |
72 | | apiPrefix | No | API prefix | string | - |
73 | | serversPath | No | Output directory path | string | - |
74 | | schemaPath | No | Swagger 2.0 or OpenAPI 3.0 URL | string | - |
75 | | projectName | No | Project name | string | - |
76 | | authorization | No | Documentation authentication token | string | - |
77 | | namespace | No | Namespace name | string | API |
78 | | mockFolder | No | Mock directory | string | - |
79 | | enumStyle | No | Enum style | string-literal \| enum | string-literal |
80 | | nullable | No | Use null instead of optional | boolean | false |
81 | | dataFields | No | Data fields in response | string[] | - |
82 | | isCamelCase | No | Use camelCase for files and functions | boolean | true |
83 | | declareType | No | Interface declaration type | type/interface | type |
84 |
85 | ### Custom Hooks
86 |
87 | | Property | Type | Description |
88 | |----------|------|-------------|
89 | | afterOpenApiDataInited | (openAPIData: OpenAPIObject) => OpenAPIObject | Hook after OpenAPI data initialization |
90 | | customFunctionName | (data: APIDataType) => string | Custom request function name |
91 | | customTypeName | (data: APIDataType) => string | Custom type name |
92 | | customClassName | (tagName: string) => string | Custom class name |
93 | | customType | (schemaObject, namespace, originGetType) => string | Custom type getter |
94 | | customFileNames | (operationObject, apiPath, _apiMethod) => string[] | Custom file name generator |
95 |
96 |
97 | ## 中文
98 |
99 | ### 介绍
100 | 一个强大的工具,可以根据 [OpenAPI 3.0](https://swagger.io/blog/news/whats-new-in-openapi-3-0/) 文档生成 TypeScript 请求代码。如果你使用 [umi](https://umijs.org),可以考虑使用 [@umijs/plugin-openapi](https://www.npmjs.com/package/@umijs/plugin-openapi) 插件。
101 |
102 | ### 安装
103 |
104 | ```bash
105 | npm i --save-dev @umijs/openapi
106 | # 或者
107 | pnpm add -D @umijs/openapi
108 | # 或者
109 | yarn add -D @umijs/openapi
110 | ```
111 |
112 | ### 使用方法
113 |
114 | 1. 在项目根目录创建配置文件,可以命名为 `openapi2ts.config.ts` 或 `.openapi2tsrc.ts`:
115 |
116 | ```typescript
117 | export default {
118 | schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
119 | serversPath: './servers',
120 | }
121 | ```
122 |
123 | 如果需要处理多个 API 源,可以使用数组配置:
124 |
125 | ```typescript
126 | export default [
127 | {
128 | schemaPath: 'http://app.swagger.io/v2/swagger.json',
129 | serversPath: './servers/app',
130 | },
131 | {
132 | schemaPath: 'http://auth.swagger.io/v2/swagger.json',
133 | serversPath: './servers/auth',
134 | }
135 | ]
136 | ```
137 |
138 | 2. 在 `package.json` 中添加生成脚本:
139 |
140 | ```json
141 | {
142 | "scripts": {
143 | "openapi2ts": "openapi2ts"
144 | }
145 | }
146 | ```
147 |
148 | 3. 生成 API 代码:
149 |
150 | ```bash
151 | npm run openapi2ts
152 | ```
153 |
154 | ### 配置选项
155 |
156 | | 属性 | 必填 | 说明 | 类型 | 默认值 |
157 | |------|------|------|------|--------|
158 | | requestLibPath | 否 | 自定义请求方法路径 | string | - |
159 | | requestOptionsType | 否 | 自定义请求方法 options 参数类型 | string | {[key: string]: any} |
160 | | requestImportStatement | 否 | 自定义请求方法表达式 | string | - |
161 | | apiPrefix | 否 | API 前缀 | string | - |
162 | | serversPath | 否 | 生成文件夹的路径 | string | - |
163 | | schemaPath | 否 | Swagger 2.0 或 OpenAPI 3.0 的地址 | string | - |
164 | | projectName | 否 | 项目名称 | string | - |
165 | | authorization | 否 | 文档登录凭证 | string | - |
166 | | namespace | 否 | 命名空间名称 | string | API |
167 | | mockFolder | 否 | mock 目录 | string | - |
168 | | enumStyle | 否 | 枚举样式 | string-literal \| enum | string-literal |
169 | | nullable | 否 | 使用 null 代替可选 | boolean | false |
170 | | dataFields | 否 | response 中数据字段 | string[] | - |
171 | | isCamelCase | 否 | 小驼峰命名文件和请求函数 | boolean | true |
172 | | declareType | 否 | interface 声明类型 | type/interface | type |
173 |
174 | ### 自定义钩子
175 |
176 | | 属性 | 类型 | 说明 |
177 | |------|------|------|
178 | | afterOpenApiDataInited | (openAPIData: OpenAPIObject) => OpenAPIObject | OpenAPI 数据初始化后的钩子 |
179 | | customFunctionName | (data: APIDataType) => string | 自定义请求方法函数名称 |
180 | | customTypeName | (data: APIDataType) => string | 自定义类型名称 |
181 | | customClassName | (tagName: string) => string | 自定义类名 |
182 | | customType | (schemaObject, namespace, originGetType) => string | 自定义获取类型 |
183 | | customFileNames | (operationObject, apiPath, _apiMethod) => string[] | 自定义生成文件名 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | openapi:
5 | build: .
6 | volumes:
7 | - .:/code
8 | stdin_open: true
9 | tty: true
10 |
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@umijs/openapi",
3 | "version": "1.13.15",
4 | "description": "",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+git@github.com:chenshuai2144/openapi2typescript.git"
8 | },
9 | "license": "MIT",
10 | "author": "chenshuai2144/kobe",
11 | "main": "dist/index.js",
12 | "bin": {
13 | "openapi2ts": "dist/cli.js"
14 | },
15 | "files": [
16 | "dist",
17 | "templates"
18 | ],
19 | "scripts": {
20 | "build": "tsc",
21 | "localConvert4Project": "rm -rf ./test/servers/ ./test/file-servers/ && npm run build && cd ./test && node ./test.js && cd .. && rm -rf /Users/fd/wj/psp-web-pro/src/services/wj && mv ./test/servers/api/ /Users/fd/wj/psp-web-pro/src/services/wj",
22 | "prepublishOnly": "npm run build && np --no-cleanup --yolo --no-publish --any-branch",
23 | "start": "tsc -w",
24 | "test": "rm -rf ./test/servers/ ./test/servers-allof/ ./test/file-servers/ && npm run build && cd ./test && node ./test.js && cd ..",
25 | "test:windows": "rimraf ./test/servers/ ./test/servers-allof/ ./test/file-servers/ && npm run build && cd ./test && ts-node ./test.js --project tsconfig.json && cd .."
26 | },
27 | "dependencies": {
28 | "chalk": "^4.1.2",
29 | "cosmiconfig": "^9.0.0",
30 | "dayjs": "^1.10.3",
31 | "glob": "^7.1.6",
32 | "lodash": "^4.17.21",
33 | "memoizee": "^0.4.15",
34 | "mock.js": "^0.2.0",
35 | "mockjs": "^1.1.0",
36 | "node-fetch": "^2.6.1",
37 | "number-to-words": "^1.2.4",
38 | "nunjucks": "^3.2.2",
39 | "openapi3-ts": "^2.0.1",
40 | "prettier": "^2.2.1",
41 | "reserved-words": "^0.1.2",
42 | "rimraf": "^3.0.2",
43 | "swagger2openapi": "^7.0.4",
44 | "tiny-pinyin": "^1.3.2"
45 | },
46 | "devDependencies": {
47 | "@types/express": "^4.17.11",
48 | "@types/node": "^14.14.22",
49 | "@types/node-fetch": "^2.6.12",
50 | "@types/number-to-words": "^1.2.3",
51 | "@types/swagger2openapi": "^7.0.4",
52 | "np": "^7.2.0",
53 | "ts-node": "^10.9.2",
54 | "tslib": "^2.6.0",
55 | "typescript": "^4.1.3"
56 | },
57 | "packageManager": "pnpm@9.13.2+sha512.88c9c3864450350e65a33587ab801acf946d7c814ed1134da4a924f6df5a2120fd36b46aab68f7cd1d413149112d53c7db3a4136624cfd00ff1846a0c6cef48a"
58 | }
59 |
--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import chalk from 'chalk';
4 | import { cosmiconfigSync } from 'cosmiconfig';
5 | import { generateService, GenerateServiceProps } from './index';
6 |
7 | const explorerSync = cosmiconfigSync('openapi2ts');
8 | const searchedFor = explorerSync.search();
9 |
10 | async function run() {
11 | try {
12 | if (searchedFor?.config) {
13 | const configs: GenerateServiceProps[] = Array.isArray(searchedFor.config)
14 | ? searchedFor.config
15 | : [searchedFor.config];
16 |
17 | for (const config of configs) {
18 | await generateService(config);
19 | }
20 | } else {
21 | throw new Error('config is not found');
22 | }
23 | } catch (error) {
24 | console.log(chalk.red(error));
25 | }
26 | }
27 |
28 | run();
29 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable global-require */
2 | /* eslint-disable import/no-dynamic-require */
3 | import http from 'http';
4 | import https from 'https';
5 | import fetch from 'node-fetch';
6 | import type { OpenAPIObject, OperationObject, SchemaObject } from 'openapi3-ts';
7 | import converter from 'swagger2openapi';
8 | import Log from './log';
9 | import { mockGenerator } from './mockGenerator';
10 | import { ServiceGenerator } from './serviceGenerator';
11 | import type { APIDataType } from './serviceGenerator';
12 |
13 | const getImportStatement = (requestLibPath: string) => {
14 | if (requestLibPath && requestLibPath.startsWith('import')) {
15 | return requestLibPath;
16 | }
17 | if (requestLibPath) {
18 | return `import request from '${requestLibPath}'`;
19 | }
20 | return `import { request } from "umi"`;
21 | };
22 |
23 | export type GenerateServiceProps = {
24 | requestLibPath?: string;
25 | requestOptionsType?: string;
26 | requestImportStatement?: string;
27 | // interface 类型声明方式, 满足某些团队的开发规范
28 | declareType?: 'type' | 'interface';
29 | /**
30 | * api 的前缀
31 | */
32 | apiPrefix?:
33 | | string
34 | | ((params: {
35 | path: string;
36 | method: string;
37 | namespace: string;
38 | functionName: string;
39 | autoExclude?: boolean;
40 | }) => string);
41 | /**
42 | * 生成的文件夹的路径
43 | */
44 | serversPath?: string;
45 | /**
46 | * Swagger 2.0 或 OpenAPI 3.0 的地址
47 | */
48 | schemaPath?: string;
49 | /**
50 | * 项目名称
51 | */
52 | projectName?: string;
53 | /**
54 | * 文档登录凭证
55 | */
56 | authorization?: string;
57 |
58 | hook?: {
59 | /** change open api data after constructor */
60 | afterOpenApiDataInited?: (openAPIData: OpenAPIObject) => OpenAPIObject;
61 |
62 | /** 自定义函数名称 */
63 | customFunctionName?: (data: APIDataType) => string;
64 | /** 自定义类型名称 */
65 | customTypeName?: (data: APIDataType) => string;
66 | /** 自定义 options 默认值 */
67 | customOptionsDefaultValue?: (data: OperationObject) => Record | undefined;
68 | /** 自定义类名 */
69 | customClassName?: (tagName: string) => string;
70 |
71 | /**
72 | * 自定义获取type hook
73 | * 返回非字符串将使用默认方法获取type
74 | * @example set number to string
75 | * function customType(schemaObject,namespace){
76 | * if(schemaObject.type==='number' && !schemaObject.format){
77 | * return 'BigDecimalString';
78 | * }
79 | * }
80 | */
81 | customType?: (
82 | schemaObject: SchemaObject | undefined,
83 | namespace: string,
84 | originGetType: (schemaObject: SchemaObject | undefined, namespace: string) => string,
85 | ) => string;
86 |
87 | /**
88 | * 自定义生成文件名,可返回多个,表示生成多个文件
89 | * 返回为空,则使用默认的获取方法获取
90 | * @example 使用operationId生成文件名
91 | * function customFileNames(operationObject,apiPath){
92 | * const operationId=operationObject.operationId;
93 | * if (!operationId) {
94 | * console.warn('[Warning] no operationId', apiPath);
95 | * return;
96 | * }
97 | * const res = operationId.split('_');
98 | * if (res.length > 1) {
99 | * res.shift();
100 | * if (res.length > 2) {
101 | * console.warn('[Warning] operationId has more than 2 part', apiPath);
102 | * }
103 | * return [res.join('_')];
104 | * } else {
105 | * const controllerName = (res || [])[0];
106 | * if (controllerName) {
107 | * return [controllerName];
108 | * }
109 | * return;
110 | * }
111 | * }
112 | */
113 | customFileNames?: (
114 | operationObject: OperationObject,
115 | apiPath: string,
116 | _apiMethod: string,
117 | ) => string[];
118 | };
119 | namespace?: string;
120 |
121 | /**
122 | * 默认为false,true时使用null代替可选
123 | */
124 | nullable?: boolean;
125 |
126 | mockFolder?: string;
127 | /**
128 | * 模板文件的文件路径
129 | */
130 | templatesFolder?: string;
131 |
132 | /**
133 | * 枚举样式
134 | */
135 | enumStyle?: 'string-literal' | 'enum';
136 |
137 | /**
138 | * response中数据字段
139 | * example: ['result', 'res']
140 | */
141 | dataFields?: string[];
142 |
143 | /**
144 | * 模板文件、请求函数采用小驼峰命名
145 | */
146 | isCamelCase?: boolean;
147 | /**
148 | * mock配置
149 | */
150 | mockConfig?: {
151 | /**
152 | * msw类型mock文件格式. 直接返回对象
153 | * 举例:
154 | * // @ts-ignore
155 |
156 | export default {
157 | 'DELETE /mydata/delete': { message: { message: 'Mydata successfully deleted' } },
158 | };
159 |
160 |
161 | 原文件:
162 | // @ts-ignore
163 | import { Request, Response } from 'express';
164 |
165 | export default {
166 | 'DELETE /mydata/delete': (req: Request, res: Response) => {
167 | res.status(200).send({ message: { message: 'Mydata successfully deleted' } });
168 | },
169 | };
170 | */
171 | msw?: boolean;
172 | };
173 | };
174 |
175 | const converterSwaggerToOpenApi = (swagger: any) => {
176 | if (!swagger.swagger) {
177 | return swagger;
178 | }
179 | return new Promise((resolve, reject) => {
180 | converter.convertObj(swagger, {}, (err, options) => {
181 | Log(['💺 将 Swagger 转化为 openAPI']);
182 | if (err) {
183 | reject(err);
184 | return;
185 | }
186 | resolve(options.openapi);
187 | });
188 | });
189 | };
190 |
191 | export const getSchema = async (schemaPath: string, authorization?: string) => {
192 | if (schemaPath.startsWith('http')) {
193 | const protocol = schemaPath.startsWith('https:') ? https : http;
194 | try {
195 | const agent = new protocol.Agent({
196 | rejectUnauthorized: false,
197 | });
198 | const headers = {
199 | authorization,
200 | };
201 | const json = await fetch(schemaPath, { agent, headers: authorization? headers: {} }).then((rest) => rest.json());
202 | return json;
203 | } catch (error) {
204 | // eslint-disable-next-line no-console
205 | console.log('fetch openapi error:', error);
206 | }
207 | return null;
208 | }
209 | if (require.cache[schemaPath]) {
210 | delete require.cache[schemaPath];
211 | }
212 | const schema = require(schemaPath);
213 | return schema;
214 | };
215 |
216 | const getOpenAPIConfig = async (schemaPath: string, authorization?: string) => {
217 | const schema = await getSchema(schemaPath, authorization);
218 | if (!schema) {
219 | return null;
220 | }
221 | const openAPI = await converterSwaggerToOpenApi(schema);
222 | return openAPI;
223 | };
224 |
225 | // 从 appName 生成 service 数据
226 | export const generateService = async ({
227 | authorization,
228 | requestLibPath,
229 | schemaPath,
230 | mockFolder,
231 | nullable = false,
232 | requestOptionsType = '{[key: string]: any}',
233 | ...rest
234 | }: GenerateServiceProps) => {
235 | const openAPI = await getOpenAPIConfig(schemaPath, authorization);
236 | const requestImportStatement = getImportStatement(requestLibPath);
237 | const serviceGenerator = new ServiceGenerator(
238 | {
239 | namespace: 'API',
240 | requestOptionsType,
241 | requestImportStatement,
242 | enumStyle: 'string-literal',
243 | nullable,
244 | isCamelCase: true,
245 | mockConfig: {},
246 | ...rest,
247 | },
248 | openAPI,
249 | );
250 | serviceGenerator.genFile();
251 |
252 | if (mockFolder) {
253 | await mockGenerator({
254 | openAPI,
255 | mockFolder: mockFolder || './mocks/',
256 | mockConfig: rest.mockConfig || {},
257 | });
258 | }
259 | };
260 |
--------------------------------------------------------------------------------
/src/log.ts:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | // eslint-disable-next-line no-console
4 | const Log = (...rest) => console.log(`${chalk.blue('[openAPI]')}: ${rest.join('\n')}`);
5 |
6 | export default Log;
7 |
--------------------------------------------------------------------------------
/src/mockGenerator.ts:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs';
2 | import fs from 'fs';
3 | import { prettierFile, writeFile } from './util';
4 | import { dirname, join } from 'path';
5 | import OpenAPIParserMock from './openAPIParserMock/index';
6 | import Log from './log';
7 | import pinyin from 'tiny-pinyin';
8 | import { GenerateServiceProps } from './index';
9 | Mock.Random.extend({
10 | country() {
11 | const data = [
12 | '阿根廷',
13 | '澳大利亚',
14 | '巴西',
15 | '加拿大',
16 | '中国',
17 | '法国',
18 | '德国',
19 | '印度',
20 | '印度尼西亚',
21 | '意大利',
22 | '日本',
23 | '韩国',
24 | '墨西哥',
25 | '俄罗斯',
26 | '沙特阿拉伯',
27 | '南非',
28 | '土耳其',
29 | '英国',
30 | '美国',
31 | ];
32 | const id = (Math.random() * data.length).toFixed();
33 | return data[id];
34 | },
35 | phone() {
36 | const phonepreFix = ['111', '112', '114']; // 自己写前缀哈
37 | return this.pick(phonepreFix) + Mock.mock(/\d{8}/); // Number()
38 | },
39 | status() {
40 | const status = ['success', 'error', 'default', 'processing', 'warning'];
41 | return status[(Math.random() * 4).toFixed(0)];
42 | },
43 | authority() {
44 | const status = ['admin', 'user', 'guest'];
45 | return status[(Math.random() * status.length).toFixed(0)];
46 | },
47 | avatar() {
48 | const avatar = [
49 | 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
50 | 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
51 | 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
52 | 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
53 | 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
54 | 'https://avatars0.githubusercontent.com/u/507615?s=40&v=4',
55 | 'https://avatars1.githubusercontent.com/u/8186664?s=40&v=4',
56 | ];
57 | const id = (Math.random() * avatar.length).toFixed();
58 | return avatar[id];
59 | },
60 | group() {
61 | const data = ['体验技术部', '创新科技组', '前端 6 组', '区块链平台部', '服务技术部'];
62 | const id = (Math.random() * data.length).toFixed();
63 | return data[id];
64 | },
65 | label() {
66 | const label = [
67 | '很有想法的',
68 | '小清新',
69 | '傻白甜',
70 | '阳光少年',
71 | '大咖',
72 | '健身达人',
73 | '程序员',
74 | '算法工程师',
75 | '川妹子',
76 | '名望程序员',
77 | '大长腿',
78 | '海纳百川',
79 | '专注设计',
80 | '爱好广泛',
81 | 'IT 互联网',
82 | ];
83 | const id = (Math.random() * label.length).toFixed();
84 | return label[id];
85 | },
86 | href() {
87 | const href = [
88 | 'https://preview.pro.ant.design/dashboard/analysis',
89 | 'https://ant.design',
90 | 'https://procomponents.ant.design/',
91 | 'https://umijs.org/',
92 | 'https://github.com/umijs/dumi',
93 | ];
94 | const id = (Math.random() * href.length).toFixed();
95 | return href[id];
96 | },
97 | });
98 |
99 | const genMockData = (example: string) => {
100 | if (!example) {
101 | return {};
102 | }
103 |
104 | if (typeof example === 'string') {
105 | return Mock.mock(example);
106 | }
107 |
108 | if (Array.isArray(example)) {
109 | return Mock.mock(example);
110 | }
111 |
112 | return Object.keys(example)
113 | .map((name) => {
114 | return {
115 | [name]: Mock.mock(example[name]),
116 | };
117 | })
118 | .reduce((pre, next) => {
119 | return {
120 | ...pre,
121 | ...next,
122 | };
123 | }, {});
124 | };
125 |
126 | const genByTemp = ({
127 | method,
128 | path,
129 | parameters,
130 | status,
131 | data,
132 | mockConfig,
133 | }: {
134 | method: string;
135 | path: string;
136 | parameters: {
137 | name: string;
138 | in: string;
139 | description: string;
140 | required: boolean;
141 | schema: { type: string };
142 | example: string;
143 | }[];
144 | status: string;
145 | data: string;
146 | mockConfig: GenerateServiceProps['mockConfig'];
147 | }) => {
148 | if (!['get', 'put', 'post', 'delete', 'patch'].includes(method.toLocaleLowerCase())) {
149 | return '';
150 | }
151 |
152 | let securityPath = path;
153 | parameters?.forEach((item) => {
154 | if (item.in === 'path') {
155 | securityPath = securityPath.replace(`{${item.name}}`, `:${item.name}`);
156 | }
157 | });
158 |
159 | if (mockConfig.msw) {
160 | return `'${method.toUpperCase()} ${securityPath}': ${data}`;
161 | }
162 |
163 | return `'${method.toUpperCase()} ${securityPath}': (req: Request, res: Response) => {
164 | res.status(${status}).send(${data});
165 | }`;
166 | };
167 |
168 | const genMockFiles = (mockFunction: string[], mockConfig: GenerateServiceProps['mockConfig']) => {
169 | return prettierFile(`
170 | // @ts-ignore
171 | ${mockConfig.msw ? '' : "import { Request, Response } from 'express'"}
172 |
173 |
174 | export default {
175 | ${mockFunction.join('\n,')}
176 | }`)[0];
177 | };
178 | export type genMockDataServerConfig = {
179 | openAPI: any;
180 | mockFolder: string;
181 | mockConfig: GenerateServiceProps['mockConfig'];
182 | };
183 |
184 | const mockGenerator = async ({ openAPI, mockFolder, mockConfig }: genMockDataServerConfig) => {
185 | const openAPParse = new OpenAPIParserMock(openAPI);
186 | const docs = openAPParse.parser();
187 | const pathList = Object.keys(docs.paths);
188 | const { paths } = docs;
189 | const mockActionsObj = {};
190 | pathList.forEach((path) => {
191 | const pathConfig = paths[path];
192 | Object.keys(pathConfig).forEach((method) => {
193 | const methodConfig = pathConfig[method];
194 | if (methodConfig) {
195 | let conte = (
196 | methodConfig.operationId ||
197 | methodConfig?.tags?.join('/') ||
198 | path.replace('/', '').split('/')[1]
199 | )?.replace(/[^\w^\s^\u4e00-\u9fa5]/gi, '');
200 | if (/[\u3220-\uFA29]/.test(conte)) {
201 | conte = pinyin.convertToPinyin(conte, '', true);
202 | }
203 | if (!conte) {
204 | return;
205 | }
206 | const data = genMockData(methodConfig.responses?.['200']?.example);
207 | if (!mockActionsObj[conte]) {
208 | mockActionsObj[conte] = [];
209 | }
210 | const tempFile = genByTemp({
211 | method,
212 | path,
213 | parameters: methodConfig.parameters,
214 | status: '200',
215 | data: JSON.stringify(data),
216 | mockConfig,
217 | });
218 | if (tempFile) {
219 | mockActionsObj[conte].push(tempFile);
220 | }
221 | }
222 | });
223 | });
224 | Object.keys(mockActionsObj).forEach((file) => {
225 | if (!file || file === 'undefined') {
226 | return;
227 | }
228 | if (file.includes('/')) {
229 | const dirName = dirname(join(mockFolder, `${file}.ts`));
230 | if (!fs.existsSync(dirName)) {
231 | fs.mkdirSync(dirName);
232 | }
233 | }
234 | writeFile(mockFolder, `${file}.ts`, genMockFiles(mockActionsObj[file], mockConfig));
235 | });
236 | Log('✅ 生成 mock 文件成功');
237 | };
238 |
239 | export { mockGenerator };
240 |
--------------------------------------------------------------------------------
/src/openAPIParserMock/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-continue */
2 | /* eslint-disable guard-for-in */
3 | /* eslint-disable no-restricted-syntax */
4 | import memoizee from 'memoizee';
5 |
6 | import * as utils from './utils';
7 | import primitives from './primitives';
8 |
9 | const getDateByName = (name: string[] | string, parentsKey?: string[]) => {
10 | if (!name || name.length < 1) {
11 | return 'string';
12 | }
13 | if (Array.isArray(name)) {
14 | return getDateByName([...name].pop(), name);
15 | }
16 | if (['nickname', 'name'].includes(name)) {
17 | return 'cname';
18 | }
19 | if (['owner', 'firstName', 'lastName', 'username'].includes(name)) {
20 | return 'name';
21 | }
22 | if (['avatar'].includes(name)) {
23 | return 'avatar';
24 | }
25 |
26 | if (['group'].includes(name)) {
27 | return 'group';
28 | }
29 |
30 | if (name.toLocaleLowerCase().endsWith('id')) {
31 | return 'uuid';
32 | }
33 |
34 | if (
35 | name.toLocaleLowerCase().endsWith('type') ||
36 | name.toLocaleLowerCase().endsWith('key') ||
37 | ['key'].includes(name)
38 | ) {
39 | return 'id';
40 | }
41 |
42 | if (name.toLocaleLowerCase().endsWith('label') || ['label'].includes(name)) {
43 | const newParents = [...parentsKey];
44 | newParents.pop();
45 | const newType = getDateByName(newParents);
46 | if (newType !== 'string' && newType !== 'csentence') {
47 | return newType;
48 | }
49 |
50 | return 'label';
51 | }
52 |
53 | if (['email'].includes(name)) {
54 | return 'email';
55 | }
56 | if (['password'].includes(name)) {
57 | return 'string(16)';
58 | }
59 | if (['phone'].includes(name)) {
60 | return 'phone';
61 | }
62 | if (['province'].includes(name)) {
63 | return 'province';
64 | }
65 | if (['city'].includes(name)) {
66 | return 'city';
67 | }
68 | if (['addr', 'address'].includes(name)) {
69 | return 'county';
70 | }
71 |
72 | if (['country'].includes(name)) {
73 | return 'country';
74 | }
75 |
76 | if (
77 | ['url', 'imageUrl', 'href'].includes(name) ||
78 | name.toLocaleLowerCase().endsWith('url') ||
79 | name.toLocaleLowerCase().endsWith('urls') ||
80 | name.toLocaleLowerCase().endsWith('image') ||
81 | name.toLocaleLowerCase().endsWith('link')
82 | ) {
83 | return 'href';
84 | }
85 |
86 | if (name.toLocaleLowerCase().endsWith('errorcode')) {
87 | return 'errorCode';
88 | }
89 |
90 | if (
91 | ['type', 'status'].includes(name) ||
92 | name.toLocaleLowerCase().endsWith('status') ||
93 | name.toLocaleLowerCase().endsWith('type')
94 | ) {
95 | return 'status';
96 | }
97 |
98 | if (name.toLocaleLowerCase().endsWith('authority')) {
99 | return 'authority';
100 | }
101 |
102 | return 'csentence';
103 | };
104 |
105 | function primitive(schemaParams, propsName) {
106 | const schema = utils.objectify(schemaParams);
107 | const { type, format } = schema;
108 | const value = primitives[`${type}_${format || getDateByName(propsName)}`] || primitives[type];
109 |
110 | if (typeof schema.example === 'undefined') {
111 | return value || `Unknown Type: ${schema.type}`;
112 | }
113 | return schema.example;
114 | }
115 |
116 | class OpenAPIGeneratorMockJs {
117 | protected openAPI: any;
118 | constructor(openAPI) {
119 | this.openAPI = openAPI;
120 | this.sampleFromSchema = memoizee(this.sampleFromSchema);
121 | }
122 |
123 | sampleFromSchema = (schema: any, propsName?: string[], schemaSet: Set = new Set()) => {
124 | let schemaRef = schema?.$ref;
125 |
126 | if (schemaRef) {
127 | // 如果之前已经使用过该引用结构,直接返回null,不然会陷入无限递归的情况
128 | if (schemaSet.has(schemaRef)) {
129 | return null;
130 | } else {
131 | schemaSet.add(schemaRef);
132 | }
133 | }
134 |
135 | const localSchema = schemaRef
136 | ? utils.get(this.openAPI, schemaRef.replace('#/', '').split('/'))
137 | : utils.objectify(schema);
138 |
139 | let { type } = localSchema;
140 | const { properties, additionalProperties, items, anyOf, oneOf, allOf } = localSchema;
141 |
142 | if (allOf) {
143 | let obj = {};
144 | allOf.forEach((item) => {
145 | const newObj = this.sampleFromSchema(item, propsName, new Set(schemaSet));
146 | obj = {
147 | ...obj,
148 | ...newObj,
149 | };
150 | });
151 | return obj;
152 | }
153 |
154 | if (!type) {
155 | if (properties) {
156 | type = 'object';
157 | } else if (items) {
158 | type = 'array';
159 | } else if (anyOf || oneOf) {
160 | type = 'union';
161 | } else {
162 | return null;
163 | }
164 | }
165 |
166 | if (type === 'null') {
167 | return null;
168 | }
169 |
170 | if (type === 'object') {
171 | const props = utils.objectify(properties);
172 | const obj: Record = {};
173 | for (const name in props) {
174 | obj[name] = this.sampleFromSchema(
175 | props[name],
176 | [...(propsName || []), name],
177 | new Set(schemaSet),
178 | );
179 | }
180 |
181 | if (additionalProperties === true) {
182 | obj.additionalProp1 = {};
183 | return obj;
184 | }
185 | if (additionalProperties) {
186 | const additionalProps = utils.objectify(additionalProperties);
187 | const additionalPropVal = this.sampleFromSchema(
188 | additionalProps,
189 | propsName,
190 | new Set(schemaSet),
191 | );
192 |
193 | for (let i = 1; i < 4; i += 1) {
194 | obj[`additionalProp${i}`] = additionalPropVal;
195 | }
196 | }
197 | return obj;
198 | }
199 |
200 | if (type === 'array') {
201 | const item = this.sampleFromSchema(items, propsName, new Set(schemaSet));
202 | return new Array(parseInt((Math.random() * 20).toFixed(0), 10)).fill(item);
203 | }
204 |
205 | if (type === 'union') {
206 | const subschemas = anyOf || oneOf;
207 | const subschemas_length = (subschemas && subschemas.length) || 0;
208 | if (subschemas_length) {
209 | const index = utils.getRandomInt(0, subschemas_length);
210 | const obj = this.sampleFromSchema(subschemas[index], propsName, new Set(schemaSet));
211 | return obj;
212 | }
213 | }
214 |
215 | if (localSchema.enum) {
216 | if (localSchema.default) return localSchema.default;
217 | return utils.normalizeArray(localSchema.enum)[0];
218 | }
219 |
220 | if (type === 'file') {
221 | return null;
222 | }
223 | return primitive(localSchema, propsName);
224 | };
225 |
226 | parser = () => {
227 | const openAPI = {
228 | ...this.openAPI,
229 | };
230 | for (const path in openAPI.paths) {
231 | for (const method in openAPI.paths[path]) {
232 | const api = openAPI.paths[path][method];
233 | for (const code in api.responses) {
234 | const response = api.responses[code];
235 |
236 | const keys = Object.keys(response.content || {});
237 | if (keys.length) {
238 | let key: string;
239 |
240 | if (keys.includes('application/json')) {
241 | key = 'application/json';
242 | } else if (keys.includes('*/*')) {
243 | key = '*/*';
244 | } else {
245 | key = keys[0];
246 | }
247 |
248 | const schema = utils.inferSchema(response.content[key]);
249 |
250 | if (schema) {
251 | response.example = schema ? this.sampleFromSchema(schema) : null;
252 | }
253 | }
254 | }
255 | if (!api.parameters) continue;
256 | for (const parameter of api.parameters) {
257 | const schema = utils.inferSchema(parameter);
258 | parameter.example = schema ? this.sampleFromSchema(schema) : null;
259 | }
260 | }
261 | }
262 | return openAPI;
263 | };
264 | }
265 |
266 | export default OpenAPIGeneratorMockJs;
267 |
--------------------------------------------------------------------------------
/src/openAPIParserMock/primitives.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | string: '@string',
3 | string_email: '@email',
4 | string_phone: '@phone',
5 | string_username: '@cname',
6 | string_url: '@url',
7 | string_uuid: '@guid',
8 | string_id: '@increment',
9 | string_status: '@status',
10 | string_authority: '@authority',
11 | string_label: '@label',
12 | string_group: '@group',
13 | string_csentence: '@csentence',
14 | string_cname: '@cname',
15 | string_name: '@last',
16 | string_errorCode: '@increment',
17 | string_country: '@country',
18 | string_county: '@county(true)',
19 | string_province: '@province',
20 | string_city: '@city',
21 | string_avatar: '@avatar',
22 | string_href: '@href',
23 | 'string_string(16)': '@string(16)',
24 | 'string_date-time': '@datetime',
25 | string_date: '@date',
26 | number: '@integer(60, 100)',
27 | number_float: '@float(60, 100, 3, 5)',
28 | integer: '@integer(60, 100)',
29 | boolean: '@boolean',
30 | };
31 |
--------------------------------------------------------------------------------
/src/openAPIParserMock/utils.ts:
--------------------------------------------------------------------------------
1 | function isObject(obj) {
2 | return !!obj && typeof obj === 'object';
3 | }
4 |
5 | function objectify(thing) {
6 | if (!isObject(thing)) return {};
7 | return thing;
8 | }
9 |
10 | function get(entity: any, path: (string | number)[]) {
11 | let current = entity;
12 |
13 | for (let i = 0; i < path.length; i += 1) {
14 | if (current === null || current === undefined) {
15 | return undefined;
16 | }
17 |
18 | current = current[path[i]];
19 | }
20 |
21 | return current;
22 | }
23 |
24 | function normalizeArray(arr) {
25 | if (Array.isArray(arr)) return arr;
26 | return [arr];
27 | }
28 |
29 | function isFunc(thing) {
30 | return typeof thing === 'function';
31 | }
32 |
33 | function inferSchema(thing) {
34 | if (thing.schema) {
35 | return thing.schema;
36 | }
37 |
38 | if (thing.properties) {
39 | return {
40 | ...thing,
41 | type: 'object',
42 | };
43 | }
44 |
45 | return thing;
46 | }
47 |
48 | function getRandomInt(min, max) {
49 | const minCeiled = Math.ceil(min);
50 | const maxFloored = Math.floor(max);
51 | return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
52 | }
53 |
54 | export { isObject, get, objectify, isFunc, inferSchema, normalizeArray, getRandomInt };
55 |
--------------------------------------------------------------------------------
/src/util.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable guard-for-in */
2 | /* eslint-disable no-restricted-syntax */
3 | /* eslint-disable no-lonely-if */
4 | /* eslint-disable no-param-reassign */
5 | import path from 'path';
6 | import fs from 'fs';
7 | import { camelCase, upperFirst } from 'lodash';
8 |
9 | export const getAbsolutePath = (filePath: string) => {
10 | if (filePath && !path.isAbsolute(filePath)) {
11 | return path.join(process.cwd(), filePath);
12 | }
13 | return filePath;
14 | };
15 |
16 | export const mkdir = (dir: string) => {
17 | if (!fs.existsSync(dir)) {
18 | mkdir(path.dirname(dir));
19 | fs.mkdirSync(dir);
20 | }
21 | };
22 |
23 | export const prettierFile = (content: string): [string, boolean] => {
24 | let result = content;
25 | let hasError = false;
26 | try {
27 | const prettier = require('prettier');
28 |
29 | const prettierOptions = prettier.resolveConfig.sync(process.cwd());
30 | result = prettier.format(content, {
31 | parser: 'typescript',
32 | ...prettierOptions,
33 | });
34 | } catch (error) {
35 | hasError = true;
36 | }
37 | return [result, hasError];
38 | };
39 |
40 | export const writeFile = (folderPath: string, fileName: string, content: string) => {
41 | const filePath = path.join(folderPath, fileName);
42 | mkdir(path.dirname(filePath));
43 | const [prettierContent, hasError] = prettierFile(content);
44 | fs.writeFileSync(filePath, prettierContent, {
45 | encoding: 'utf8',
46 | });
47 | return hasError;
48 | };
49 |
50 | export const getTagName = (name: string) => {
51 | const result = name.split('.');
52 | // 数据源中的 tag 等同于全量的 op API 名,确定为 4-5 段,如上格式
53 | // 取中间的 1-2 字段作为 tag,作为 serviceController 创建目录的依据
54 | if (result.length === 4) {
55 | return result[2];
56 | }
57 | if (result.length === 5) {
58 | return result[2] + upperFirst(result[3]);
59 | }
60 | return name;
61 | };
62 |
63 | /**
64 | * 根据当前的数据源类型,对请求回来的 apiInfo 进行格式化
65 | * 如果是 op 数据源,对 tags 以及 path 中的 tags 进行处理
66 | * - before: 前缀(产品集.产品码) + 操作对象(必填)+ 子操作对象(可选)+ 动作(必填)
67 | * - after: 操作对象(必填)+ 子操作对象(可选) ==> 驼峰
68 | */
69 | export const formatApiInfo = (apiInfo: Record): any => {
70 | if (
71 | !(
72 | apiInfo &&
73 | apiInfo.schema.info &&
74 | apiInfo.schema.info.extensions &&
75 | apiInfo.schema.info.extensions['x-antTech-description']
76 | )
77 | ) {
78 | // 非 op 数据源,直接返回
79 | return apiInfo;
80 | }
81 |
82 | apiInfo.schema.tags = apiInfo.schema.tags.map((item: Record) => {
83 | return {
84 | ...item,
85 | name: getTagName(item.name),
86 | };
87 | });
88 |
89 | for (const child_path in apiInfo.schema.paths) {
90 | apiInfo.schema.paths[child_path].post.tags = apiInfo.schema.paths[
91 | child_path
92 | ].post.tags.map((tag: string) => getTagName(tag));
93 | }
94 |
95 | return apiInfo;
96 | };
97 |
98 | type serviceParam = {
99 | title: string;
100 | type: string;
101 | description: string;
102 | default: string;
103 | [key: string]: any;
104 | };
105 |
106 | type serviceParams = Record;
107 | /**
108 | * 一方化场景下,由于 onex 会对请求的响应做处理
109 | * 1. 将 Response & Request 中的参数字段会变更为小驼峰写法
110 | * onex 相关代码 : http://gitlab.alipay-inc.com/one-console/sdk/blob/master/src/request.ts#L110
111 | * 2. 另外要注意:
112 | * op 返回的数据,请求参数的类型格式 需要做额外的处理
113 | * - (name) key.n, (type) string ==> key: string []
114 | * - (name) key.m, (type) string ===> key: string []
115 | * - (name) key.key1 , (type) string ==> key: {key1:string}
116 | * - (name) key.n.key1 ,(type) string => key:{ key1 :string}[]
117 | * - (name) key.n.key1.m,(type) string ==> key:{key1: string[]}[]
118 | */
119 | export function formatParamsForYFH(
120 | params: serviceParams,
121 | paramsObject: serviceParams = {},
122 | ): serviceParams {
123 | Object.keys(params).forEach((name) => {
124 | const prop = params[name];
125 | let key = name;
126 | const nameList = name.split('.');
127 | const nameListLength = nameList.length;
128 |
129 | if (nameListLength === 1) {
130 | // 正常的 key
131 | paramsObject[key] = { ...prop };
132 | } else if (nameListLength === 2 && nameList[1] !== 'n' && nameList[1] !== 'm') {
133 | const [childKey] = nameList;
134 | // key.child_key
135 | const key_child_key = camelCase(nameList[1]);
136 | paramsObject[childKey] = combineParams(childKey, key_child_key, prop, paramsObject);
137 | } else {
138 | // key.n.child_key
139 | if (nameList[nameListLength - 2] === 'n' || nameList[nameListLength - 2] === 'm') {
140 | const child_key = camelCase(nameList.pop());
141 | nameList.pop();
142 | key = nameList.join('.');
143 | paramsObject[key] = combineParams(key, child_key, prop, paramsObject, '.n.key');
144 | } else {
145 | const child_key = camelCase(nameList.pop());
146 | key = nameList.join('.');
147 |
148 | // .key.n
149 | if (child_key === 'n' || child_key === 'm') {
150 | // .n.key.m
151 | if (nameList[nameList.length - 2] === 'n' || nameList[nameList.length - 2] === 'm') {
152 | const child_child_key = camelCase(nameList.pop());
153 | nameList.pop();
154 | key = nameList.join('.');
155 | paramsObject[key] = combineParams(key, child_child_key, prop, paramsObject, '.n.key.m');
156 | } else {
157 | prop.type = `${prop.type}[]`;
158 | paramsObject[key] = { ...prop };
159 | }
160 | } else {
161 | paramsObject[key] = combineParams(key, child_key, prop, paramsObject);
162 | }
163 | }
164 | }
165 |
166 | paramsObject[key].name = camelCase(key);
167 | });
168 |
169 | const hasInvoke = Object.keys(paramsObject).filter((param) => param.includes('.')).length > 0;
170 |
171 | if (hasInvoke) {
172 | // 递归
173 | return formatParamsForYFH(paramsObject);
174 | }
175 | return paramsObject;
176 | }
177 |
178 | function combineParams(
179 | key: string,
180 | child_key: string,
181 | prop: serviceParam,
182 | paramsObject: serviceParams,
183 | type?: string,
184 | ): serviceParam {
185 | const typeSuffix = type === '.n.key.m' ? '[]' : '';
186 | const keySuffix = type === '.n.key' || type === '.n.key.m' ? '[]' : '';
187 | if (paramsObject[key]) {
188 | const child_type = `{${child_key}:${prop.type}${typeSuffix}, ${paramsObject[key].type.slice(
189 | 1,
190 | )}`;
191 | paramsObject[key] = {
192 | ...paramsObject[key],
193 | type: child_type,
194 | };
195 | } else {
196 | paramsObject[key] = {
197 | ...prop,
198 | type: `{${child_key}:${prop.type}
199 | }${keySuffix}`,
200 | };
201 | }
202 |
203 | return paramsObject[key];
204 | }
205 |
206 | export const stripDot = (str: string) => {
207 | return str.replace(/[-_ .](\w)/g, (_all, letter) => letter.toUpperCase());
208 | };
209 |
--------------------------------------------------------------------------------
/swagger.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
5 | "version": "1.0.0",
6 | "title": "Swagger Petstore",
7 | "termsOfService": "http://swagger.io/terms/",
8 | "contact": {
9 | "email": "apiteam@swagger.io"
10 | },
11 | "license": {
12 | "name": "Apache 2.0",
13 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
14 | }
15 | },
16 | "host": "petstore.swagger.io",
17 | "basePath": "/v2",
18 | "tags": [
19 | {
20 | "name": "pet",
21 | "description": "Everything about your Pets",
22 | "externalDocs": {
23 | "description": "Find out more",
24 | "url": "http://swagger.io"
25 | }
26 | },
27 | {
28 | "name": "store",
29 | "description": "Access to Petstore orders"
30 | },
31 | {
32 | "name": "user",
33 | "description": "Operations about user",
34 | "externalDocs": {
35 | "description": "Find out more about our store",
36 | "url": "http://swagger.io"
37 | }
38 | }
39 | ],
40 | "schemes": ["https", "http"],
41 | "paths": {
42 | "/pet": {
43 | "post": {
44 | "tags": ["pet"],
45 | "summary": "Add a new pet to the store",
46 | "description": "",
47 | "operationId": "addPet",
48 | "consumes": ["application/json", "application/xml"],
49 | "produces": ["application/xml", "application/json"],
50 | "parameters": [
51 | {
52 | "in": "body",
53 | "name": "body",
54 | "description": "Pet object that needs to be added to the store",
55 | "required": true,
56 | "schema": {
57 | "$ref": "#/definitions/Pet"
58 | }
59 | }
60 | ],
61 | "responses": {
62 | "405": {
63 | "description": "Invalid input"
64 | }
65 | },
66 | "security": [
67 | {
68 | "petstore_auth": ["write:pets", "read:pets"]
69 | }
70 | ]
71 | },
72 | "put": {
73 | "tags": ["pet"],
74 | "summary": "Update an existing pet",
75 | "description": "",
76 | "operationId": "updatePet",
77 | "consumes": ["application/json", "application/xml"],
78 | "produces": ["application/xml", "application/json"],
79 | "parameters": [
80 | {
81 | "in": "body",
82 | "name": "body",
83 | "description": "Pet object that needs to be added to the store",
84 | "required": true,
85 | "schema": {
86 | "$ref": "#/definitions/Pet"
87 | }
88 | }
89 | ],
90 | "responses": {
91 | "400": {
92 | "description": "Invalid ID supplied"
93 | },
94 | "404": {
95 | "description": "Pet not found"
96 | },
97 | "405": {
98 | "description": "Validation exception"
99 | }
100 | },
101 | "security": [
102 | {
103 | "petstore_auth": ["write:pets", "read:pets"]
104 | }
105 | ]
106 | }
107 | },
108 | "/pet/findByStatus": {
109 | "get": {
110 | "tags": ["pet"],
111 | "summary": "Finds Pets by status",
112 | "description": "Multiple status values can be provided with comma separated strings",
113 | "operationId": "findPetsByStatus",
114 | "produces": ["application/xml", "application/json"],
115 | "parameters": [
116 | {
117 | "name": "status",
118 | "in": "query",
119 | "description": "Status values that need to be considered for filter",
120 | "required": true,
121 | "type": "array",
122 | "items": {
123 | "type": "string",
124 | "enum": ["available", "pending", "sold"],
125 | "default": "available"
126 | },
127 | "collectionFormat": "multi"
128 | }
129 | ],
130 | "responses": {
131 | "200": {
132 | "description": "successful operation",
133 | "schema": {
134 | "type": "array",
135 | "items": {
136 | "$ref": "#/definitions/Pet"
137 | }
138 | }
139 | },
140 | "400": {
141 | "description": "Invalid status value"
142 | }
143 | },
144 | "security": [
145 | {
146 | "petstore_auth": ["write:pets", "read:pets"]
147 | }
148 | ]
149 | }
150 | },
151 | "/pet/findByTags": {
152 | "get": {
153 | "tags": ["pet"],
154 | "summary": "Finds Pets by tags",
155 | "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
156 | "operationId": "findPetsByTags",
157 | "produces": ["application/xml", "application/json"],
158 | "parameters": [
159 | {
160 | "name": "tags",
161 | "in": "query",
162 | "description": "Tags to filter by",
163 | "required": true,
164 | "type": "array",
165 | "items": {
166 | "type": "string"
167 | },
168 | "collectionFormat": "multi"
169 | }
170 | ],
171 | "responses": {
172 | "200": {
173 | "description": "successful operation",
174 | "schema": {
175 | "type": "array",
176 | "items": {
177 | "$ref": "#/definitions/Pet"
178 | }
179 | }
180 | },
181 | "400": {
182 | "description": "Invalid tag value"
183 | }
184 | },
185 | "security": [
186 | {
187 | "petstore_auth": ["write:pets", "read:pets"]
188 | }
189 | ],
190 | "deprecated": true
191 | }
192 | },
193 | "/pet/{petId}": {
194 | "get": {
195 | "tags": ["pet"],
196 | "summary": "Find pet by ID",
197 | "description": "Returns a single pet",
198 | "operationId": "getPetById",
199 | "produces": ["application/xml", "application/json"],
200 | "parameters": [
201 | {
202 | "name": "petId",
203 | "in": "path",
204 | "description": "ID of pet to return",
205 | "required": true,
206 | "type": "integer",
207 | "format": "int64"
208 | }
209 | ],
210 | "responses": {
211 | "200": {
212 | "description": "successful operation",
213 | "schema": {
214 | "$ref": "#/definitions/Pet"
215 | }
216 | },
217 | "400": {
218 | "description": "Invalid ID supplied"
219 | },
220 | "404": {
221 | "description": "Pet not found"
222 | }
223 | },
224 | "security": [
225 | {
226 | "api_key": []
227 | }
228 | ]
229 | },
230 | "post": {
231 | "tags": ["pet"],
232 | "summary": "Updates a pet in the store with form data",
233 | "description": "",
234 | "operationId": "updatePetWithForm",
235 | "consumes": ["application/x-www-form-urlencoded"],
236 | "produces": ["application/xml", "application/json"],
237 | "parameters": [
238 | {
239 | "name": "petId",
240 | "in": "path",
241 | "description": "ID of pet that needs to be updated",
242 | "required": true,
243 | "type": "integer",
244 | "format": "int64"
245 | },
246 | {
247 | "name": "name",
248 | "in": "formData",
249 | "description": "Updated name of the pet",
250 | "required": false,
251 | "type": "string"
252 | },
253 | {
254 | "name": "status",
255 | "in": "formData",
256 | "description": "Updated status of the pet",
257 | "required": false,
258 | "type": "string"
259 | }
260 | ],
261 | "responses": {
262 | "405": {
263 | "description": "Invalid input"
264 | }
265 | },
266 | "security": [
267 | {
268 | "petstore_auth": ["write:pets", "read:pets"]
269 | }
270 | ]
271 | },
272 | "delete": {
273 | "tags": ["pet"],
274 | "summary": "Deletes a pet",
275 | "description": "",
276 | "operationId": "deletePet",
277 | "produces": ["application/xml", "application/json"],
278 | "parameters": [
279 | {
280 | "name": "api_key",
281 | "in": "header",
282 | "required": false,
283 | "type": "string"
284 | },
285 | {
286 | "name": "petId",
287 | "in": "path",
288 | "description": "Pet id to delete",
289 | "required": true,
290 | "type": "integer",
291 | "format": "int64"
292 | }
293 | ],
294 | "responses": {
295 | "400": {
296 | "description": "Invalid ID supplied"
297 | },
298 | "404": {
299 | "description": "Pet not found"
300 | }
301 | },
302 | "security": [
303 | {
304 | "petstore_auth": ["write:pets", "read:pets"]
305 | }
306 | ]
307 | }
308 | },
309 | "/pet/{petId}/uploadImage": {
310 | "post": {
311 | "tags": ["pet"],
312 | "summary": "uploads an image",
313 | "description": "",
314 | "operationId": "uploadFile",
315 | "consumes": ["multipart/form-data"],
316 | "produces": ["application/json"],
317 | "parameters": [
318 | {
319 | "name": "petId",
320 | "in": "path",
321 | "description": "ID of pet to update",
322 | "required": true,
323 | "type": "integer",
324 | "format": "int64"
325 | },
326 | {
327 | "name": "additionalMetadata",
328 | "in": "formData",
329 | "description": "Additional data to pass to server",
330 | "required": false,
331 | "type": "string"
332 | },
333 | {
334 | "name": "file",
335 | "in": "formData",
336 | "description": "file to upload",
337 | "required": false,
338 | "type": "file"
339 | }
340 | ],
341 | "responses": {
342 | "200": {
343 | "description": "successful operation",
344 | "schema": {
345 | "$ref": "#/definitions/ApiResponse"
346 | }
347 | }
348 | },
349 | "security": [
350 | {
351 | "petstore_auth": ["write:pets", "read:pets"]
352 | }
353 | ]
354 | }
355 | },
356 | "/store/inventory": {
357 | "get": {
358 | "tags": ["store"],
359 | "summary": "Returns pet inventories by status",
360 | "description": "Returns a map of status codes to quantities",
361 | "operationId": "getInventory",
362 | "produces": ["application/json"],
363 | "parameters": [],
364 | "responses": {
365 | "200": {
366 | "description": "successful operation",
367 | "schema": {
368 | "type": "object",
369 | "additionalProperties": {
370 | "type": "integer",
371 | "format": "int32"
372 | }
373 | }
374 | }
375 | },
376 | "security": [
377 | {
378 | "api_key": []
379 | }
380 | ]
381 | }
382 | },
383 | "/store/order": {
384 | "post": {
385 | "tags": ["store"],
386 | "summary": "Place an order for a pet",
387 | "description": "",
388 | "operationId": "placeOrder",
389 | "produces": ["application/xml", "application/json"],
390 | "parameters": [
391 | {
392 | "in": "body",
393 | "name": "body",
394 | "description": "order placed for purchasing the pet",
395 | "required": true,
396 | "schema": {
397 | "$ref": "#/definitions/Order"
398 | }
399 | }
400 | ],
401 | "responses": {
402 | "200": {
403 | "description": "successful operation",
404 | "schema": {
405 | "$ref": "#/definitions/Order"
406 | }
407 | },
408 | "400": {
409 | "description": "Invalid Order"
410 | }
411 | }
412 | }
413 | },
414 | "/store/order/{orderId}": {
415 | "get": {
416 | "tags": ["store"],
417 | "summary": "Find purchase order by ID",
418 | "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
419 | "operationId": "getOrderById",
420 | "produces": ["application/xml", "application/json"],
421 | "parameters": [
422 | {
423 | "name": "orderId",
424 | "in": "path",
425 | "description": "ID of pet that needs to be fetched",
426 | "required": true,
427 | "type": "integer",
428 | "maximum": 10,
429 | "minimum": 1,
430 | "format": "int64"
431 | }
432 | ],
433 | "responses": {
434 | "200": {
435 | "description": "successful operation",
436 | "schema": {
437 | "$ref": "#/definitions/Order"
438 | }
439 | },
440 | "400": {
441 | "description": "Invalid ID supplied"
442 | },
443 | "404": {
444 | "description": "Order not found"
445 | }
446 | }
447 | },
448 | "delete": {
449 | "tags": ["store"],
450 | "summary": "Delete purchase order by ID",
451 | "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors",
452 | "operationId": "deleteOrder",
453 | "produces": ["application/xml", "application/json"],
454 | "parameters": [
455 | {
456 | "name": "orderId",
457 | "in": "path",
458 | "description": "ID of the order that needs to be deleted",
459 | "required": true,
460 | "type": "integer",
461 | "minimum": 1,
462 | "format": "int64"
463 | }
464 | ],
465 | "responses": {
466 | "400": {
467 | "description": "Invalid ID supplied"
468 | },
469 | "404": {
470 | "description": "Order not found"
471 | }
472 | }
473 | }
474 | },
475 | "/user": {
476 | "post": {
477 | "tags": ["user"],
478 | "summary": "Create user",
479 | "description": "This can only be done by the logged in user.",
480 | "operationId": "createUser",
481 | "produces": ["application/xml", "application/json"],
482 | "parameters": [
483 | {
484 | "in": "body",
485 | "name": "body",
486 | "description": "Created user object",
487 | "required": true,
488 | "schema": {
489 | "$ref": "#/definitions/User"
490 | }
491 | }
492 | ],
493 | "responses": {
494 | "default": {
495 | "description": "successful operation"
496 | }
497 | }
498 | }
499 | },
500 | "/user/createWithArray": {
501 | "post": {
502 | "tags": ["user"],
503 | "summary": "Creates list of users with given input array",
504 | "description": "",
505 | "operationId": "createUsersWithArrayInput",
506 | "produces": ["application/xml", "application/json"],
507 | "parameters": [
508 | {
509 | "in": "body",
510 | "name": "body",
511 | "description": "List of user object",
512 | "required": true,
513 | "schema": {
514 | "type": "array",
515 | "items": {
516 | "$ref": "#/definitions/User"
517 | }
518 | }
519 | }
520 | ],
521 | "responses": {
522 | "default": {
523 | "description": "successful operation"
524 | }
525 | }
526 | }
527 | },
528 | "/user/createWithList": {
529 | "post": {
530 | "tags": ["user"],
531 | "summary": "Creates list of users with given input array",
532 | "description": "",
533 | "operationId": "createUsersWithListInput",
534 | "produces": ["application/xml", "application/json"],
535 | "parameters": [
536 | {
537 | "in": "body",
538 | "name": "body",
539 | "description": "List of user object",
540 | "required": true,
541 | "schema": {
542 | "type": "array",
543 | "items": {
544 | "$ref": "#/definitions/User"
545 | }
546 | }
547 | }
548 | ],
549 | "responses": {
550 | "default": {
551 | "description": "successful operation"
552 | }
553 | }
554 | }
555 | },
556 | "/user/login": {
557 | "get": {
558 | "tags": ["user"],
559 | "summary": "Logs user into the system",
560 | "description": "",
561 | "operationId": "loginUser",
562 | "produces": ["application/xml", "application/json"],
563 | "parameters": [
564 | {
565 | "name": "username",
566 | "in": "query",
567 | "description": "The user name for login",
568 | "required": true,
569 | "type": "string"
570 | },
571 | {
572 | "name": "password",
573 | "in": "query",
574 | "description": "The password for login in clear text",
575 | "required": true,
576 | "type": "string"
577 | }
578 | ],
579 | "responses": {
580 | "200": {
581 | "description": "successful operation",
582 | "schema": {
583 | "type": "string"
584 | },
585 | "headers": {
586 | "X-Rate-Limit": {
587 | "type": "integer",
588 | "format": "int32",
589 | "description": "calls per hour allowed by the user"
590 | },
591 | "X-Expires-After": {
592 | "type": "string",
593 | "format": "date-time",
594 | "description": "date in UTC when token expires"
595 | }
596 | }
597 | },
598 | "400": {
599 | "description": "Invalid username/password supplied"
600 | }
601 | }
602 | }
603 | },
604 | "/user/logout": {
605 | "get": {
606 | "tags": ["user"],
607 | "summary": "Logs out current logged in user session",
608 | "description": "",
609 | "operationId": "logoutUser",
610 | "produces": ["application/xml", "application/json"],
611 | "parameters": [],
612 | "responses": {
613 | "default": {
614 | "description": "successful operation"
615 | }
616 | }
617 | }
618 | },
619 | "/user/{username}": {
620 | "get": {
621 | "tags": ["user"],
622 | "summary": "Get user by user name",
623 | "description": "",
624 | "operationId": "getUserByName",
625 | "produces": ["application/xml", "application/json"],
626 | "parameters": [
627 | {
628 | "name": "username",
629 | "in": "path",
630 | "description": "The name that needs to be fetched. Use user1 for testing. ",
631 | "required": true,
632 | "type": "string"
633 | }
634 | ],
635 | "responses": {
636 | "200": {
637 | "description": "successful operation",
638 | "schema": {
639 | "$ref": "#/definitions/User"
640 | }
641 | },
642 | "400": {
643 | "description": "Invalid username supplied"
644 | },
645 | "404": {
646 | "description": "User not found"
647 | }
648 | }
649 | },
650 | "put": {
651 | "tags": ["user"],
652 | "summary": "Updated user",
653 | "description": "This can only be done by the logged in user.",
654 | "operationId": "updateUser",
655 | "produces": ["application/xml", "application/json"],
656 | "parameters": [
657 | {
658 | "name": "username",
659 | "in": "path",
660 | "description": "name that need to be updated",
661 | "required": true,
662 | "type": "string"
663 | },
664 | {
665 | "in": "body",
666 | "name": "body",
667 | "description": "Updated user object",
668 | "required": true,
669 | "schema": {
670 | "$ref": "#/definitions/User"
671 | }
672 | }
673 | ],
674 | "responses": {
675 | "400": {
676 | "description": "Invalid user supplied"
677 | },
678 | "404": {
679 | "description": "User not found"
680 | }
681 | }
682 | },
683 | "delete": {
684 | "tags": ["user"],
685 | "summary": "Delete user",
686 | "description": "This can only be done by the logged in user.",
687 | "operationId": "deleteUser",
688 | "produces": ["application/xml", "application/json"],
689 | "parameters": [
690 | {
691 | "name": "username",
692 | "in": "path",
693 | "description": "The name that needs to be deleted",
694 | "required": true,
695 | "type": "string"
696 | }
697 | ],
698 | "responses": {
699 | "400": {
700 | "description": "Invalid username supplied"
701 | },
702 | "404": {
703 | "description": "User not found"
704 | }
705 | }
706 | }
707 | }
708 | },
709 | "securityDefinitions": {
710 | "petstore_auth": {
711 | "type": "oauth2",
712 | "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
713 | "flow": "implicit",
714 | "scopes": {
715 | "write:pets": "modify pets in your account",
716 | "read:pets": "read your pets"
717 | }
718 | },
719 | "api_key": {
720 | "type": "apiKey",
721 | "name": "api_key",
722 | "in": "header"
723 | }
724 | },
725 | "definitions": {
726 | "Order": {
727 | "type": "object",
728 | "properties": {
729 | "id": {
730 | "type": "integer",
731 | "format": "int64"
732 | },
733 | "petId": {
734 | "type": "integer",
735 | "format": "int64"
736 | },
737 | "quantity": {
738 | "type": "integer",
739 | "format": "int32"
740 | },
741 | "shipDate": {
742 | "type": "string",
743 | "format": "date-time"
744 | },
745 | "status": {
746 | "type": "string",
747 | "description": "Order Status",
748 | "enum": ["placed", "approved", "delivered"]
749 | },
750 | "complete": {
751 | "type": "boolean",
752 | "default": false
753 | }
754 | },
755 | "xml": {
756 | "name": "Order"
757 | }
758 | },
759 | "Category": {
760 | "type": "object",
761 | "properties": {
762 | "id": {
763 | "type": "integer",
764 | "format": "int64"
765 | },
766 | "name": {
767 | "type": "string"
768 | }
769 | },
770 | "xml": {
771 | "name": "Category"
772 | }
773 | },
774 | "User": {
775 | "type": "object",
776 | "properties": {
777 | "id": {
778 | "type": "integer",
779 | "format": "int64"
780 | },
781 | "username": {
782 | "type": "string"
783 | },
784 | "firstName": {
785 | "type": "string"
786 | },
787 | "lastName": {
788 | "type": "string"
789 | },
790 | "email": {
791 | "type": "string"
792 | },
793 | "password": {
794 | "type": "string"
795 | },
796 | "phone": {
797 | "type": "string"
798 | },
799 | "userStatus": {
800 | "type": "integer",
801 | "format": "int32",
802 | "description": "User Status"
803 | }
804 | },
805 | "xml": {
806 | "name": "User"
807 | }
808 | },
809 | "Tag": {
810 | "type": "object",
811 | "properties": {
812 | "id": {
813 | "type": "integer",
814 | "format": "int64"
815 | },
816 | "name": {
817 | "type": "string"
818 | }
819 | },
820 | "xml": {
821 | "name": "Tag"
822 | }
823 | },
824 | "Pet": {
825 | "type": "object",
826 | "required": ["name", "photoUrls"],
827 | "properties": {
828 | "id": {
829 | "type": "integer",
830 | "format": "int64"
831 | },
832 | "category": {
833 | "$ref": "#/definitions/Category"
834 | },
835 | "name": {
836 | "type": "string",
837 | "example": "doggie"
838 | },
839 | "photoUrls": {
840 | "type": "array",
841 | "xml": {
842 | "name": "photoUrl",
843 | "wrapped": true
844 | },
845 | "items": {
846 | "type": "string"
847 | }
848 | },
849 | "tags": {
850 | "type": "array",
851 | "xml": {
852 | "name": "tag",
853 | "wrapped": true
854 | },
855 | "items": {
856 | "$ref": "#/definitions/Tag"
857 | }
858 | },
859 | "status": {
860 | "type": "string",
861 | "description": "pet status in the store",
862 | "enum": ["available", "pending", "sold"]
863 | }
864 | },
865 | "xml": {
866 | "name": "Pet"
867 | }
868 | },
869 | "ApiResponse": {
870 | "type": "object",
871 | "properties": {
872 | "code": {
873 | "type": "integer",
874 | "format": "int32"
875 | },
876 | "type": {
877 | "type": "string"
878 | },
879 | "message": {
880 | "type": "string"
881 | }
882 | }
883 | }
884 | },
885 | "externalDocs": {
886 | "description": "Find out more about Swagger",
887 | "url": "http://swagger.io"
888 | }
889 | }
890 |
--------------------------------------------------------------------------------
/templates/interface.njk:
--------------------------------------------------------------------------------
1 | declare namespace {{ namespace }} {
2 | {% for type in list -%}
3 | {%- if type.props.length %}
4 | {%- if type.isEnum %}
5 | enum {{ type.typeName | safe }}
6 | {%- else %}
7 | {{ declareType }} {{ type.typeName | safe }} {{ equalSymbol }}
8 | {%- endif %}
9 | {%- for prop in type.props %}
10 | {%- if prop.length > 1 %}
11 | {
12 | {%- endif %}
13 | {%- if prop.length == 1 %}
14 | {%- if not prop[0].$ref or prop[0].name %}
15 | {
16 | {%- endif %}
17 | {%- endif %}
18 | {%- for p in prop %}
19 | {%- if p.desc %}
20 | /** {{ p.desc }} */
21 | {%- endif %}
22 | {%- if p["$ref"] and not p.name %}
23 | // {{ p.$ref }}
24 | {{ p.type | safe }}
25 | {%- else %}
26 | {%- if nullable %}
27 | '{{ p.name }}': {{ p.type | safe }}{{'' if p.required else '| null'}};
28 | {%- else %}
29 | '{{ p.name }}'{{ '' if p.required else '?' }}: {{ p.type | safe }};
30 | {%- endif %}
31 | {%- endif %}
32 | {%- endfor %}
33 | {%- if prop.length > 1 %}
34 | }
35 | {%- endif %}
36 | {%- if prop.length == 1 %}
37 | {%- if not prop[0].$ref or prop[0].name %}
38 | }
39 | {%- endif %}
40 | {%- endif %}
41 | {%- if prop.length == 0 %}
42 | {}
43 | {%- endif %}
44 | {{ '' if loop.last === true else ' & ' }}
45 | {%- endfor %}
46 | {%- else %}
47 | {%- if type.isEnum %}
48 | enum {{ type.typeName | safe }} {{ type.type }};
49 | {%- else %}
50 | type {{ type.typeName | safe }} = {{ type.type }};
51 | {%- endif %}
52 | {%- endif %}
53 | {% endfor %}
54 | }
55 |
--------------------------------------------------------------------------------
/templates/serviceController.njk:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | /* eslint-disable */
3 | {{ requestImportStatement }}
4 |
5 | {% for api in list -%}
6 | /** {{ api.desc if api.desc else '此处后端没有提供注释' }} {{api.method | upper}} {{ api.pathInComment | safe }} */
7 | export async function {{ api.functionName }}(
8 | {%- if api.params and api.hasParams %}
9 | // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
10 | params
11 | {%- if genType === "ts" -%}
12 | : {{namespace}}.{{api.typeName}}
13 | {# header 入参 -#}
14 | {% if api.params.header -%}
15 | & { // header
16 | {% for param in api.params.header -%}
17 | {% if param.description -%}
18 | /** {{ param.description }} */
19 | {% endif -%}
20 | '{{ param.name }}'
21 | {{- "?" if not param.required }}
22 | {{- (": " + param.type + ";") | safe }}
23 | {% endfor -%}
24 | }
25 | {%- endif -%}
26 | {%- endif -%}
27 | {%- if api.hasParams -%}
28 | {{ "," if api.body or api.file}}
29 | {%- endif -%}
30 | {%- endif -%}
31 | {%- if api.body -%}
32 | body
33 | {%- if genType === "ts" -%}
34 | : {% if api.body.propertiesList %}{
35 | {%- for prop in api.body.propertiesList %}
36 | {% if prop.schema.description -%}
37 | /** {{ prop.schema.description }} */
38 | {% endif -%}
39 | {{ prop.key }}{{ "?" if not prop.schema.required }}: {{ prop.schema.type }},
40 | {%- endfor %}
41 | }
42 | {%- else -%}
43 | {{ api.body.type }}
44 | {%- endif -%}
45 | {%- endif -%}
46 | {{ "," if api.file }}
47 | {%- endif %}
48 | {%- if api.file -%}
49 | {%- for file in api.file -%}
50 | {{file.title | safe}}
51 | {%- if genType === "ts" -%}
52 | {{- "?" if not api.file.required -}}
53 | : File {{ "[]" if file.multiple }}
54 | {%- endif -%}
55 | {{"," if not loop.last }}
56 | {%- endfor -%}
57 | {%- endif -%}
58 | {{ "," if api.body or api.hasParams or api.file }}
59 | options {{ ("?: " + requestOptionsType) if genType === "ts" }}
60 | ) {
61 | {% if api.params and api.params.path -%}
62 | const { {% for param in api.params.path %}'{{ param.name }}': {{ param.alias }}, {% endfor %}
63 | {% if api.params.path -%}
64 | ...queryParams
65 | {% endif -%}
66 | } = params;
67 | {% endif -%}
68 | {% if api.hasFormData -%}
69 | const formData = new FormData();
70 | {% if api.file -%}
71 | {% for file in api.file %}
72 | if({{file.title | safe}}){
73 | {% if file.multiple %}
74 | {{file.title | safe}}.forEach(f => formData.append('{{file.title | safe}}', f || ''));
75 | {% else %}
76 | formData.append('{{file.title | safe}}', {{file.title | safe}})
77 | {% endif %}
78 | }
79 | {% endfor %}
80 | {%- endif -%}
81 | {% if api.body %}
82 | Object.keys(body).forEach(ele => {
83 | {% if genType === "ts" %}
84 | const item = (body as any)[ele];
85 | {% else %}
86 | const item = body[ele];
87 | {% endif %}
88 | if (item !== undefined && item !== null) {
89 | {% if genType === "ts" %}
90 | if (typeof item === 'object' && !(item instanceof File)) {
91 | if (item instanceof Array) {
92 | item.forEach((f) => formData.append(ele, f || ''));
93 | } else {
94 | formData.append(ele, JSON.stringify(item));
95 | }
96 | } else {
97 | formData.append(ele, item);
98 | }
99 | {% else %}
100 | formData.append(ele, typeof item === 'object' ? JSON.stringify(item) : item);
101 | {% endif %}
102 | }
103 | });
104 | {% endif %}
105 | {% endif -%}
106 |
107 | {% if api.hasPathVariables or api.hasApiPrefix -%}
108 | return request{{ ("<" + api.response.type + ">") | safe if genType === "ts" }}(`{{ api.path | safe }}`, {
109 | {% else -%}
110 | return request{{ ("<" + api.response.type + ">") | safe if genType === "ts" }}('{{ api.path }}', {
111 | {% endif -%}
112 | method: '{{ api.method | upper }}',
113 | {%- if api.hasHeader and api.body.mediaType not in ["multipart/form-data"]%}
114 | headers: {
115 | {%- if api.body.mediaType %}
116 | 'Content-Type': '{{ api.body.mediaType | safe }}',
117 | {%- endif %}
118 | },
119 | {%- endif %}
120 | {%- if api.params and api.hasParams %}
121 | params: {
122 | {%- for query in api.params.query %}
123 | {% if query.schema.default -%}
124 | // {{query.name | safe}} has a default value: {{ query.schema.default | safe }}
125 | '{{query.name | safe}}': '{{query.schema.default | safe}}',
126 | {%- endif -%}
127 | {%- endfor -%}
128 | ...{{ 'queryParams' if api.params and api.params.path else 'params' }},
129 | {%- for query in api.params.query %}
130 | {%- if query.isComplexType %}
131 | '{{query.name | safe}}': undefined,
132 | ...{{ 'queryParams' if api.params and api.params.path else 'params' }}['{{query.name | safe}}'],
133 | {%- endif %}
134 | {%- endfor -%}
135 | },
136 | {%- endif %}
137 | {%- if api.hasFormData %}
138 | data: formData,
139 | {%- if api.body.mediaType === "multipart/form-data" %}
140 | requestType: 'form',
141 | {%- endif %}
142 | {%- else %}
143 | {%- if api.body %}
144 | data: body,
145 | {%- endif %}
146 | {%- endif %}
147 | ...(options || {{api.options | dump}}),
148 | });
149 | }
150 |
151 | {% endfor -%}
152 |
--------------------------------------------------------------------------------
/templates/serviceIndex.njk:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | /* eslint-disable */
3 | // API 更新时间:{{ apiResourceModifyTime }}
4 | // API 唯一标识:{{ apiResourceId }}
5 | {% for api in list -%}
6 | import * as {{ api.controllerName }} from './{{ api.fileName }}'
7 | {% endfor -%}
8 |
9 |
10 | export default {
11 | {% for api in list -%}
12 | {{ api.controllerName }},
13 | {% endfor -%}
14 | }
15 |
--------------------------------------------------------------------------------
/test/apispe/api/api0.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | /* eslint-disable */
3 | import { request } from 'umi';
4 |
5 | /** Run Template API POST /agent/runtemplate */
6 | export async function postAgentRuntemplate(options?: { [key: string]: any }) {
7 | return request<{ message?: any }>('/agent/runtemplate', {
8 | method: 'POST',
9 | ...(options || {}),
10 | });
11 | }
12 |
13 | /** Active Licence API POST /licence/active */
14 | export async function postLicenceActive(body: {}, file?: File, options?: { [key: string]: any }) {
15 | const formData = new FormData();
16 |
17 | if (file) {
18 | formData.append('file', file);
19 | }
20 |
21 | Object.keys(body).forEach((ele) => {
22 | const item = (body as any)[ele];
23 |
24 | if (item !== undefined && item !== null) {
25 | if (typeof item === 'object' && !(item instanceof File)) {
26 | if (item instanceof Array) {
27 | item.forEach((f) => formData.append(ele, f || ''));
28 | } else {
29 | formData.append(ele, JSON.stringify(item));
30 | }
31 | } else {
32 | formData.append(ele, item);
33 | }
34 | }
35 | });
36 |
37 | return request<{ message?: any }>('/licence/active', {
38 | method: 'POST',
39 | data: formData,
40 | requestType: 'form',
41 | ...(options || {}),
42 | });
43 | }
44 |
45 | /** Show Licence API GET /licence/info */
46 | export async function getLicenceInfo(options?: { [key: string]: any }) {
47 | return request<{ message?: any }>('/licence/info', {
48 | method: 'GET',
49 | ...(options || {}),
50 | });
51 | }
52 |
53 | /** Show machine code API GET /licence/machinecode */
54 | export async function getLicenceMachinecode(options?: { [key: string]: any }) {
55 | return request<{ message?: any }>('/licence/machinecode', {
56 | method: 'GET',
57 | ...(options || {}),
58 | });
59 | }
60 |
61 | /** Licence Test API GET /licence/test */
62 | export async function getLicenceTest(options?: { [key: string]: any }) {
63 | return request<{ message?: any }>('/licence/test', {
64 | method: 'GET',
65 | ...(options || {}),
66 | });
67 | }
68 |
69 | /** Create one Mydata for user (Folders,Files, & APIDataFeeds) POST /mydata/create */
70 | export async function postMydataCreate(
71 | body: {
72 | /** The type of data to create ('folder', 'file', 'api_data_feed'). */
73 | type: string;
74 | /** Name of the folder or API data feed. Required for 'folder' and 'api_data_feed'. */
75 | name?: string;
76 | /** Name of the folder to upload files into. Required for 'file'. */
77 | folder_name?: string;
78 | /** Permission setting for the folder. Defaults to 'private' if not specified. */
79 | permission?: string;
80 | /** Boolean flag to set the folder as searchable. */
81 | is_searchable?: boolean;
82 | /** API code for the API data feed. Required for 'api_data_feed'. */
83 | api_code?: string;
84 | },
85 | options?: { [key: string]: any },
86 | ) {
87 | return request<{ message?: any }>('/mydata/create', {
88 | method: 'POST',
89 | headers: {
90 | 'Content-Type': 'application/x-www-form-urlencoded',
91 | },
92 | data: body,
93 | ...(options || {}),
94 | });
95 | }
96 |
97 | /** Delete one Mydata for user (Folders,Files, & APIDataFeeds) DELETE /mydata/delete */
98 | export async function deleteMydataOpenApiDelete(options?: { [key: string]: any }) {
99 | return request<{ message?: any }>('/mydata/delete', {
100 | method: 'DELETE',
101 | ...(options || {}),
102 | });
103 | }
104 |
105 | /** List all mydata (Folders,Files, & APIDataFeeds) GET /mydata/list */
106 | export async function getMydataList(options?: { [key: string]: any }) {
107 | return request<{ message?: any }>('/mydata/list', {
108 | method: 'GET',
109 | ...(options || {}),
110 | });
111 | }
112 |
113 | /** Search one Mydata for its name or tags. GET /mydata/search */
114 | export async function getMydataSearch(
115 | // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
116 | params: API.getMydataSearchParams,
117 | options?: { [key: string]: any },
118 | ) {
119 | return request('/mydata/search', {
120 | method: 'GET',
121 | params: {
122 | ...params,
123 | },
124 | ...(options || {}),
125 | });
126 | }
127 |
128 | /** Update one Mydata for user (Folders,Files, & APIDataFeeds) GET /mydata/update */
129 | export async function getMydataUpdate(options?: { [key: string]: any }) {
130 | return request<{ message?: any }>('/mydata/update', {
131 | method: 'GET',
132 | ...(options || {}),
133 | });
134 | }
135 |
136 | /** Update one Mydata for user (Folders,Files, & APIDataFeeds) POST /mydata/update */
137 | export async function postMydataUpdate(options?: { [key: string]: any }) {
138 | return request<{ message?: any }>('/mydata/update', {
139 | method: 'POST',
140 | ...(options || {}),
141 | });
142 | }
143 |
--------------------------------------------------------------------------------
/test/apispe/api/index.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | /* eslint-disable */
3 | // API 更新时间:
4 | // API 唯一标识:
5 | import * as api0 from './api0';
6 | export default {
7 | api0,
8 | };
9 |
--------------------------------------------------------------------------------
/test/apispe/api/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare namespace API {}
2 |
--------------------------------------------------------------------------------
/test/example-files/apispec_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "definitions": {},
3 | "info": {
4 | "description": "API for InvRet",
5 | "title": "InvRet API",
6 | "version": "0.3.0"
7 | },
8 | "paths": {
9 | "/agent/runtemplate": {
10 | "post": {
11 | "responses": {
12 | "200": {
13 | "content": {
14 | "application/json": {
15 | "schema": {
16 | "properties": {
17 | "message": {
18 | "example": {
19 | "message": "Module successfully launched"
20 | },
21 | "type": "text"
22 | }
23 | },
24 | "type": "object"
25 | }
26 | }
27 | },
28 | "description": "Run Template"
29 | }
30 | },
31 | "summary": "Run Template API"
32 | }
33 | },
34 | "/licence/active": {
35 | "post": {
36 | "consumes": ["multipart/form-data"],
37 | "parameters": [
38 | {
39 | "description": "The file to upload",
40 | "in": "formData",
41 | "name": "file",
42 | "required": true,
43 | "type": "file"
44 | }
45 | ],
46 | "responses": {
47 | "200": {
48 | "content": {
49 | "application/json": {
50 | "schema": {
51 | "properties": {
52 | "message": {
53 | "example": {
54 | "Expired": "2024-05-15 12:45:32",
55 | "HasFeature1:": "True",
56 | "HasFeature2:": "True",
57 | "HasFeature3:": "False",
58 | "UserCount:": 10
59 | },
60 | "type": "text"
61 | }
62 | },
63 | "type": "object"
64 | }
65 | }
66 | },
67 | "description": "Active licence info"
68 | }
69 | },
70 | "summary": "Active Licence API"
71 | }
72 | },
73 | "/licence/info": {
74 | "get": {
75 | "responses": {
76 | "200": {
77 | "content": {
78 | "application/json": {
79 | "schema": {
80 | "properties": {
81 | "message": {
82 | "example": {
83 | "Expired": "2024-05-15 12:45:32",
84 | "HasFeature1:": "True",
85 | "HasFeature2:": "True",
86 | "HasFeature3:": "False",
87 | "UserCount:": 10
88 | },
89 | "type": "text"
90 | }
91 | },
92 | "type": "object"
93 | }
94 | }
95 | },
96 | "description": "Show Licence info"
97 | }
98 | },
99 | "summary": "Show Licence API"
100 | }
101 | },
102 | "/licence/machinecode": {
103 | "get": {
104 | "responses": {
105 | "200": {
106 | "content": {
107 | "application/json": {
108 | "schema": {
109 | "properties": {
110 | "message": {
111 | "example": {
112 | "MachineCode": "632d813473d18c3d2b1a9f9e07b19750394aab4090c63ad3609b2f1ba69bb656"
113 | },
114 | "type": "text"
115 | }
116 | },
117 | "type": "object"
118 | }
119 | }
120 | },
121 | "description": "Show machine code info"
122 | }
123 | },
124 | "summary": "Show machine code API"
125 | }
126 | },
127 | "/licence/test": {
128 | "get": {
129 | "responses": {
130 | "200": {
131 | "content": {
132 | "application/json": {
133 | "schema": {
134 | "properties": {
135 | "message": {
136 | "example": {
137 | "message": "ok!"
138 | },
139 | "type": "text"
140 | }
141 | },
142 | "type": "object"
143 | }
144 | }
145 | },
146 | "description": "Test licence info"
147 | }
148 | },
149 | "summary": "Licence Test API"
150 | }
151 | },
152 | "/mydata/create": {
153 | "post": {
154 | "parameters": [
155 | {
156 | "description": "The type of data to create ('folder', 'file', 'api_data_feed').",
157 | "in": "formData",
158 | "name": "type",
159 | "required": true,
160 | "type": "string"
161 | },
162 | {
163 | "description": "Name of the folder or API data feed. Required for 'folder' and 'api_data_feed'.",
164 | "in": "formData",
165 | "name": "name",
166 | "required": false,
167 | "type": "string"
168 | },
169 | {
170 | "description": "File or files to upload. Required for 'file' type.",
171 | "in": "formData",
172 | "name": "file",
173 | "required": false,
174 | "type": "file"
175 | },
176 | {
177 | "description": "Name of the folder to upload files into. Required for 'file'.",
178 | "in": "formData",
179 | "name": "folder_name",
180 | "required": false,
181 | "type": "string"
182 | },
183 | {
184 | "description": "Permission setting for the folder. Defaults to 'private' if not specified.",
185 | "in": "formData",
186 | "name": "permission",
187 | "required": false,
188 | "type": "string"
189 | },
190 | {
191 | "description": "Boolean flag to set the folder as searchable.",
192 | "in": "formData",
193 | "name": "is_searchable",
194 | "required": false,
195 | "type": "boolean"
196 | },
197 | {
198 | "description": "API code for the API data feed. Required for 'api_data_feed'.",
199 | "in": "formData",
200 | "name": "api_code",
201 | "required": false,
202 | "type": "string"
203 | }
204 | ],
205 | "responses": {
206 | "200": {
207 | "content": {
208 | "application/json": {
209 | "schema": {
210 | "properties": {
211 | "message": {
212 | "example": {
213 | "message": "Mydata successfully created"
214 | },
215 | "type": "text"
216 | }
217 | },
218 | "type": "object"
219 | }
220 | }
221 | },
222 | "description": "Create Mydata"
223 | }
224 | },
225 | "summary": "Create one Mydata for user (Folders,Files, & APIDataFeeds)"
226 | }
227 | },
228 | "/mydata/delete": {
229 | "delete": {
230 | "responses": {
231 | "200": {
232 | "content": {
233 | "application/json": {
234 | "schema": {
235 | "properties": {
236 | "message": {
237 | "example": {
238 | "message": "Mydata successfully deleted"
239 | },
240 | "type": "text"
241 | }
242 | },
243 | "type": "object"
244 | }
245 | }
246 | },
247 | "description": "Delete Mydata"
248 | }
249 | },
250 | "summary": "Delete one Mydata for user (Folders,Files, & APIDataFeeds)"
251 | }
252 | },
253 | "/mydata/list": {
254 | "get": {
255 | "responses": {
256 | "200": {
257 | "content": {
258 | "application/json": {
259 | "schema": {
260 | "properties": {
261 | "message": {
262 | "example": {
263 | "message": "Module successfully launched"
264 | },
265 | "type": "text"
266 | }
267 | },
268 | "type": "object"
269 | }
270 | }
271 | },
272 | "description": "List Mydata"
273 | }
274 | },
275 | "summary": "List all mydata (Folders,Files, & APIDataFeeds)"
276 | }
277 | },
278 | "/mydata/search": {
279 | "get": {
280 | "parameters": [
281 | {
282 | "description": "The search keyword to look for in MyData names or tags.",
283 | "in": "query",
284 | "name": "query",
285 | "required": true,
286 | "type": "string"
287 | },
288 | {
289 | "description": "Type for the keyword. 'folder' or 'file'",
290 | "in": "query",
291 | "name": "type",
292 | "required": true,
293 | "type": "string"
294 | }
295 | ],
296 | "responses": {
297 | "200": {
298 | "description": "An array of MyData entries that match the search criteria.",
299 | "items": {
300 | "id": {
301 | "example": 1,
302 | "format": "int64",
303 | "type": "integer"
304 | },
305 | "name": {
306 | "example": "Sample Data",
307 | "type": "string"
308 | },
309 | "properties": null,
310 | "tags": {
311 | "example": "example tag",
312 | "items": null,
313 | "type": "string"
314 | },
315 | "type": "object"
316 | },
317 | "schema": null,
318 | "type": "array"
319 | }
320 | },
321 | "summary": "Search one Mydata for its name or tags."
322 | }
323 | },
324 | "/mydata/update": {
325 | "get": {
326 | "responses": {
327 | "200": {
328 | "content": {
329 | "application/json": {
330 | "schema": {
331 | "properties": {
332 | "message": {
333 | "example": {
334 | "message": "Mydata successfully updated"
335 | },
336 | "type": "text"
337 | }
338 | },
339 | "type": "object"
340 | }
341 | }
342 | },
343 | "description": "Update Mydata"
344 | }
345 | },
346 | "summary": "Update one Mydata for user (Folders,Files, & APIDataFeeds)"
347 | },
348 | "post": {
349 | "responses": {
350 | "200": {
351 | "content": {
352 | "application/json": {
353 | "schema": {
354 | "properties": {
355 | "message": {
356 | "example": {
357 | "message": "Mydata successfully updated"
358 | },
359 | "type": "text"
360 | }
361 | },
362 | "type": "object"
363 | }
364 | }
365 | },
366 | "description": "Update Mydata"
367 | }
368 | },
369 | "summary": "Update one Mydata for user (Folders,Files, & APIDataFeeds)"
370 | }
371 | }
372 | },
373 | "swagger": "2.0"
374 | }
375 |
--------------------------------------------------------------------------------
/test/example-files/swagger-custom-hook.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.3",
3 | "info": {
4 | "version": "1.0.20210224155647",
5 | "description": "custom-hook-swagger",
6 | "title": "custom-hook-test"
7 | },
8 | "servers": [
9 | {
10 | "url": "http://127.0.0.1:9421",
11 | "description": "Inferred Url"
12 | }
13 | ],
14 | "tags": [
15 | {
16 | "name": "帐号 租户帐号 UserAccount"
17 | },
18 | {
19 | "name": "帐号 验证码 Captcha"
20 | }
21 | ],
22 | "paths": {
23 | "/api/v1/captcha/img/check.json": {
24 | "post": {
25 | "tags": [
26 | "帐号 验证码 Captcha"
27 | ],
28 | "summary": "验证图片验证码是否正确",
29 | "operationId": "checkImgCaptchaUsingPOST",
30 | "requestBody": {
31 | "content": {
32 | "application/json": {
33 | "schema": {
34 | "$ref": "#/components/schemas/CheckImgCaptchaReq"
35 | }
36 | }
37 | }
38 | },
39 | "responses": {
40 | "200": {
41 | "description": "OK",
42 | "content": {
43 | "*/*": {
44 | "schema": {
45 | "$ref": "#/components/schemas/ApiRes«CaptchaTokenVO»"
46 | }
47 | }
48 | }
49 | },
50 | "201": {
51 | "description": "Created"
52 | },
53 | "401": {
54 | "description": "Unauthorized"
55 | },
56 | "403": {
57 | "description": "Forbidden"
58 | },
59 | "404": {
60 | "description": "Not Found"
61 | }
62 | }
63 | }
64 | },
65 | "/api/v1/captcha/img/get.json": {
66 | "post": {
67 | "tags": [
68 | "帐号 验证码 Captcha"
69 | ],
70 | "summary": "获取图片验证码",
71 | "operationId": "getImageCaptchaUsingPOST",
72 | "requestBody": {
73 | "content": {
74 | "application/json": {
75 | "schema": {
76 | "$ref": "#/components/schemas/ImgCaptchaReq"
77 | }
78 | }
79 | }
80 | },
81 | "responses": {
82 | "200": {
83 | "description": "OK",
84 | "content": {
85 | "*/*": {
86 | "schema": {
87 | "$ref": "#/components/schemas/ApiRes«ImgCaptchaDTO»"
88 | }
89 | }
90 | }
91 | },
92 | "201": {
93 | "description": "Created"
94 | },
95 | "401": {
96 | "description": "Unauthorized"
97 | },
98 | "403": {
99 | "description": "Forbidden"
100 | },
101 | "404": {
102 | "description": "Not Found"
103 | }
104 | }
105 | }
106 | },
107 | "/api/v1/user/account/login.json": {
108 | "post": {
109 | "tags": [
110 | "帐号 租户帐号 UserAccount"
111 | ],
112 | "summary": "登录 - 帐密登录",
113 | "description":"参数:account",
114 | "operationId": "accountLoginUsingPOST",
115 | "requestBody": {
116 | "content": {
117 | "application/json": {
118 | "schema": {
119 | "$ref": "#/components/schemas/AccountLoginReq"
120 | }
121 | }
122 | }
123 | },
124 | "responses": {
125 | "default":{
126 | "description":"true代表登录成功,否则为提示信息",
127 | "content":{"*/*":{"schema":{"type":"string"}}}
128 | },
129 | "200": {
130 | "description": "OK",
131 | "content": {
132 | "*/*": {
133 | "schema": {
134 | "$ref": "#/components/schemas/ApiRes«TokenDTO»"
135 | }
136 | }
137 | }
138 | },
139 | "201": {
140 | "description": "Created"
141 | },
142 | "401": {
143 | "description": "Unauthorized"
144 | },
145 | "403": {
146 | "description": "Forbidden"
147 | },
148 | "404": {
149 | "description": "Not Found"
150 | }
151 | }
152 | }
153 | },
154 | "/api/v1/user/account/loginIsNeedCaptcha.json": {
155 | "post": {
156 | "tags": [
157 | "帐号 租户帐号 UserAccount"
158 | ],
159 | "summary": "登录 - 帐密登录是否需验证码验证",
160 | "operationId": "loginIsNeedCaptchaUsingPOST",
161 | "requestBody": {
162 | "content": {
163 | "application/json": {
164 | "schema": {
165 | "$ref": "#/components/schemas/LoginIsNeedCaptchaReq"
166 | }
167 | }
168 | }
169 | },
170 | "responses": {
171 | "200": {
172 | "description": "OK",
173 | "content": {
174 | "*/*": {
175 | "schema": {
176 | "$ref": "#/components/schemas/ApiRes«boolean»"
177 | }
178 | }
179 | }
180 | },
181 | "201": {
182 | "description": "Created"
183 | },
184 | "401": {
185 | "description": "Unauthorized"
186 | },
187 | "403": {
188 | "description": "Forbidden"
189 | },
190 | "404": {
191 | "description": "Not Found"
192 | }
193 | }
194 | }
195 | },
196 | "/api/v1/user/account/register.json": {
197 | "post": {
198 | "tags": [
199 | "帐号 租户帐号 UserAccount"
200 | ],
201 | "summary": "注册 - 帐密方式",
202 | "description": "图片验证码验证方式二选一:ID + token || ID + 验证码",
203 | "operationId": "accountRegisterUsingPOST",
204 | "requestBody": {
205 | "content": {
206 | "application/json": {
207 | "schema": {
208 | "$ref": "#/components/schemas/AccountRegisterReq"
209 | }
210 | }
211 | }
212 | },
213 | "responses": {
214 | "200": {
215 | "description": "OK",
216 | "content": {
217 | "*/*": {
218 | "schema": {
219 | "$ref": "#/components/schemas/ApiRes«TokenDTO»"
220 | }
221 | }
222 | }
223 | },
224 | "201": {
225 | "description": "Created"
226 | },
227 | "401": {
228 | "description": "Unauthorized"
229 | },
230 | "403": {
231 | "description": "Forbidden"
232 | },
233 | "404": {
234 | "description": "Not Found"
235 | }
236 | }
237 | }
238 | },
239 | "/api/v1/user/edit/pwd.json": {
240 | "post": {
241 | "tags": [
242 | "帐号 租户帐号 UserAccount"
243 | ],
244 | "summary": "修改密码 - 原密码方式",
245 | "operationId": "editPasswordUsingPOST",
246 | "requestBody": {
247 | "content": {
248 | "application/json": {
249 | "schema": {
250 | "$ref": "#/components/schemas/EditPasswordReq"
251 | }
252 | }
253 | }
254 | },
255 | "responses": {
256 | "200": {
257 | "description": "OK",
258 | "content": {
259 | "*/*": {
260 | "schema": {
261 | "$ref": "#/components/schemas/ApiRes«TokenDTO»"
262 | }
263 | }
264 | }
265 | },
266 | "201": {
267 | "description": "Created"
268 | },
269 | "401": {
270 | "description": "Unauthorized"
271 | },
272 | "403": {
273 | "description": "Forbidden"
274 | },
275 | "404": {
276 | "description": "Not Found"
277 | }
278 | }
279 | }
280 | },
281 | "/api/v1/user/forgot/pwd/sms.json": {
282 | "post": {
283 | "tags": [
284 | "帐号 租户帐号 UserAccount"
285 | ],
286 | "summary": "忘记密码 - 手机号方式",
287 | "operationId": "forgotPasswordUsingPOST",
288 | "requestBody": {
289 | "content": {
290 | "application/json": {
291 | "schema": {
292 | "$ref": "#/components/schemas/ApiReq"
293 | }
294 | }
295 | }
296 | },
297 | "responses": {
298 | "200": {
299 | "description": "OK",
300 | "content": {
301 | "*/*": {
302 | "schema": {
303 | "$ref": "#/components/schemas/ApiRes«TokenDTO»"
304 | }
305 | }
306 | }
307 | },
308 | "201": {
309 | "description": "Created"
310 | },
311 | "401": {
312 | "description": "Unauthorized"
313 | },
314 | "403": {
315 | "description": "Forbidden"
316 | },
317 | "404": {
318 | "description": "Not Found"
319 | }
320 | }
321 | }
322 | }
323 | },
324 | "components": {
325 | "schemas": {
326 | "AccountLoginReq": {
327 | "title": "AccountLoginReq",
328 | "required": [
329 | "password",
330 | "username"
331 | ],
332 | "type": "object",
333 | "properties": {
334 | "captcha": {
335 | "type": "string",
336 | "description": "验证码"
337 | },
338 | "captchaId": {
339 | "type": "integer",
340 | "description": "验证码ID",
341 | "format": "int64"
342 | },
343 | "captchaToken": {
344 | "type": "string",
345 | "description": "验证令牌"
346 | },
347 | "password": {
348 | "type": "string",
349 | "description": "密码(客户端使用 “墙]・▽・)ノ 嗨,美女+密码” 的MD5值提交,32位小写)",
350 | "example": "123456"
351 | },
352 | "username": {
353 | "type": "string",
354 | "description": "用户名",
355 | "example": "fastdev"
356 | }
357 | }
358 | },
359 | "AccountRegisterReq": {
360 | "title": "AccountRegisterReq",
361 | "required": [
362 | "captchaId",
363 | "password",
364 | "username"
365 | ],
366 | "type": "object",
367 | "properties": {
368 | "captcha": {
369 | "type": "string",
370 | "description": "验证码"
371 | },
372 | "captchaId": {
373 | "type": "integer",
374 | "description": "验证码ID",
375 | "format": "int64"
376 | },
377 | "captchaToken": {
378 | "type": "string",
379 | "description": "验证令牌"
380 | },
381 | "password": {
382 | "type": "string",
383 | "description": "密码(输入的密码,需要检测密码是否合法)",
384 | "example": "123456"
385 | },
386 | "username": {
387 | "type": "string",
388 | "description": "用户名",
389 | "example": "fastdev"
390 | }
391 | }
392 | },
393 | "ApiReq": {
394 | "title": "ApiReq",
395 | "type": "object"
396 | },
397 | "ApiRes«CaptchaTokenVO»": {
398 | "title": "ApiRes«CaptchaTokenVO»",
399 | "required": [
400 | "code",
401 | "msg",
402 | "showType"
403 | ],
404 | "type": "object",
405 | "properties": {
406 | "code": {
407 | "type": "integer",
408 | "description": "状态码;大于零为处理成功的不同状态,小于零的状态则视为失败的情况",
409 | "format": "int32",
410 | "example": 200
411 | },
412 | "data": {
413 | "description": "相应数据",
414 | "$ref": "#/components/schemas/CaptchaTokenVO",
415 | "example": "{}"
416 | },
417 | "msg": {
418 | "type": "string",
419 | "description": "提示消息",
420 | "example": "请求成功"
421 | },
422 | "showType": {
423 | "type": "string",
424 | "description": "消息提示方式",
425 | "example": "0",
426 | "enum": [
427 | "DIALOG",
428 | "ERROR",
429 | "NOTIFICATION",
430 | "PAGE",
431 | "SLIENT",
432 | "SUCCESS",
433 | "UNUSED_6",
434 | "UNUSED_7",
435 | "UNUSED_8",
436 | "WARN"
437 | ]
438 | }
439 | }
440 | },
441 | "ApiRes«ImgCaptchaDTO»": {
442 | "title": "ApiRes«ImgCaptchaDTO»",
443 | "required": [
444 | "code",
445 | "msg",
446 | "showType"
447 | ],
448 | "type": "object",
449 | "properties": {
450 | "code": {
451 | "type": "integer",
452 | "description": "状态码;大于零为处理成功的不同状态,小于零的状态则视为失败的情况",
453 | "format": "int32",
454 | "example": 200
455 | },
456 | "data": {
457 | "description": "相应数据",
458 | "$ref": "#/components/schemas/ImgCaptchaDTO",
459 | "example": "{}"
460 | },
461 | "msg": {
462 | "type": "string",
463 | "description": "提示消息",
464 | "example": "请求成功"
465 | },
466 | "showType": {
467 | "type": "string",
468 | "description": "消息提示方式",
469 | "example": "0",
470 | "enum": [
471 | "DIALOG",
472 | "ERROR",
473 | "NOTIFICATION",
474 | "PAGE",
475 | "SLIENT",
476 | "SUCCESS",
477 | "UNUSED_6",
478 | "UNUSED_7",
479 | "UNUSED_8",
480 | "WARN"
481 | ]
482 | }
483 | }
484 | },
485 | "ApiRes«TokenDTO»": {
486 | "title": "ApiRes«TokenDTO»",
487 | "required": [
488 | "code",
489 | "msg",
490 | "showType"
491 | ],
492 | "type": "object",
493 | "properties": {
494 | "code": {
495 | "type": "integer",
496 | "description": "状态码;大于零为处理成功的不同状态,小于零的状态则视为失败的情况",
497 | "format": "int32",
498 | "example": 200
499 | },
500 | "data": {
501 | "description": "相应数据",
502 | "$ref": "#/components/schemas/TokenDTO",
503 | "example": "{}"
504 | },
505 | "msg": {
506 | "type": "string",
507 | "description": "提示消息",
508 | "example": "请求成功"
509 | },
510 | "showType": {
511 | "type": "string",
512 | "description": "消息提示方式",
513 | "example": "0",
514 | "enum": [
515 | "DIALOG",
516 | "ERROR",
517 | "NOTIFICATION",
518 | "PAGE",
519 | "SLIENT",
520 | "SUCCESS",
521 | "UNUSED_6",
522 | "UNUSED_7",
523 | "UNUSED_8",
524 | "WARN"
525 | ]
526 | }
527 | }
528 | },
529 | "ApiRes«boolean»": {
530 | "title": "ApiRes«boolean»",
531 | "required": [
532 | "code",
533 | "msg",
534 | "showType"
535 | ],
536 | "type": "object",
537 | "properties": {
538 | "code": {
539 | "type": "integer",
540 | "description": "状态码;大于零为处理成功的不同状态,小于零的状态则视为失败的情况",
541 | "format": "int32",
542 | "example": 200
543 | },
544 | "data": {
545 | "type": "boolean",
546 | "description": "相应数据",
547 | "example": false
548 | },
549 | "msg": {
550 | "type": "string",
551 | "description": "提示消息",
552 | "example": "请求成功"
553 | },
554 | "showType": {
555 | "type": "string",
556 | "description": "消息提示方式",
557 | "example": "0",
558 | "enum": [
559 | "DIALOG",
560 | "ERROR",
561 | "NOTIFICATION",
562 | "PAGE",
563 | "SLIENT",
564 | "SUCCESS",
565 | "UNUSED_6",
566 | "UNUSED_7",
567 | "UNUSED_8",
568 | "WARN"
569 | ]
570 | }
571 | }
572 | },
573 | "CaptchaTokenVO": {
574 | "title": "CaptchaTokenVO",
575 | "required": [
576 | "token"
577 | ],
578 | "type": "object",
579 | "properties": {
580 | "token": {
581 | "type": "string",
582 | "description": "验证令牌"
583 | }
584 | }
585 | },
586 | "CheckImgCaptchaReq": {
587 | "title": "CheckImgCaptchaReq",
588 | "required": [
589 | "captcha",
590 | "id",
591 | "type"
592 | ],
593 | "type": "object",
594 | "properties": {
595 | "captcha": {
596 | "type": "string",
597 | "description": "验证码"
598 | },
599 | "id": {
600 | "type": "integer",
601 | "description": "验证码ID",
602 | "format": "int64"
603 | },
604 | "type": {
605 | "type": "string",
606 | "description": "验证码类型,1->注册,2->登录,3->忘记密码,4->修改密码",
607 | "enum": [
608 | "EDIT_PASSWORD",
609 | "FORGOT_PASSWORD",
610 | "LOGIN",
611 | "REGISTER"
612 | ]
613 | }
614 | }
615 | },
616 | "EditPasswordReq": {
617 | "title": "EditPasswordReq",
618 | "required": [
619 | "newPassword",
620 | "password",
621 | "token",
622 | "uid"
623 | ],
624 | "type": "object",
625 | "properties": {
626 | "newPassword": {
627 | "type": "string",
628 | "description": "新密码"
629 | },
630 | "password": {
631 | "type": "string",
632 | "description": "当前的密码"
633 | },
634 | "token": {
635 | "type": "string",
636 | "description": "用户通行令牌"
637 | },
638 | "uid": {
639 | "type": "integer",
640 | "description": "用户ID",
641 | "format": "int64"
642 | }
643 | }
644 | },
645 | "ImgCaptchaDTO": {
646 | "title": "ImgCaptchaDTO",
647 | "required": [
648 | "id",
649 | "url"
650 | ],
651 | "type": "object",
652 | "properties": {
653 | "id": {
654 | "type": "integer",
655 | "description": "验证码ID",
656 | "format": "int64"
657 | },
658 | "url": {
659 | "type": "string",
660 | "description": "图片验证码URL"
661 | }
662 | }
663 | },
664 | "ImgCaptchaReq": {
665 | "title": "ImgCaptchaReq",
666 | "required": [
667 | "type"
668 | ],
669 | "type": "object",
670 | "properties": {
671 | "type": {
672 | "type": "string",
673 | "description": "验证码类型",
674 | "enum": [
675 | "EDIT_PASSWORD",
676 | "FORGOT_PASSWORD",
677 | "LOGIN",
678 | "REGISTER"
679 | ]
680 | }
681 | }
682 | },
683 | "LoginIsNeedCaptchaReq": {
684 | "title": "LoginIsNeedCaptchaReq",
685 | "required": [
686 | "username"
687 | ],
688 | "type": "object",
689 | "properties": {
690 | "username": {
691 | "type": "string",
692 | "description": "用户名",
693 | "example": "fastdev"
694 | }
695 | }
696 | },
697 | "TokenDTO": {
698 | "title": "TokenDTO",
699 | "required": [
700 | "accessToken",
701 | "refreshToken",
702 | "userId"
703 | ],
704 | "type": "object",
705 | "properties": {
706 | "accessToken": {
707 | "type": "string",
708 | "description": "通行令牌"
709 | },
710 | "refreshToken": {
711 | "type": "string",
712 | "description": "刷新令牌"
713 | },
714 | "userId": {
715 | "type": "integer",
716 | "description": "用户ID",
717 | "format": "int64"
718 | }
719 | }
720 | }
721 | }
722 | }
723 | }
724 |
--------------------------------------------------------------------------------
/test/example-files/swagger-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "info": {
4 | "title": "未定义接口",
5 | "description": "接口文档描述",
6 | "contact": {},
7 | "license": {},
8 | "version": "v1.0"
9 | },
10 | "paths": {},
11 | "components": {},
12 | "x-openapi": {
13 | "x-setting": {
14 | "customCode": 200,
15 | "language": "zh-CN",
16 | "enableSwaggerModels": true,
17 | "swaggerModelName": "实体类列表",
18 | "enableReloadCacheParameter": false,
19 | "enableAfterScript": true,
20 | "enableDocumentManage": true,
21 | "enableVersion": false,
22 | "enableRequestCache": true,
23 | "enableFilterMultipartApis": false,
24 | "enableFilterMultipartApiMethodType": "POST",
25 | "enableHost": false,
26 | "enableHostText": "",
27 | "enableDynamicParameter": true,
28 | "enableDebug": true,
29 | "enableFooter": true,
30 | "enableFooterCustom": false,
31 | "enableSearch": true,
32 | "enableOpenApi": true,
33 | "enableHomeCustom": false,
34 | "enableGroup": true,
35 | "enableResponseCode": true
36 | },
37 | "x-markdownFiles": []
38 | }
39 | }
--------------------------------------------------------------------------------
/test/example-files/swagger-file-convert.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "file swagger",
5 | "version": "1.0.0"
6 | },
7 | "basePath": "/",
8 | "tags": [
9 | {
10 | "name": "file-controller",
11 | "description": "FileController"
12 | }
13 | ],
14 | "paths": {
15 | "/webapi/clear/importNavReCheckFile": {
16 | "post": {
17 | "tags": [
18 | "file-controller"
19 | ],
20 | "summary": "导入文件",
21 | "description": "导入文件",
22 | "operationId": "importNavReCheckFileUsingPOST",
23 | "consumes": [
24 | "multipart/form-data"
25 | ],
26 | "produces": [
27 | "*/*"
28 | ],
29 | "parameters": [
30 | {
31 | "name": "file",
32 | "in": "formData",
33 | "description": "file",
34 | "required": true,
35 | "type": "file"
36 | }
37 | ],
38 | "responses": {
39 | "200": {
40 | "description": "结果",
41 | "schema": {
42 | "originalRef": "Response«string»",
43 | "$ref": "#/definitions/Response«string»"
44 | }
45 | },
46 | "201": {
47 | "description": "Created"
48 | },
49 | "401": {
50 | "description": "Unauthorized"
51 | },
52 | "403": {
53 | "description": "Forbidden"
54 | },
55 | "404": {
56 | "description": "Not Found"
57 | }
58 | },
59 | "deprecated": false
60 | }
61 | }
62 | },
63 | "definitions": {
64 | "Response«string»": {
65 | "type": "object",
66 | "properties": {
67 | "msg": {
68 | "type": "string"
69 | },
70 | "result": {
71 | "type": "string"
72 | },
73 | "resultCode": {
74 | "type": "string"
75 | },
76 | "success": {
77 | "type": "boolean"
78 | }
79 | },
80 | "title": "Response«string»"
81 | },
82 | "中文测试1": {
83 | "type": "object",
84 | "properties": {
85 | "msg": {
86 | "type": "string"
87 | },
88 | "result": {
89 | "type": "string"
90 | },
91 | "resultCode": {
92 | "type": "string"
93 | },
94 | "success": {
95 | "type": "boolean"
96 | }
97 | },
98 | "title": "Response«string»"
99 | },
100 | "中文测试2": {
101 | "type": "object",
102 | "properties": {
103 | "msg": {
104 | "type": "string"
105 | },
106 | "result": {
107 | "type": "string"
108 | },
109 | "resultCode": {
110 | "type": "string"
111 | },
112 | "success": {
113 | "type": "boolean"
114 | }
115 | }
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/test/example-files/swagger-schema-contain-blank-symbol.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "info": {
4 | "title": "Swagger Petstore",
5 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
6 | "termsOfService": "http://swagger.io/terms/",
7 | "contact": {
8 | "email": "apiteam@swagger.io"
9 | },
10 | "license": {
11 | "name": "Apache 2.0",
12 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
13 | },
14 | "version": "1.0.0"
15 | },
16 | "externalDocs": {
17 | "description": "Find out more about Swagger",
18 | "url": "http://swagger.io"
19 | },
20 | "servers": [
21 | {
22 | "url": "https://petstore.swagger.io/v2"
23 | },
24 | {
25 | "url": "http://petstore.swagger.io/v2"
26 | }
27 | ],
28 | "tags": [
29 | {
30 | "name": "pet",
31 | "description": "Everything about your Pets",
32 | "externalDocs": {
33 | "description": "Find out more",
34 | "url": "http://swagger.io"
35 | }
36 | },
37 | {
38 | "name": "store",
39 | "description": "Access to Petstore orders"
40 | },
41 | {
42 | "name": "user",
43 | "description": "Operations about user",
44 | "externalDocs": {
45 | "description": "Find out more about our store",
46 | "url": "http://swagger.io"
47 | }
48 | }
49 | ],
50 | "paths": {
51 | "/electricity/classification/time-sharing-electricity": {
52 | "post": {
53 | "tags": ["分项用电模块{6C76B49E435F7713E0531F0B10AC7013}"],
54 | "summary": "分时电量查询",
55 | "operationId": "timeSharingElectricityUsingPOST",
56 | "requestBody": {
57 | "content": {
58 | "application/json": {
59 | "schema": {
60 | "$ref": "#/components/schemas/分项、设备 自然时间 统计查询 dto"
61 | }
62 | }
63 | }
64 | },
65 | "responses": {
66 | "200": {
67 | "description": "OK",
68 | "content": {
69 | "*/*": {
70 | "schema": {
71 | "$ref": "#/components/schemas/StatisticsQueryVo"
72 | }
73 | }
74 | }
75 | },
76 | "201": {
77 | "description": "Created"
78 | },
79 | "401": {
80 | "description": "Unauthorized"
81 | },
82 | "403": {
83 | "description": "Forbidden"
84 | },
85 | "404": {
86 | "description": "Not Found"
87 | }
88 | }
89 | }
90 | }
91 | },
92 | "components": {
93 | "schemas": {
94 | "分项、设备 自然时间 统计查询 dto": {
95 | "title": "分项、设备 自然时间 统计查询 dto",
96 | "type": "object",
97 | "properties": {
98 | "businessType": {
99 | "type": "string",
100 | "description": "业务类型",
101 | "enum": ["CLASSIFICATION", "DEVICE", "INSTRUMENT"]
102 | },
103 | "endTime": {
104 | "type": "string",
105 | "description": "结束时间",
106 | "format": "date-time"
107 | },
108 | "energyType": {
109 | "type": "string",
110 | "description": "能源类型"
111 | },
112 | "ids": {
113 | "type": "array",
114 | "description": "根据业务类型传勾选id",
115 | "items": {
116 | "type": "string"
117 | }
118 | },
119 | "startTime": {
120 | "type": "string",
121 | "description": "开始时间",
122 | "format": "date-time"
123 | },
124 | "timeInterval": {
125 | "type": "string",
126 | "description": "时间粒度",
127 | "enum": ["DAY", "HALFHOUR", "HOUR", "MINUTE", "MONTH", "QUARTERHOUR", "YEAR"]
128 | },
129 | "timeQueryType": {
130 | "type": "string",
131 | "description": "查询类型 自然时间-NATURAL,班制时间-SHIFT",
132 | "enum": ["NATURAL", "SHIFT"]
133 | },
134 | "vsEndTime": {
135 | "type": "string",
136 | "description": "对比结束时间",
137 | "format": "date-time"
138 | },
139 | "vsStartTime": {
140 | "type": "string",
141 | "description": "对比开始时间",
142 | "format": "date-time"
143 | },
144 | "vsType": {
145 | "type": "string",
146 | "description": "比较类型",
147 | "enum": ["CLASSIFICATION", "DEVICE", "TIME"]
148 | }
149 | }
150 | },
151 | "ApiResponse": {
152 | "type": "object",
153 | "properties": {
154 | "code": {
155 | "type": "integer",
156 | "format": "int32"
157 | },
158 | "type": {
159 | "type": "string"
160 | },
161 | "message": {
162 | "type": "string"
163 | }
164 | }
165 | }
166 | },
167 | "securitySchemes": {
168 | "petstore_auth": {
169 | "type": "oauth2",
170 | "flows": {
171 | "implicit": {
172 | "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
173 | "scopes": {
174 | "write:pets": "modify pets in your account",
175 | "read:pets": "read your pets"
176 | }
177 | }
178 | }
179 | },
180 | "api_key": {
181 | "type": "apiKey",
182 | "name": "api_key",
183 | "in": "header"
184 | }
185 | }
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/test/example-files/swgger3.0.1.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "info": {
4 | "title": "test API",
5 | "description": "test API ",
6 | "version": "v1.0.0"
7 | },
8 | "tags": [
9 | {
10 | "name": "SysOperlog",
11 | "description": "日志管理"
12 | }
13 | ],
14 | "paths": {
15 | "/LandIA/sysOperlog/listOperlog": {
16 | "get": {
17 | "tags": [
18 | "SysOperlog"
19 | ],
20 | "summary": "操作日志接口",
21 | "operationId": "get_test1",
22 | "parameters": [
23 | {
24 | "name": "startTime",
25 | "in": "query",
26 | "description": "起始时间",
27 | "required": false,
28 | "schema": {
29 | "type": "integer",
30 | "format": "int64"
31 | }
32 | },
33 | {
34 | "name": "endTime",
35 | "in": "query",
36 | "description": "结束时间",
37 | "required": false,
38 | "schema": {
39 | "type": "integer",
40 | "format": "int64"
41 | }
42 | },
43 | {
44 | "name": "userId",
45 | "in": "query",
46 | "description": "用户ID",
47 | "required": false,
48 | "schema": {
49 | "type": "string"
50 | }
51 | },
52 | {
53 | "name": "pageSize",
54 | "in": "query",
55 | "description": "分页页容量",
56 | "required": false,
57 | "schema": {
58 | "type": "integer",
59 | "format": "int32"
60 | }
61 | },
62 | {
63 | "name": "pageIndex",
64 | "in": "query",
65 | "description": "分页页序号",
66 | "required": false,
67 | "schema": {
68 | "type": "integer",
69 | "format": "int32"
70 | }
71 | },
72 | {
73 | "name": "reqSerial",
74 | "in": "header",
75 | "description": "请求流水号",
76 | "required": true,
77 | "schema": {
78 | "type": "string"
79 | }
80 | },
81 | {
82 | "name": "Authorization",
83 | "in": "header",
84 | "description": "请求授权码",
85 | "required": false,
86 | "schema": {
87 | "type": "string"
88 | }
89 | }
90 | ],
91 | "responses": {
92 | "200": {
93 | "description": "OK",
94 | "content": {
95 | "*/*": {
96 | "schema": {
97 | "$ref": "#/components/schemas/F2BResponseGetListOperlogRespPost"
98 | }
99 | }
100 | }
101 | }
102 | }
103 | },
104 | "post": {
105 | "tags": [
106 | "SysOperlog"
107 | ],
108 | "summary": "操作日志接口2",
109 | "operationId": "post_test2",
110 | "parameters": [
111 | {
112 | "name": "Authorization",
113 | "in": "header",
114 | "description": "请求授权码",
115 | "required": false,
116 | "schema": {
117 | "type": "string"
118 | }
119 | }
120 | ],
121 | "responses": {
122 | "200": {
123 | "description": "OK",
124 | "content": {
125 | "*/*": {
126 | "schema": {
127 | "$ref": "#/components/schemas/F2BResponseGetListOperlogRespPost"
128 | }
129 | }
130 | }
131 | }
132 | }
133 | }
134 | },
135 | "/admin-api/system/oauth2/user/update": {
136 | "get": {
137 | "description": "New endpoint",
138 | "responses": {
139 | "200": {
140 | "description": "New response",
141 | "content": {
142 | "application/json": {
143 | "schema": {
144 | "": ""
145 | }
146 | }
147 | }
148 | }
149 | }
150 | },
151 | "put": {
152 | "tags": [
153 | "管理后台 - OAuth2.0 用户"
154 | ],
155 | "summary": "更新用户基本信息",
156 | "operationId": "updateUserInfo",
157 | "parameters": [
158 | {
159 | "name": "AUTH_ID",
160 | "in": "header",
161 | "description": "Session Token",
162 | "schema": {
163 | "type": "string",
164 | "description": "session-id",
165 | "default": "1"
166 | }
167 | },
168 | {
169 | "name": "tenant-id",
170 | "in": "header",
171 | "description": "租户编号",
172 | "schema": {
173 | "type": "integer",
174 | "description": "租户编号",
175 | "format": "int32",
176 | "default": 1
177 | }
178 | },
179 | {
180 | "name": "Authorization",
181 | "in": "header",
182 | "description": "认证 Token",
183 | "schema": {
184 | "type": "string",
185 | "description": "认证 Token",
186 | "default": "Best test1"
187 | }
188 | }
189 | ],
190 | "requestBody": {
191 | "content": {
192 | "application/json": {
193 | "schema": {
194 | "$ref": "#/components/schemas/OAuth2UserUpdateReqVO"
195 | }
196 | }
197 | },
198 | "required": true
199 | },
200 | "responses": {
201 | "200": {
202 | "description": "OK",
203 | "content": {
204 | "*/*": {
205 | "schema": {
206 | "$ref": "#/components/schemas/CommonResultBoolean"
207 | }
208 | }
209 | }
210 | }
211 | }
212 | }
213 | }
214 | },
215 | "components": {
216 | "schemas": {
217 | "F2BResponseGetListOperlogRespPost": {
218 | "type": "object",
219 | "properties": {
220 | "bizContent": {
221 | "$ref": "#/components/schemas/GetListOperlogRespPost"
222 | },
223 | "bizCode": {
224 | "type": "string"
225 | },
226 | "bizMsg": {
227 | "type": "string"
228 | },
229 | "sysCode": {
230 | "type": "string"
231 | },
232 | "sysMsg": {
233 | "type": "string"
234 | },
235 | "reqSerial": {
236 | "type": "string"
237 | }
238 | }
239 | },
240 | "GetListOperlogRespPost": {
241 | "type": "object",
242 | "properties": {
243 | "total": {
244 | "type": "integer",
245 | "format": "int64"
246 | },
247 | "rows": {
248 | "type": "array",
249 | "items": {
250 | "$ref": "#/components/schemas/SysCommonLogPojo"
251 | }
252 | }
253 | }
254 | },
255 | "CommonResultBoolean": {
256 | "type": "object",
257 | "properties": {
258 | "code": {
259 | "type": "integer",
260 | "format": "int32"
261 | },
262 | "data": {
263 | "type": "boolean"
264 | },
265 | "msg": {
266 | "type": "string"
267 | }
268 | }
269 | },
270 | "OAuth2UserUpdateReqVO": {
271 | "required": [
272 | "nickname"
273 | ],
274 | "type": "object",
275 | "properties": {
276 | "nickname": {
277 | "maxLength": 30,
278 | "minLength": 0,
279 | "type": "string",
280 | "description": "用户昵称",
281 | "example": "芋艿"
282 | },
283 | "email": {
284 | "maxLength": 50,
285 | "minLength": 0,
286 | "type": "string",
287 | "description": "用户邮箱",
288 | "example": "platform@iocoder.cn"
289 | },
290 | "mobile": {
291 | "type": "string",
292 | "description": "手机号码",
293 | "example": "15601691300"
294 | },
295 | "sex": {
296 | "type": "integer",
297 | "description": "用户性别,参见 SexEnum 枚举类",
298 | "format": "int32",
299 | "example": 1
300 | }
301 | },
302 | "description": "管理后台 - OAuth2 更新用户基本信息 Request VO"
303 | }
304 | }
305 | }
306 | }
--------------------------------------------------------------------------------
/test/genSwagger.js:
--------------------------------------------------------------------------------
1 | const openAPI = require('../dist/index');
2 |
3 | openAPI.generateService({
4 | schemaPath: './swagger.json',
5 | serversPath: './servers',
6 | declareType: 'interface',
7 | });
8 |
--------------------------------------------------------------------------------
/test/java-api.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.3",
3 | "info": {
4 | "title": "Api Documentation",
5 | "description": "Api Documentation",
6 | "termsOfService": "urn:tos",
7 | "contact": {},
8 | "license": {
9 | "name": "Apache 2.0",
10 | "url": "http://www.apache.org/licenses/LICENSE-2.0"
11 | },
12 | "version": "1.0"
13 | },
14 | "servers": [
15 | {
16 | "url": "http://localhost:8080",
17 | "description": "Inferred Url"
18 | }
19 | ],
20 | "tags": [
21 | {
22 | "name": "flow-controller",
23 | "description": "Flow Controller"
24 | }
25 | ],
26 | "paths": {
27 | "/flow/flows": {
28 | "get": {
29 | "tags": ["flow-controller"],
30 | "summary": "flows",
31 | "operationId": "flowsUsingGET_2",
32 | "parameters": [
33 | {
34 | "name": "arguments",
35 | "in": "query",
36 | "required": false,
37 | "style": "form",
38 | "schema": {
39 | "type": "string"
40 | }
41 | },
42 | {
43 | "name": "createDate",
44 | "in": "query",
45 | "required": false,
46 | "style": "form",
47 | "schema": {
48 | "type": "string",
49 | "format": "date-time"
50 | }
51 | },
52 | {
53 | "name": "createUserId",
54 | "in": "query",
55 | "required": false,
56 | "style": "form",
57 | "schema": {
58 | "type": "integer",
59 | "format": "int64"
60 | }
61 | },
62 | {
63 | "name": "edge",
64 | "in": "query",
65 | "required": false,
66 | "style": "form",
67 | "schema": {
68 | "type": "string"
69 | }
70 | },
71 | {
72 | "name": "id",
73 | "in": "query",
74 | "required": false,
75 | "style": "form",
76 | "schema": {
77 | "type": "integer",
78 | "format": "int64"
79 | }
80 | },
81 | {
82 | "name": "name",
83 | "in": "query",
84 | "required": false,
85 | "style": "form",
86 | "schema": {
87 | "type": "string"
88 | }
89 | },
90 | {
91 | "name": "node",
92 | "in": "query",
93 | "required": false,
94 | "style": "form",
95 | "schema": {
96 | "type": "string"
97 | }
98 | },
99 | {
100 | "name": "note",
101 | "in": "query",
102 | "required": false,
103 | "style": "form",
104 | "schema": {
105 | "type": "string"
106 | }
107 | },
108 | {
109 | "name": "statusCode",
110 | "in": "query",
111 | "required": false,
112 | "style": "form",
113 | "schema": {
114 | "type": "integer",
115 | "format": "int32"
116 | }
117 | }
118 | ],
119 | "responses": {
120 | "200": {
121 | "description": "OK",
122 | "content": {
123 | "*/*": {
124 | "schema": {
125 | "$ref": "#/components/schemas/Result«List«ConfigFlow»»"
126 | }
127 | }
128 | }
129 | },
130 | "401": {
131 | "description": "Unauthorized"
132 | },
133 | "403": {
134 | "description": "Forbidden"
135 | },
136 | "404": {
137 | "description": "Not Found"
138 | }
139 | }
140 | }
141 | }
142 | },
143 | "components": {
144 | "schemas": {
145 | "Result«List«ConfigFlow»»": {
146 | "title": "Result«List«ConfigFlow»»",
147 | "type": "object",
148 | "properties": {
149 | "data": {
150 | "type": "array",
151 | "items": {
152 | "$ref": "#/components/schemas/ConfigFlow"
153 | }
154 | },
155 | "errorCode": {
156 | "type": "string"
157 | },
158 | "errorMessage": {
159 | "type": "string"
160 | },
161 | "host": {
162 | "type": "string"
163 | },
164 | "showType": {
165 | "$ref": "#/components/schemas/ShowType"
166 | },
167 | "success": {
168 | "type": "boolean"
169 | },
170 | "traceId": {
171 | "type": "string"
172 | }
173 | }
174 | },
175 | "ShowType": {
176 | "title": "ShowType",
177 | "type": "object",
178 | "properties": {
179 | "type": {
180 | "type": "integer",
181 | "format": "int32"
182 | }
183 | }
184 | },
185 | "ConfigFlow": {
186 | "title": "ConfigFlow",
187 | "type": "object",
188 | "properties": {
189 | "id": {
190 | "type": "integer",
191 | "format": "int64"
192 | },
193 | "name": {
194 | "type": "string"
195 | }
196 | }
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/test/morse-api.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "version": "1.0.20210224155647",
4 | "description": "morse_restful_api",
5 | "title": "morse_product"
6 | },
7 | "paths": {
8 | "/manager/user/addUser.json": {
9 | "post": {
10 | "responses": {
11 | "200": {
12 | "description": "Success"
13 | }
14 | },
15 | "parameters": [
16 | {
17 | "required": true,
18 | "type": "string",
19 | "description": "\u7528\u6237\u540d",
20 | "name": "username",
21 | "in": "query"
22 | },
23 | {
24 | "required": true,
25 | "type": "string",
26 | "description": "\u5bc6\u7801",
27 | "name": "passwd",
28 | "in": "query"
29 | },
30 | {
31 | "type": "string",
32 | "description": "\u90ae\u7bb1",
33 | "name": "email",
34 | "in": "query"
35 | },
36 | {
37 | "type": "string",
38 | "description": "\u624b\u673a\u53f7",
39 | "name": "mobile",
40 | "in": "query"
41 | }
42 | ],
43 | "tags": ["manager/user"],
44 | "description": ":return:",
45 | "summary": "\u6dfb\u52a0\u7528\u6237\u4fe1\u606f",
46 | "operationId": "post_user_add"
47 | }
48 | },
49 | "/manager/user/authorization.json": {
50 | "post": {
51 | "tags": ["manager/user"],
52 | "responses": {
53 | "200": {
54 | "description": "Success"
55 | }
56 | },
57 | "operationId": "post_user_authorization"
58 | }
59 | },
60 | "/manager/user/delUser.json": {
61 | "post": {
62 | "tags": ["manager/user"],
63 | "responses": {
64 | "200": {
65 | "description": "Success"
66 | }
67 | },
68 | "parameters": [
69 | {
70 | "required": true,
71 | "type": "string",
72 | "description": "\u81ea\u589eid",
73 | "name": "id",
74 | "in": "query"
75 | }
76 | ],
77 | "operationId": "post_user_del"
78 | }
79 | },
80 | "/manager/user/importUser.json": {
81 | "post": {
82 | "tags": ["manager/user"],
83 | "responses": {
84 | "200": {
85 | "description": "Success"
86 | }
87 | },
88 | "operationId": "post_user_import"
89 | }
90 | },
91 | "/manager/user/queryAuthcodes.json": {
92 | "get": {
93 | "tags": ["manager/user"],
94 | "responses": {
95 | "200": {
96 | "description": "Success"
97 | }
98 | },
99 | "operationId": "get_query_authcodes"
100 | }
101 | },
102 | "/manager/user/queryUserInfo.json": {
103 | "get": {
104 | "tags": ["manager/user"],
105 | "responses": {
106 | "200": {
107 | "description": "Success"
108 | }
109 | },
110 | "parameters": [
111 | {
112 | "required": true,
113 | "type": "string",
114 | "description": "\u81ea\u589e",
115 | "name": "id",
116 | "in": "query"
117 | }
118 | ],
119 | "operationId": "get_user_info"
120 | }
121 | },
122 | "/manager/user/queryUsers.json": {
123 | "get": {
124 | "tags": ["manager/user"],
125 | "responses": {
126 | "200": {
127 | "description": "Success"
128 | }
129 | },
130 | "parameters": [
131 | {
132 | "type": "string",
133 | "description": "\u7528\u6237\u7c7b\u578b\uff0cadmin/operator/None",
134 | "name": "user_type",
135 | "in": "query"
136 | },
137 | {
138 | "type": "string",
139 | "description": "\u5173\u952e\u8bcd",
140 | "name": "key_words",
141 | "in": "query"
142 | },
143 | {
144 | "type": "string",
145 | "description": "\u7b2c\u51e0\u6761",
146 | "name": "page_num",
147 | "in": "query"
148 | },
149 | {
150 | "type": "string",
151 | "description": "\u4e00\u9875\u51e0\u6761",
152 | "name": "page_size",
153 | "in": "query"
154 | }
155 | ],
156 | "operationId": "get_users_query"
157 | }
158 | },
159 | "/manager/user/randomPassword.json": {
160 | "get": {
161 | "tags": ["manager/user"],
162 | "responses": {
163 | "200": {
164 | "description": "Success"
165 | }
166 | },
167 | "operationId": "get_random_password"
168 | }
169 | },
170 | "/manager/user/updateUser.json": {
171 | "post": {
172 | "responses": {
173 | "200": {
174 | "description": "Success"
175 | }
176 | },
177 | "parameters": [
178 | {
179 | "required": true,
180 | "type": "string",
181 | "description": "id",
182 | "name": "id",
183 | "in": "query"
184 | },
185 | {
186 | "required": true,
187 | "type": "string",
188 | "description": "\u7528\u6237\u540d",
189 | "name": "username",
190 | "in": "query"
191 | },
192 | {
193 | "required": true,
194 | "type": "string",
195 | "description": "\u5bc6\u7801",
196 | "name": "passwd",
197 | "in": "query"
198 | },
199 | {
200 | "type": "string",
201 | "description": "\u90ae\u7bb1",
202 | "name": "email",
203 | "in": "query"
204 | },
205 | {
206 | "type": "string",
207 | "description": "\u624b\u673a\u53f7",
208 | "name": "mobile",
209 | "in": "query"
210 | }
211 | ],
212 | "tags": ["manager/user"],
213 | "description": ":return:",
214 | "summary": "\u7f16\u8f91\u7528\u6237\u4fe1\u606f",
215 | "operationId": "post_userupdate"
216 | }
217 | }
218 | },
219 | "responses": {
220 | "MaskError": {
221 | "description": "When any error occurs on mask"
222 | },
223 | "ParseError": {
224 | "description": "When a mask can't be parsed"
225 | }
226 | },
227 | "tags": [
228 | {
229 | "name": "manager/user",
230 | "description": "\u7528\u6237\u6a21\u5757"
231 | }
232 | ],
233 | "basePath": "/",
234 | "produces": ["application/json"],
235 | "swagger": "2.0",
236 | "consumes": ["application/json"]
237 | }
238 |
--------------------------------------------------------------------------------
/test/openapi.json:
--------------------------------------------------------------------------------
1 | {
2 | "openapi": "3.0.1",
3 | "info": {
4 | "title": "Swagger Petstore",
5 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
6 | "termsOfService": "http://swagger.io/terms/",
7 | "contact": {
8 | "email": "apiteam@swagger.io"
9 | },
10 | "license": {
11 | "name": "Apache 2.0",
12 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
13 | },
14 | "version": "1.0.0"
15 | },
16 | "externalDocs": {
17 | "description": "Find out more about Swagger",
18 | "url": "http://swagger.io"
19 | },
20 | "servers": [
21 | {
22 | "url": "https://petstore.swagger.io/v2"
23 | },
24 | {
25 | "url": "http://petstore.swagger.io/v2"
26 | }
27 | ],
28 | "tags": [
29 | {
30 | "name": "pet",
31 | "description": "Everything about your Pets",
32 | "externalDocs": {
33 | "description": "Find out more",
34 | "url": "http://swagger.io"
35 | }
36 | },
37 | {
38 | "name": "store",
39 | "description": "Access to Petstore orders"
40 | },
41 | {
42 | "name": "user",
43 | "description": "Operations about user",
44 | "externalDocs": {
45 | "description": "Find out more about our store",
46 | "url": "http://swagger.io"
47 | }
48 | }
49 | ],
50 | "paths": {
51 | "/pet": {
52 | "put": {
53 | "tags": ["pet"],
54 | "summary": "Update an existing pet",
55 | "operationId": "updatePet",
56 | "requestBody": {
57 | "description": "Pet object that needs to be added to the store",
58 | "content": {
59 | "application/json": {
60 | "schema": {
61 | "$ref": "#/components/schemas/Pet"
62 | }
63 | },
64 | "application/xml": {
65 | "schema": {
66 | "$ref": "#/components/schemas/Pet"
67 | }
68 | }
69 | },
70 | "required": true
71 | },
72 | "responses": {
73 | "400": {
74 | "description": "Invalid ID supplied",
75 | "content": {}
76 | },
77 | "404": {
78 | "description": "Pet not found",
79 | "content": {}
80 | },
81 | "405": {
82 | "description": "Validation exception",
83 | "content": {}
84 | }
85 | },
86 | "security": [
87 | {
88 | "petstore_auth": ["write:pets", "read:pets"]
89 | }
90 | ],
91 | "x-codegen-request-body-name": "body"
92 | },
93 | "post": {
94 | "tags": ["pet"],
95 | "summary": "Add a new pet to the store",
96 | "operationId": "addPet",
97 | "requestBody": {
98 | "description": "Pet object that needs to be added to the store",
99 | "content": {
100 | "application/json": {
101 | "schema": {
102 | "$ref": "#/components/schemas/Pet"
103 | }
104 | },
105 | "application/xml": {
106 | "schema": {
107 | "$ref": "#/components/schemas/Pet"
108 | }
109 | }
110 | },
111 | "required": true
112 | },
113 | "responses": {
114 | "405": {
115 | "description": "Invalid input",
116 | "content": {}
117 | }
118 | },
119 | "security": [
120 | {
121 | "petstore_auth": ["write:pets", "read:pets"]
122 | }
123 | ],
124 | "x-codegen-request-body-name": "body"
125 | }
126 | },
127 | "/pet/findByStatus": {
128 | "get": {
129 | "tags": ["pet"],
130 | "summary": "Finds Pets by status",
131 | "description": "Multiple status values can be provided with comma separated strings",
132 | "operationId": "findPetsByStatus",
133 | "parameters": [
134 | {
135 | "name": "status",
136 | "in": "query",
137 | "description": "Status values that need to be considered for filter",
138 | "required": true,
139 | "style": "form",
140 | "explode": true,
141 | "schema": {
142 | "type": "array",
143 | "items": {
144 | "type": "string",
145 | "default": "available",
146 | "enum": ["available", "pending", "sold"]
147 | }
148 | }
149 | }
150 | ],
151 | "responses": {
152 | "200": {
153 | "description": "successful operation",
154 | "content": {
155 | "application/xml": {
156 | "schema": {
157 | "type": "array",
158 | "items": {
159 | "$ref": "#/components/schemas/Pet"
160 | }
161 | }
162 | },
163 | "application/json": {
164 | "schema": {
165 | "type": "array",
166 | "items": {
167 | "$ref": "#/components/schemas/Pet"
168 | }
169 | }
170 | }
171 | }
172 | },
173 | "400": {
174 | "description": "Invalid status value",
175 | "content": {}
176 | }
177 | },
178 | "security": [
179 | {
180 | "petstore_auth": ["write:pets", "read:pets"]
181 | }
182 | ]
183 | }
184 | },
185 | "/pet/findByTags": {
186 | "get": {
187 | "tags": ["pet"],
188 | "summary": "Finds Pets by tags",
189 | "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
190 | "operationId": "findPetsByTags",
191 | "parameters": [
192 | {
193 | "name": "tags",
194 | "in": "query",
195 | "description": "Tags to filter by",
196 | "required": true,
197 | "style": "form",
198 | "explode": true,
199 | "schema": {
200 | "type": "array",
201 | "items": {
202 | "type": "string"
203 | }
204 | }
205 | }
206 | ],
207 | "responses": {
208 | "200": {
209 | "description": "successful operation",
210 | "content": {
211 | "application/xml": {
212 | "schema": {
213 | "type": "array",
214 | "items": {
215 | "$ref": "#/components/schemas/Pet"
216 | }
217 | }
218 | },
219 | "application/json": {
220 | "schema": {
221 | "type": "array",
222 | "items": {
223 | "$ref": "#/components/schemas/Pet"
224 | }
225 | }
226 | }
227 | }
228 | },
229 | "400": {
230 | "description": "Invalid tag value",
231 | "content": {}
232 | }
233 | },
234 | "deprecated": true,
235 | "security": [
236 | {
237 | "petstore_auth": ["write:pets", "read:pets"]
238 | }
239 | ]
240 | }
241 | },
242 | "/pet/{petId}": {
243 | "get": {
244 | "tags": ["pet"],
245 | "summary": "Find pet by ID",
246 | "description": "Returns a single pet",
247 | "operationId": "getPetById",
248 | "parameters": [
249 | {
250 | "name": "petId",
251 | "in": "path",
252 | "description": "ID of pet to return",
253 | "required": true,
254 | "schema": {
255 | "type": "integer",
256 | "format": "int64"
257 | }
258 | }
259 | ],
260 | "responses": {
261 | "200": {
262 | "description": "successful operation",
263 | "content": {
264 | "application/xml": {
265 | "schema": {
266 | "$ref": "#/components/schemas/Pet"
267 | }
268 | },
269 | "application/json": {
270 | "schema": {
271 | "$ref": "#/components/schemas/Pet"
272 | }
273 | }
274 | }
275 | },
276 | "400": {
277 | "description": "Invalid ID supplied",
278 | "content": {}
279 | },
280 | "404": {
281 | "description": "Pet not found",
282 | "content": {}
283 | }
284 | },
285 | "security": [
286 | {
287 | "api_key": []
288 | }
289 | ]
290 | },
291 | "post": {
292 | "tags": ["pet"],
293 | "summary": "Updates a pet in the store with form data",
294 | "operationId": "updatePetWithForm",
295 | "parameters": [
296 | {
297 | "name": "petId",
298 | "in": "path",
299 | "description": "ID of pet that needs to be updated",
300 | "required": true,
301 | "schema": {
302 | "type": "integer",
303 | "format": "int64"
304 | }
305 | }
306 | ],
307 | "requestBody": {
308 | "content": {
309 | "application/x-www-form-urlencoded": {
310 | "schema": {
311 | "properties": {
312 | "name": {
313 | "type": "string",
314 | "description": "Updated name of the pet"
315 | },
316 | "status": {
317 | "type": "string",
318 | "description": "Updated status of the pet"
319 | }
320 | }
321 | }
322 | }
323 | }
324 | },
325 | "responses": {
326 | "405": {
327 | "description": "Invalid input",
328 | "content": {}
329 | }
330 | },
331 | "security": [
332 | {
333 | "petstore_auth": ["write:pets", "read:pets"]
334 | }
335 | ]
336 | },
337 | "delete": {
338 | "tags": ["pet"],
339 | "summary": "Deletes a pet",
340 | "operationId": "deletePet",
341 | "parameters": [
342 | {
343 | "name": "api_key",
344 | "in": "header",
345 | "schema": {
346 | "type": "string"
347 | }
348 | },
349 | {
350 | "name": "petId",
351 | "in": "path",
352 | "description": "Pet id to delete",
353 | "required": true,
354 | "schema": {
355 | "type": "integer",
356 | "format": "int64"
357 | }
358 | }
359 | ],
360 | "responses": {
361 | "400": {
362 | "description": "Invalid ID supplied",
363 | "content": {}
364 | },
365 | "404": {
366 | "description": "Pet not found",
367 | "content": {}
368 | }
369 | },
370 | "security": [
371 | {
372 | "petstore_auth": ["write:pets", "read:pets"]
373 | }
374 | ]
375 | }
376 | },
377 | "/pet/{petId}/uploadImage": {
378 | "post": {
379 | "tags": ["pet"],
380 | "summary": "uploads an image",
381 | "operationId": "uploadFile",
382 | "parameters": [
383 | {
384 | "name": "petId",
385 | "in": "path",
386 | "description": "ID of pet to update",
387 | "required": true,
388 | "schema": {
389 | "type": "integer",
390 | "format": "int64"
391 | }
392 | }
393 | ],
394 | "requestBody": {
395 | "content": {
396 | "multipart/form-data": {
397 | "schema": {
398 | "properties": {
399 | "additionalMetadata": {
400 | "type": "string",
401 | "description": "Additional data to pass to server"
402 | },
403 | "file": {
404 | "type": "string",
405 | "description": "file to upload",
406 | "format": "binary"
407 | }
408 | }
409 | }
410 | }
411 | }
412 | },
413 | "responses": {
414 | "200": {
415 | "description": "successful operation",
416 | "content": {
417 | "application/json": {
418 | "schema": {
419 | "$ref": "#/components/schemas/ApiResponse"
420 | }
421 | }
422 | }
423 | }
424 | },
425 | "security": [
426 | {
427 | "petstore_auth": ["write:pets", "read:pets"]
428 | }
429 | ]
430 | }
431 | },
432 | "/store/inventory": {
433 | "get": {
434 | "tags": ["store"],
435 | "summary": "Returns pet inventories by status",
436 | "description": "Returns a map of status codes to quantities",
437 | "operationId": "getInventory",
438 | "responses": {
439 | "200": {
440 | "description": "successful operation",
441 | "content": {
442 | "application/json": {
443 | "schema": {
444 | "type": "object",
445 | "additionalProperties": {
446 | "type": "integer",
447 | "format": "int32"
448 | }
449 | }
450 | }
451 | }
452 | }
453 | },
454 | "security": [
455 | {
456 | "api_key": []
457 | }
458 | ]
459 | }
460 | },
461 | "/store/order": {
462 | "post": {
463 | "tags": ["store"],
464 | "summary": "Place an order for a pet",
465 | "operationId": "placeOrder",
466 | "requestBody": {
467 | "description": "order placed for purchasing the pet",
468 | "content": {
469 | "*/*": {
470 | "schema": {
471 | "$ref": "#/components/schemas/Order"
472 | }
473 | }
474 | },
475 | "required": true
476 | },
477 | "responses": {
478 | "200": {
479 | "description": "successful operation",
480 | "content": {
481 | "application/xml": {
482 | "schema": {
483 | "$ref": "#/components/schemas/Order"
484 | }
485 | },
486 | "application/json": {
487 | "schema": {
488 | "$ref": "#/components/schemas/Order"
489 | }
490 | }
491 | }
492 | },
493 | "400": {
494 | "description": "Invalid Order",
495 | "content": {}
496 | }
497 | },
498 | "x-codegen-request-body-name": "body"
499 | }
500 | },
501 | "/store/order/{orderId}": {
502 | "get": {
503 | "tags": ["store"],
504 | "summary": "Find purchase order by ID",
505 | "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
506 | "operationId": "getOrderById",
507 | "parameters": [
508 | {
509 | "name": "orderId",
510 | "in": "path",
511 | "description": "ID of pet that needs to be fetched",
512 | "required": true,
513 | "schema": {
514 | "maximum": 10,
515 | "minimum": 1,
516 | "type": "integer",
517 | "format": "int64"
518 | }
519 | }
520 | ],
521 | "responses": {
522 | "200": {
523 | "description": "successful operation",
524 | "content": {
525 | "application/xml": {
526 | "schema": {
527 | "$ref": "#/components/schemas/Order"
528 | }
529 | },
530 | "application/json": {
531 | "schema": {
532 | "$ref": "#/components/schemas/Order"
533 | }
534 | }
535 | }
536 | },
537 | "400": {
538 | "description": "Invalid ID supplied",
539 | "content": {}
540 | },
541 | "404": {
542 | "description": "Order not found",
543 | "content": {}
544 | }
545 | }
546 | },
547 | "delete": {
548 | "tags": ["store"],
549 | "summary": "Delete purchase order by ID",
550 | "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors",
551 | "operationId": "deleteOrder",
552 | "parameters": [
553 | {
554 | "name": "orderId",
555 | "in": "path",
556 | "description": "ID of the order that needs to be deleted",
557 | "required": true,
558 | "schema": {
559 | "minimum": 1,
560 | "type": "integer",
561 | "format": "int64"
562 | }
563 | }
564 | ],
565 | "responses": {
566 | "400": {
567 | "description": "Invalid ID supplied",
568 | "content": {}
569 | },
570 | "404": {
571 | "description": "Order not found",
572 | "content": {}
573 | }
574 | }
575 | }
576 | },
577 | "/user": {
578 | "post": {
579 | "tags": ["user"],
580 | "summary": "Create user",
581 | "description": "This can only be done by the logged in user.",
582 | "operationId": "createUser",
583 | "requestBody": {
584 | "description": "Created user object",
585 | "content": {
586 | "*/*": {
587 | "schema": {
588 | "$ref": "#/components/schemas/User"
589 | }
590 | }
591 | },
592 | "required": true
593 | },
594 | "responses": {
595 | "default": {
596 | "description": "successful operation",
597 | "content": {}
598 | }
599 | },
600 | "x-codegen-request-body-name": "body"
601 | }
602 | },
603 | "/user/createWithArray": {
604 | "post": {
605 | "tags": ["user"],
606 | "summary": "Creates list of users with given input array",
607 | "operationId": "createUsersWithArrayInput",
608 | "requestBody": {
609 | "description": "List of user object",
610 | "content": {
611 | "*/*": {
612 | "schema": {
613 | "type": "array",
614 | "items": {
615 | "$ref": "#/components/schemas/User"
616 | }
617 | }
618 | }
619 | },
620 | "required": true
621 | },
622 | "responses": {
623 | "default": {
624 | "description": "successful operation",
625 | "content": {}
626 | }
627 | },
628 | "x-codegen-request-body-name": "body"
629 | }
630 | },
631 | "/user/createWithList": {
632 | "post": {
633 | "tags": ["user"],
634 | "summary": "Creates list of users with given input array",
635 | "operationId": "createUsersWithListInput",
636 | "requestBody": {
637 | "description": "List of user object",
638 | "content": {
639 | "*/*": {
640 | "schema": {
641 | "type": "array",
642 | "items": {
643 | "$ref": "#/components/schemas/User"
644 | }
645 | }
646 | }
647 | },
648 | "required": true
649 | },
650 | "responses": {
651 | "default": {
652 | "description": "successful operation",
653 | "content": {}
654 | }
655 | },
656 | "x-codegen-request-body-name": "body"
657 | }
658 | },
659 | "/user/login": {
660 | "get": {
661 | "tags": ["user"],
662 | "summary": "Logs user into the system",
663 | "operationId": "loginUser",
664 | "parameters": [
665 | {
666 | "name": "username",
667 | "in": "query",
668 | "description": "The user name for login",
669 | "required": true,
670 | "schema": {
671 | "type": "string"
672 | }
673 | },
674 | {
675 | "name": "password",
676 | "in": "query",
677 | "description": "The password for login in clear text",
678 | "required": true,
679 | "schema": {
680 | "type": "string"
681 | }
682 | }
683 | ],
684 | "responses": {
685 | "200": {
686 | "description": "successful operation",
687 | "headers": {
688 | "X-Rate-Limit": {
689 | "description": "calls per hour allowed by the user",
690 | "schema": {
691 | "type": "integer",
692 | "format": "int32"
693 | }
694 | },
695 | "X-Expires-After": {
696 | "description": "date in UTC when token expires",
697 | "schema": {
698 | "type": "string",
699 | "format": "date-time"
700 | }
701 | }
702 | },
703 | "content": {
704 | "application/xml": {
705 | "schema": {
706 | "type": "string"
707 | }
708 | },
709 | "application/json": {
710 | "schema": {
711 | "type": "string"
712 | }
713 | }
714 | }
715 | },
716 | "400": {
717 | "description": "Invalid username/password supplied",
718 | "content": {}
719 | }
720 | }
721 | }
722 | },
723 | "/user/logout": {
724 | "get": {
725 | "tags": ["user"],
726 | "summary": "Logs out current logged in user session",
727 | "operationId": "logoutUser",
728 | "responses": {
729 | "default": {
730 | "description": "successful operation",
731 | "content": {}
732 | }
733 | }
734 | }
735 | },
736 | "/user/{username}": {
737 | "get": {
738 | "tags": ["user"],
739 | "summary": "Get user by user name",
740 | "operationId": "getUserByName",
741 | "parameters": [
742 | {
743 | "name": "username",
744 | "in": "path",
745 | "description": "The name that needs to be fetched. Use user1 for testing. ",
746 | "required": true,
747 | "schema": {
748 | "type": "string"
749 | }
750 | }
751 | ],
752 | "responses": {
753 | "200": {
754 | "description": "successful operation",
755 | "content": {
756 | "application/xml": {
757 | "schema": {
758 | "$ref": "#/components/schemas/User"
759 | }
760 | },
761 | "application/json": {
762 | "schema": {
763 | "$ref": "#/components/schemas/User"
764 | }
765 | }
766 | }
767 | },
768 | "400": {
769 | "description": "Invalid username supplied",
770 | "content": {}
771 | },
772 | "404": {
773 | "description": "User not found",
774 | "content": {}
775 | }
776 | }
777 | },
778 | "put": {
779 | "tags": ["user"],
780 | "summary": "Updated user",
781 | "description": "This can only be done by the logged in user.",
782 | "operationId": "updateUser",
783 | "parameters": [
784 | {
785 | "name": "username",
786 | "in": "path",
787 | "description": "name that need to be updated",
788 | "required": true,
789 | "schema": {
790 | "type": "string"
791 | }
792 | }
793 | ],
794 | "requestBody": {
795 | "description": "Updated user object",
796 | "content": {
797 | "*/*": {
798 | "schema": {
799 | "$ref": "#/components/schemas/User"
800 | }
801 | }
802 | },
803 | "required": true
804 | },
805 | "responses": {
806 | "400": {
807 | "description": "Invalid user supplied",
808 | "content": {}
809 | },
810 | "404": {
811 | "description": "User not found",
812 | "content": {}
813 | }
814 | },
815 | "x-codegen-request-body-name": "body"
816 | },
817 | "delete": {
818 | "tags": ["user"],
819 | "summary": "Delete user",
820 | "description": "This can only be done by the logged in user.",
821 | "operationId": "deleteUser",
822 | "parameters": [
823 | {
824 | "name": "username",
825 | "in": "path",
826 | "description": "The name that needs to be deleted",
827 | "required": true,
828 | "schema": {
829 | "type": "string"
830 | }
831 | }
832 | ],
833 | "responses": {
834 | "400": {
835 | "description": "Invalid username supplied",
836 | "content": {}
837 | },
838 | "404": {
839 | "description": "User not found",
840 | "content": {}
841 | }
842 | }
843 | }
844 | }
845 | },
846 | "components": {
847 | "schemas": {
848 | "Order": {
849 | "type": "object",
850 | "properties": {
851 | "id": {
852 | "type": "integer",
853 | "format": "int64"
854 | },
855 | "petId": {
856 | "type": "integer",
857 | "format": "int64"
858 | },
859 | "quantity": {
860 | "type": "integer",
861 | "format": "int32"
862 | },
863 | "shipDate": {
864 | "type": "string",
865 | "format": "date-time"
866 | },
867 | "status": {
868 | "type": "string",
869 | "description": "Order Status",
870 | "enum": ["placed", "approved", "delivered"]
871 | },
872 | "complete": {
873 | "type": "boolean",
874 | "default": false
875 | }
876 | },
877 | "xml": {
878 | "name": "Order"
879 | }
880 | },
881 | "Category": {
882 | "type": "object",
883 | "properties": {
884 | "id": {
885 | "type": "integer",
886 | "format": "int64"
887 | },
888 | "name": {
889 | "type": "string"
890 | }
891 | },
892 | "xml": {
893 | "name": "Category"
894 | }
895 | },
896 | "User": {
897 | "type": "object",
898 | "properties": {
899 | "id": {
900 | "type": "integer",
901 | "format": "int64"
902 | },
903 | "username": {
904 | "type": "string"
905 | },
906 | "firstName": {
907 | "type": "string"
908 | },
909 | "lastName": {
910 | "type": "string"
911 | },
912 | "email": {
913 | "type": "string"
914 | },
915 | "password": {
916 | "type": "string"
917 | },
918 | "phone": {
919 | "type": "string"
920 | },
921 | "userStatus": {
922 | "type": "integer",
923 | "description": "User Status",
924 | "format": "int32"
925 | }
926 | },
927 | "xml": {
928 | "name": "User"
929 | }
930 | },
931 | "Tag": {
932 | "type": "object",
933 | "properties": {
934 | "id": {
935 | "type": "integer",
936 | "format": "int64"
937 | },
938 | "name": {
939 | "type": "string"
940 | }
941 | },
942 | "xml": {
943 | "name": "Tag"
944 | }
945 | },
946 | "Pet": {
947 | "required": ["name", "photoUrls"],
948 | "type": "object",
949 | "properties": {
950 | "id": {
951 | "type": "integer",
952 | "format": "int64"
953 | },
954 | "category": {
955 | "$ref": "#/components/schemas/Category"
956 | },
957 | "name": {
958 | "type": "string",
959 | "example": "doggie"
960 | },
961 | "photoUrls": {
962 | "type": "array",
963 | "xml": {
964 | "name": "photoUrl",
965 | "wrapped": true
966 | },
967 | "items": {
968 | "type": "string"
969 | }
970 | },
971 | "tags": {
972 | "type": "array",
973 | "xml": {
974 | "name": "tag",
975 | "wrapped": true
976 | },
977 | "items": {
978 | "$ref": "#/components/schemas/Tag"
979 | }
980 | },
981 | "status": {
982 | "type": "string",
983 | "description": "pet status in the store",
984 | "enum": ["available", "pending", "sold"]
985 | }
986 | },
987 | "xml": {
988 | "name": "Pet"
989 | }
990 | },
991 | "ApiResponse": {
992 | "type": "object",
993 | "properties": {
994 | "code": {
995 | "type": "integer",
996 | "format": "int32"
997 | },
998 | "type": {
999 | "type": "string"
1000 | },
1001 | "message": {
1002 | "type": "string"
1003 | }
1004 | }
1005 | }
1006 | },
1007 | "securitySchemes": {
1008 | "petstore_auth": {
1009 | "type": "oauth2",
1010 | "flows": {
1011 | "implicit": {
1012 | "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
1013 | "scopes": {
1014 | "write:pets": "modify pets in your account",
1015 | "read:pets": "read your pets"
1016 | }
1017 | }
1018 | }
1019 | },
1020 | "api_key": {
1021 | "type": "apiKey",
1022 | "name": "api_key",
1023 | "in": "header"
1024 | }
1025 | }
1026 | }
1027 | }
1028 |
--------------------------------------------------------------------------------
/test/swagger-allof.json:
--------------------------------------------------------------------------------
1 | {"basePath":"/","definitions":{"area.Area":{"properties":{"children":{"$ref":"#/definitions/area.Areas"},"id":{"type":"string"},"name":{"type":"string"},"pid":{"type":"string"},"type":{"type":"string"}},"type":"object"},"area.Areas":{"items":{"$ref":"#/definitions/area.Area"},"type":"array"},"model.AdminCommonArg":{"properties":{"id":{"description":"成员id","type":"string"}},"type":"object"},"model.AdminCreateArg":{"properties":{"name":{"description":"成员姓名","type":"string"},"number":{"description":"成员手机号","type":"string"},"organization_id":{"description":"成员所属机构","type":"string"},"role":{"description":"成员角色","type":"string"}},"type":"object"},"model.AdminCreateRet":{"properties":{"id":{"type":"string"},"password":{"type":"string"}},"type":"object"},"model.AdminInfo":{"properties":{"created_at":{"type":"string"},"enabled":{"type":"boolean"},"id":{"type":"string"},"name":{"type":"string"},"number":{"type":"string"},"organization":{"$ref":"#/definitions/model.OrganizationInfo"},"organization_id":{"type":"string"},"permissions":{"items":{"type":"string"},"type":"array"},"role":{"type":"string"},"updated_at":{"type":"string"},"visited_at":{"type":"string"}},"type":"object"},"model.AdminLoginArg":{"properties":{"number":{"description":"手机号","type":"string"},"password":{"description":"密码","type":"string"}},"type":"object"},"model.AdminPermission":{"properties":{"cate":{"type":"string"},"permissions":{"items":{"$ref":"#/definitions/model.Dict"},"type":"array"}},"type":"object"},"model.AdminSetPermissionsArg":{"properties":{"id":{"description":"成员id","type":"string"},"permissions":{"description":"成员权限","items":{"type":"string"},"type":"array"},"role":{"description":"成员角色","type":"string"}},"type":"object"},"model.AdminToggleArg":{"properties":{"enabled":{"description":"成员状态","type":"boolean"},"id":{"description":"成员id","type":"string"}},"type":"object"},"model.AdminUpdateArg":{"properties":{"id":{"description":"成员id","type":"string"},"name":{"description":"成员姓名","type":"string"},"number":{"description":"成员手机号","type":"string"}},"type":"object"},"model.Dict":{"properties":{"hidden":{"type":"boolean"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"model.OrganizationAllInfo":{"properties":{"children":{"items":{"$ref":"#/definitions/model.OrganizationAllInfo"},"type":"array"},"enabled":{"type":"boolean"},"id":{"type":"string"},"name":{"type":"string"},"pid":{"type":"string"}},"type":"object"},"model.OrganizationCommonArg":{"properties":{"id":{"description":"机构id","type":"string"}},"type":"object"},"model.OrganizationCreateArg":{"properties":{"address":{"description":"机构地址","type":"string"},"admin_name":{"description":"负责人姓名","type":"string"},"admin_number":{"description":"负责人手机号","type":"string"},"area":{"description":"机构地区","items":{"type":"string"},"type":"array"},"modules":{"description":"开通模块","items":{"type":"string"},"type":"array"},"name":{"description":"机构名称","type":"string"},"pid":{"description":"上级机构id","type":"string"},"type":{"description":"机构类别","type":"string"}},"type":"object"},"model.OrganizationCreateRet":{"properties":{"admin":{"$ref":"#/definitions/model.AdminCreateRet"},"id":{"type":"string"}},"type":"object"},"model.OrganizationInfo":{"properties":{"address":{"type":"string"},"area":{"items":{"type":"string"},"type":"array"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"id":{"type":"string"},"modules":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"pid":{"type":"string"},"type":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"model.OrganizationMoveArg":{"properties":{"id":{"description":"机构id","type":"string"},"pid":{"description":"上级机构id","type":"string"}},"type":"object"},"model.OrganizationToggleArg":{"properties":{"enabled":{"description":"机构状态","type":"boolean"},"id":{"description":"机构id","type":"string"}},"type":"object"},"model.OrganizationUpdateArg":{"properties":{"address":{"description":"机构地址","type":"string"},"area":{"description":"机构地区","items":{"type":"string"},"type":"array"},"id":{"description":"机构id","type":"string"},"modules":{"description":"开通模块","items":{"type":"string"},"type":"array"},"name":{"description":"机构名称","type":"string"},"type":{"description":"机构类别","type":"string"}},"type":"object"},"model.UtilDataRet":{"properties":{"admin_permissions":{"items":{"$ref":"#/definitions/model.AdminPermission"},"type":"array"},"admin_role_permissions":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"admin_roles":{"items":{"$ref":"#/definitions/model.Dict"},"type":"array"},"organization_modules":{"items":{"$ref":"#/definitions/model.Dict"},"type":"array"},"organization_types":{"items":{"$ref":"#/definitions/model.Dict"},"type":"array"}},"type":"object"},"response.Body":{"properties":{"code":{"type":"integer"},"data":{"type":"object"},"msg":{"type":"string"}},"type":"object"}},"host":"psp.wangritian.com","info":{"contact":{},"title":"社心平台测试服","version":"1.0.0"},"paths":{"/admin/admin/create":{"post":{"operationId":"admin_create","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminCreateArg"}}],"responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.AdminCreateRet"}},"type":"object"}]}}},"summary":"成员创建","tags":["成员管理"]}},"/admin/admin/info":{"post":{"operationId":"admin_info","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminCommonArg"}}],"responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.AdminInfo"}},"type":"object"}]}}},"summary":"成员信息","tags":["成员管理"]}},"/admin/admin/setPermissions":{"post":{"operationId":"admin_set_permissions","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminSetPermissionsArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"成员权限设置","tags":["成员管理"]}},"/admin/admin/toggle":{"post":{"operationId":"admin_toggle","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminToggleArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"启用/禁用成员","tags":["成员管理"]}},"/admin/admin/update":{"post":{"operationId":"admin_update","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminUpdateArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"成员编辑","tags":["成员管理"]}},"/admin/open/login":{"post":{"operationId":"open_login","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.AdminLoginArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"管理员登录","tags":["开放接口"]}},"/admin/organization/all":{"post":{"operationId":"organization_all","responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"items":{"$ref":"#/definitions/model.OrganizationAllInfo"},"type":"array"}},"type":"object"}]}}},"summary":"机构树形列表","tags":["机构管理"]}},"/admin/organization/create":{"post":{"operationId":"organization_create","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationCreateArg"}}],"responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.OrganizationCreateRet"}},"type":"object"}]}}},"summary":"机构创建","tags":["机构管理"]}},"/admin/organization/delete":{"post":{"operationId":"organization_delete","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationCommonArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"机构删除","tags":["机构管理"]}},"/admin/organization/info":{"post":{"operationId":"organization_info","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationCommonArg"}}],"responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.OrganizationInfo"}},"type":"object"}]}}},"summary":"机构详情","tags":["机构管理"]}},"/admin/organization/move":{"post":{"operationId":"organization_move","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationMoveArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"机构移动","tags":["机构管理"]}},"/admin/organization/toggle":{"post":{"operationId":"organization_toggle","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationToggleArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"机构启用/禁用","tags":["机构管理"]}},"/admin/organization/update":{"post":{"operationId":"organization_update","parameters":[{"description":"_","in":"body","name":"_","schema":{"$ref":"#/definitions/model.OrganizationUpdateArg"}}],"responses":{"200":{"description":"_","schema":{"$ref":"#/definitions/response.Body"}}},"summary":"机构编辑","tags":["机构管理"]}},"/admin/util/admin":{"post":{"operationId":"util_admin","responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.AdminInfo"}},"type":"object"}]}}},"summary":"登录信息","tags":["系统"]}},"/admin/util/area":{"post":{"operationId":"util_area","responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"items":{"$ref":"#/definitions/area.Area"},"type":"array"}},"type":"object"}]}}},"summary":"地区数据","tags":["系统"]}},"/admin/util/data":{"post":{"operationId":"util_data","responses":{"200":{"description":"_","schema":{"allOf":[{"$ref":"#/definitions/response.Body"},{"properties":{"data":{"$ref":"#/definitions/model.UtilDataRet"}},"type":"object"}]}}},"summary":"字典数据","tags":["系统"]}}},"swagger":"2.0"}
--------------------------------------------------------------------------------
/test/test-allof-api.json:
--------------------------------------------------------------------------------
1 | {
2 | "components": {
3 | "schemas": {
4 | "Batch": {
5 | "allOf": [
6 | {
7 | "$ref": "#/components/schemas/Response"
8 | },
9 | {
10 | "$ref": "#/components/schemas/Batch_allOf"
11 | }
12 | ]
13 | },
14 | "BatchList": {
15 | "allOf": [
16 | {
17 | "$ref": "#/components/schemas/Response"
18 | },
19 | {
20 | "properties": {
21 | "data": {
22 | "items": {
23 | "$ref": "#/components/schemas/Batch"
24 | },
25 | "type": "array"
26 | }
27 | },
28 | "type": "object"
29 | }
30 | ]
31 | },
32 | "Batch_allOf": {
33 | "properties": {
34 | "data": {
35 | "type": "object"
36 | }
37 | },
38 | "type": "object"
39 | },
40 | "Response": {
41 | "description": "所有API的返回数据,如果业务处理失败,success必然是false,\n如果业务处理成功,success为True,并添加data字段携带需要的数据\n",
42 | "properties": {
43 | "errorCode": {
44 | "description": "业务约定的错误码",
45 | "type": "string"
46 | },
47 | "errorMessage": {
48 | "description": "业务上的错误信息",
49 | "type": "string"
50 | },
51 | "success": {
52 | "description": "业务上的请求是否成功",
53 | "type": "boolean"
54 | }
55 | },
56 | "required": [
57 | "success"
58 | ],
59 | "type": "object"
60 | }
61 | }
62 | },
63 | "info": {
64 | "title": "Test allOf API",
65 | "version": "1.0.0"
66 | },
67 | "openapi": "3.0.1",
68 | "paths": {},
69 | "servers": [
70 | {
71 | "url": "http://localhost:1234/"
72 | }
73 | ]
74 | }
75 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const path = require('path');
3 | const fs = require('fs');
4 |
5 | const openAPI = require('../dist/index');
6 |
7 | const gen = async () => {
8 | await openAPI.generateService({
9 | schemaPath: `${__dirname}/example-files/swagger-empty.json`,
10 | serversPath: './servers/empty',
11 | });
12 |
13 | await openAPI.generateService({
14 | schemaPath: `${__dirname}/test-allof-api.json`,
15 | serversPath: './servers-allof',
16 | });
17 |
18 | await openAPI.generateService({
19 | schemaPath: `${__dirname}/example-files/swagger-get-method-params-convert-obj.json`,
20 | serversPath: './servers',
21 | });
22 |
23 | await openAPI.generateService({
24 | schemaPath: `${__dirname}/example-files/swagger-schema-contain-blank-symbol.json`,
25 | serversPath: './servers/blank-symbol-servers',
26 | });
27 |
28 | await openAPI.generateService({
29 | requestLibPath: "import request from '@/request';",
30 | schemaPath: `${__dirname}/example-files/swagger-custom-hook.json`,
31 | serversPath: './servers/custom',
32 | declareType: 'interface',
33 | hook: {
34 | // 自定义类名
35 | customClassName: (tagName) => {
36 | return /[A-Z].+/.exec(tagName);
37 | },
38 | // 自定义函数名
39 | customFunctionName: (data) => {
40 | let funName = data.operationId ? data.operationId : '';
41 | const suffix = 'Using';
42 | if (funName.indexOf(suffix) != -1) {
43 | funName = funName.substring(0, funName.lastIndexOf(suffix));
44 | }
45 | return funName;
46 | },
47 | // 自定义类型名
48 | customTypeName: (data) => {
49 | const { operationId } = data;
50 | const funName = operationId ? operationId[0].toUpperCase() + operationId.substring(1) : '';
51 | const tag = data?.tags?.[0];
52 |
53 | return `${tag ? tag : ''}${funName}`;
54 | },
55 | },
56 | });
57 |
58 | // 支持null类型作为默认值
59 | await openAPI.generateService({
60 | schemaPath: `${__dirname}/example-files/swagger-get-method-params-convert-obj.json`,
61 | serversPath: './servers/support-null',
62 | nullable: true,
63 | });
64 |
65 | // 正常命名文件和请求函数
66 | await openAPI.generateService({
67 | schemaPath: `${__dirname}/example-files/swagger-get-method-params-convert-obj.json`,
68 | serversPath: './servers/name/normal',
69 | isCamelCase: false,
70 | });
71 |
72 | // 小驼峰命名文件和请求函数
73 | await openAPI.generateService({
74 | schemaPath: `${__dirname}/example-files/swagger-get-method-params-convert-obj.json`,
75 | serversPath: './servers/name/camel-case',
76 | isCamelCase: true,
77 | });
78 |
79 | await openAPI.generateService({
80 | schemaPath: `${__dirname}/example-files/swagger-file-convert.json`,
81 | serversPath: './file-servers',
82 | });
83 |
84 | // check 文件生成
85 | const fileControllerStr = fs.readFileSync(
86 | path.join(__dirname, 'file-servers/api/fileController.ts'),
87 | 'utf8',
88 | );
89 | assert(fileControllerStr.indexOf('!(item instanceof File)') > 0);
90 | assert(fileControllerStr.indexOf(`requestType: 'form',`) > 0);
91 | assert(fileControllerStr.indexOf('Content-Type') < 0);
92 | // await openAPI.generateService({
93 | // // requestLibPath: "import request from '@/request';",
94 | // schemaPath: `http://82.157.33.9/swagger/swagger.json`,
95 | // serversPath: './servers',
96 | // });
97 | // await openAPI.generateService({
98 | // schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json',
99 | // serversPath: './servers',
100 | // mockFolder: './mocks',
101 | // });
102 | // await openAPI.generateService({
103 | // schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
104 | // serversPath: './servers',
105 | // mockFolder: './mocks',
106 | // });
107 | // await openAPI.generateService({
108 | // schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/LyDMjDyIhK/1611471979478-opa.json',
109 | // serversPath: './servers',
110 | // mockFolder: './mocks',
111 | // });
112 | // await openAPI.generateService({
113 | // schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/Zd7dLTHUjE/ant-design-pro.json',
114 | // serversPath: './servers',
115 | // mockFolder: './mocks',
116 | // });
117 | // await openAPI.generateService({
118 | // schemaPath: `${__dirname}/morse-api.json`,
119 | // serversPath: './servers',
120 | // mockFolder: './mocks',
121 | // });
122 | // await openAPI.generateService({
123 | // schemaPath: `${__dirname}/oc-swagger.json`,
124 | // serversPath: './servers',
125 | // mockFolder: './mocks',
126 | // });
127 | // await openAPI.generateService({
128 | // schemaPath: `${__dirname}/java-api.json`,
129 | // serversPath: './servers',
130 | // mockFolder: './mocks',
131 | // });
132 |
133 | await openAPI.generateService({
134 | schemaPath: `${__dirname}/example-files/apispec_1.json`,
135 | serversPath: './apispe',
136 | mockFolder: './mocks',
137 | mockConfig: {
138 | // msw: true,
139 | },
140 | });
141 | };
142 | gen();
143 |
--------------------------------------------------------------------------------
/test/test.locale.js:
--------------------------------------------------------------------------------
1 | const openAPI = require('../dist/index');
2 |
3 | openAPI.generateService({
4 | schemaPath: './openapi.json',
5 | serversPath: './servers',
6 | });
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "rootDir": "src",
4 | "outDir": "dist",
5 | "target": "ES2015",
6 | "module": "CommonJS",
7 | "moduleResolution": "node",
8 | "importHelpers": true,
9 | "esModuleInterop": true,
10 | "allowSyntheticDefaultImports": true,
11 | "skipLibCheck": true,
12 | "declaration": true
13 | },
14 | "include": ["src/**/*"],
15 | "exclude": ["node_modules", "lib", "es", "dist", "**/__tests__", "**/__test__", "**/demo"]
16 | }
17 |
--------------------------------------------------------------------------------