Coder Social home page Coder Social logo

openapi2typescript's Introduction

介绍

GitHub Repo stars npm (scoped) GitHub tag (latest SemVer pre-release)

根据 OpenApi3 文档生成 request 请求代码。

如果你使用 umi ,你可以使用@umijs/plugin-openapi 插件。

使用

npm i --save-dev @umijs/openapi

在项目根目录新建 openapi.config.ts

const { generateService } = require('@umijs/openapi')

generateService({
  schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
  serversPath: './servers',
})

package.jsonscript 中添加 api: "openapi": "ts-node openapi.config.ts",

生成api

npm run openapi

参数

属性 必填 备注 类型 默认值
requestLibPath 自定义请求方法路径 string -
requestOptionsType 自定义请求方法 options 参数类型 string {[key: string]: any}
requestImportStatement 自定义请求方法表达式 string -
apiPrefix api 的前缀 string -
serversPath 生成的文件夹的路径 string -
schemaPath Swagger 2.0 或 OpenAPI 3.0 的地址 string -
projectName 项目名称 string -
namespace 命名空间名称 string API
mockFolder mock目录 string -
enumStyle 枚举样式 string-literal | enum string-literal
nullable 使用null代替可选 boolean false
dataFields response中数据字段 string[] -
isCamelCase 小驼峰命名文件和请求函数 boolean true
hook 自定义 hook Custom Hook -

Custom Hook

属性 类型 说明
afterOpenApiDataInited (openAPIData: OpenAPIObject) => OpenAPIObject -
customFunctionName (data: OperationObject) => string 自定义请求方法路径
customTypeName (data: OperationObject) => string 自定义函数名称
customClassName (tagName: string) => string 自定义类型名称
customType (
schemaObject: SchemaObject | undefined,
namespace: string,
originGetType:(schemaObject: SchemaObject | undefined, namespace: string) => string,
) => string
自定义获取类型
返回非字符串将使用默认方法获取type
customFileNames (
operationObject: OperationObject,
apiPath: string,
_apiMethod: string,
) => string[]
自定义生成文件名,可返回多个,表示生成多个文件.
返回为空,则使用默认的获取方法获取

openapi2typescript's People

Contributors

adokevin avatar alioth1017 avatar bruceye2020 avatar buqiyuan avatar chen-kay avatar chenshuai2144 avatar citrusjunoss avatar creampnx-x avatar cui-xxu avatar daviyang35 avatar hlouis avatar huangjq148 avatar ianhash avatar kuaikaiyun avatar lampofaladdin avatar lifegit avatar liu-ya avatar liuyang-kevin avatar loulin avatar lovewinders avatar mazhaolin avatar monkeykingblack avatar neverstop1024 avatar rookie-luochao avatar scrapstation avatar slightc avatar stantoxt avatar thanhlcm90 avatar wilds avatar wkeylin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

openapi2typescript's Issues

multipart/form-data 类型的值都被 JSON.stringify, 无法上传文件

image
还有就是不用手动设置 content-type: multipart/form-data, 要不会会由于未包含 boundary 信息,导致上传失败(umijs/umi-request#118)
image
image

下面是复现的 swagger.json

{
  "openapi": "3.0.1",
  "info": {
    "title": "API Common",
    "description": "ASP.NET Core Web API Common",
    "version": "Common"
  },
  "paths": {
    "/api/CommonMicro/Uploader/Upload": {
      "post": {
        "tags": [
          "Uploader"
        ],
        "summary": "上传图片",
        "operationId": "Upload",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "BucketName": {
                    "type": "string"
                  },
                  "ObjectName": {
                    "type": "string"
                  }
                }
              },
              "encoding": {
                "BucketName": {
                  "style": "form"
                },
                "ObjectName": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/StringListResponseResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StringListResponseResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/StringListResponseResult"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "StringListResponseResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "请求是否成功"
          },
          "code": {
            "type": "integer",
            "description": "响应代码 200 为成功, 非200为失败,Message为失败原因",
            "format": "int32"
          },
          "message": {
            "type": "string",
            "description": "消息",
            "nullable": true
          },
          "data": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "返回实体",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "apiKey",
        "description": "JWT Authorization header using the Bearer scheme. \\r\\n\\r\\n \r\n                      Enter 'Bearer' [space] and then your token in the text input below.\r\n                      \\r\\n\\r\\nExample: 'Bearer 12345abcdef'",
        "name": "Authorization",
        "in": "header"
      }
    }
  },
  "security": [
    {
      "Bearer": [ ]
    }
  ]
}

生成 mock 出现堆栈溢出



> [email protected] openapi /Users/koofrank/Documents/projects/wanda-sa-h5
> vite-node openapi.config.ts

[openAPI]: ✅ 成功生成 service 文件
/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:98
        this.sampleFromSchema = (schema, propsName) => {
                                ^

RangeError: Maximum call stack size exceeded
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:98:33)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/[email protected]/node_modules/memoizee/lib/configure-map.js:61:24)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:135:35)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/[email protected]/node_modules/memoizee/lib/configure-map.js:61:24)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:119:38)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/[email protected]/node_modules/memoizee/lib/configure-map.js:61:24)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:135:35)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/[email protected]/node_modules/memoizee/lib/configure-map.js:61:24)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/@[email protected]/node_modules/@umijs/openapi/dist/openAPIParserMock/index.js:119:38)
    at OpenAPIGeneratorMockJs.sampleFromSchema (/Users/koofrank/Documents/projects/wanda-sa-h5/node_modules/.pnpm/[email protected]/node_modules/memoizee/lib/configure-map.js:61:24)
 ELIFECYCLE  Command failed with exit code 1.

文档请求参数如果在header中 转换是错误的.

        "parameters": [
          {
            "name": "tenantId",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "default": "tenant's Id"
          }
        ]

比如 请求中有一个参数是tenantId,该参数需要通过Header传递 ,但是生成的代理该参数不会包装到header去 而是query :(

[Bug] 1.4.4 升级后,allof数据模型生成问题

在1.3.10版本生在代码无问题,但升级1.4.4后

"OutSourceOrderVO": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CommonVO"
          },
          {
            "$ref": "#/components/schemas/FinishedGoodsInventoryOrderVO"
          }
        ],
        "description": "xx实体",
        "x-apifox-folder": "finishedGoodsInventory/outSourceOrder"
      },

1.3.10版本生生的代码

 type OutSourceOrderVO = CommonVO & FinishedGoodsInventoryOrderVO;

1.4.4版本生成的代码

 type OutSourceOrderVO = '' & FinishedGoodsInventoryOrderVO;

Validate config "openAPI" failed, "serversPath" is not allowed

设置 serversPath 後,运行 npm run openapi 报错:

PS > npm run openapi

> umi openapi

Validate config "openAPI" failed, "serversPath" is not allowed
ValidationError: "serversPath" is not allowed

.umirc.ts 内容:

import * as appconfig from './appconfig';

export default {
  openAPI: {
    requestLibPath: "import request from '../../utils/request'",
    schemaPath: `${appconfig.default.apiBaseURL}/api-json`,
    mock: false,
    serversPath: './services/',
  },
};

[Bug] Parameter 中引用无法解析

例如这样的配置

API中params使用引用

"parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],

引用的parameters定义
"ProjectId": {
        "in": "path",
        "name": "projectId",
        "schema": {
          "$ref": "#/components/schemas/ProjectId"
        },
        "required": true,
        "description": "project ID",
        "example": 1
      },

schemas定义
"ProjectId": {
        "type": "integer",
        "description": "项目ID",
        "example": 1
      },

但是最终生成的参数是,不符合预期

  type extendKeyWordParams = {
    ''?: any;
  };

在 getSchema 方法中对本地文件使用 require 加载会在文件更新后,无法获取新的文件内容

export const getSchema = async (schemaPath: string) => {
  if (schemaPath.startsWith('http')) {
    ...
  }
  const schema = require(schemaPath);
  return schema;
};

https://github.com/chenshuai2144/openapi2typescript/blob/b035170d8c5a6bea14616a87e1d7ce7b1390440a/src/index.ts#LL114C18-L114C25

如题,我在使用 getSchema 对本地文件的 json 进行加载时,由于存在轮询刷新该文件的逻辑,但是一直获取的都是第一次的内容。

新版本v1.4.1无法正常生成接口文件

报错信息:
image

openapi.json
{ "openapi": "3.0.1", "info": { "title": "酒店", "description": "", "version": "1.0.0" }, "tags": [ { "name": "用户" }, { "name": "系统" } ], "paths": { "/api/login": { "get": { "summary": "登录", "x-apifox-folder": "用户", "x-apifox-status": "developing", "deprecated": false, "description": "", "tags": [ "用户" ], "parameters": [], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "data": { "type": "object", "properties": { "status": { "type": "string", "description": "ok为成功" }, "token": { "type": "string" }, "config": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" } }, "required": [ "name" ] } }, "currentUser": { "type": "object", "properties": { "user_type": { "type": "string", "description": "0为管理员" }, "shift": { "type": "string" }, "shiftName": { "type": "string" }, "hotelCode": { "type": "string" } }, "required": [ "user_type", "shift", "shiftName", "hotelCode" ] } }, "required": [ "status", "currentUser", "token", "config" ] } }, "required": [ "code", "data", "message" ] }, "examples": {} } } } } } }, "/api/sys/shift": { "get": { "summary": "班次", "x-apifox-folder": "系统", "x-apifox-status": "developing", "deprecated": false, "description": "", "tags": [ "系统" ], "parameters": [], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "string" }, "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "description": { "type": "string" } }, "required": [ "id", "description" ] } } }, "required": [ "code", "data" ] }, "examples": {} } } } } } } }, "components": { "schemas": {} } }

[bug] 模板生成部分数据异常

在测试示例中

const { generateService } = require('@umijs/openapi')

generateService({
    requestLibPath: "import { Request as request } from 'umi'",
    schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
    serversPath: './servers',
})

生成的数据有部分异常

错误的添加了部分header参数

pet.ts Line:166
image

此处添加了多余的header参数,并且没有使用&{ } 进行包裹

部分空白字符没有处理好

pet.ts Line:125
image

模板中部分 - 控制空白字符没有正确添加

生成的api文件中的请求方法第一个参数必定是params,即使没有定义path参数和query参数

if (path && path.length > 0) {
var regex = /\{(\w+)\}/g;
templateParams['path'] = templateParams['path'] || [];
let match = null;
while (match = regex.exec(path)) {
if (!templateParams['path'].some(p => p.name === match[1])) {
templateParams['path'].push({
...DEFAULT_PATH_PARAM,
name: match[1]
})
}
}
}

这个if执行完后,即使url上没有path参数,也会给templateParams对象添加path属性
导致
const allParams = this.getParamsTP(newApi.parameters, newApi.path);

拿到的结果是{path:[]}这样的
使得
return {
...newApi,
functionName,
path: getPrefixPath(),
pathInComment: formattedPath.replace(/\*/g, '*'),
hasPathVariables: formattedPath.includes('{'),
hasApiPrefix: !!this.config.apiPrefix,
method: newApi.method,
// 如果 functionName 和 summary 相同,则不显示 summary
desc:
functionName === newApi.summary
? newApi.description
: [newApi.summary, newApi.description].filter((s) => s).join(' '),
hasHeader: !!(params && params.header) || !!(body && body.mediaType),
params: finalParams,
hasParams: Boolean(Object.keys(finalParams || {}).length),
body,
file,
hasFormData: formData,
response,
};

中hasParams的值Boolean(Object.keys(finalParams || {}).length)最小为1
最终导致生成的api文件的请求方法参数中必定会有个params参数
export async function {{ api.functionName }}(
{%- if api.params and api.hasParams %}
params
{%- if genType === "ts" -%}
: {
{# query 入参 -#}
{% if api.params.query -%}
// query
{% for param in api.params.query -%}
{% if param.description -%}
/** {{ param.description }} */
{% endif -%}
'{{ param.name }}'
{{- "?" if not param.required }}
{{- (": " + param.type + ";") | safe }}
{% endfor -%}
{% endif -%}
{# header 入参 -#}
{% if api.params.header -%}
// header
{% for param in api.params.header -%}
{% if param.description -%}
/** {{ param.description }} */
{% endif -%}
'{{ param.name }}'
{{- "?" if not param.required }}
{{- (": " + param.type + ";") | safe }}
{% endfor -%}
{% endif -%}
{# path 入参 -#}
{% if api.params.path -%}
// path
{% for param in api.params.path -%}
{% if param.description -%}
/** {{ param.description }} */
{% endif -%}
'{{ param.name }}'
{{- "?" if not param.required }}
{{- (": " + param.type + ";") | safe }}
{% endfor -%}
{% endif -%}
}
{%- endif -%}
{%- if api.hasParams %}
{{ "," if api.body or api.file}}
{%- endif %}
{%- endif -%}

openapi 不能生成嵌套的结构(没有报错

"@umijs/plugin-openapi": "^1.3.3"

我使用openapi 生成接口的时候,我服务端model是结构性的
type ArticleItem struct {
CollectedData * ArticleCollectedData

ArticleFormData * ArticleFormData
Highlight map[string]*HighlightItem
}
我预期生成一个也是结构性的结构比如
type ArticleItem = {
article_form_data?: ArticleFormData;
collected_data?: ArticleCollectedData;
};

但是通过plugin-openapi生成接口的时候,ArticleItem 结构只得到了 type ArticleItem = ArticleFormData,并没有生成嵌套的结构声明;
执行npm run openapi 命令显示生成成功,并没有报错。我把代码回滚到了老的版本也不行。不知道是不是哪个依赖的变动导致了这个问题

下面是我用openapi生成的typing.d.ts 文件和swagger.json 的结构
`
type ArticleFormData = {
/** 摘要 /
abstract?: string;
/* 分类列表 /
category?: string[];
/* 清理格式后的内容 /
clean_content?: string;
/* content 内容 /
content?: string;
/* 编辑器类型 /
editor?: number;
/* 题材 /
genre?: number;
/* id /
id?: number;
logo?: string;
/* 是否转载 /
reship_url?: string;
source?: number;
/* 标签列表 /
tags?: string[];
/* 文章标题 */
title?: string;
user_name?: string;
};

type ArticleItem = ArticleFormData;`

swagger.json 的model
`
{
"swagger": "2.0",
"info": {
"contact": {}
},
"paths": {

"/article/detail": {
    "get": {
        "description": "根据id获取文章",
        "consumes": [
            "application/json"
        ],
        "produces": [
            "application/json"
        ],
        "tags": [
            "article"
        ],
        "summary": "根据id获取文章",
        "parameters": [
            {
                "type": "integer",
                "description": " ID",
                "name": "id",
                "in": "query",
                "required": true
            }
        ],
        "responses": {
            "200": {
                "description": "OK",
                "schema": {
                    "$ref": "#/definitions/model.ArticleItem"
                }
            },
            "500": {
                "description": "Internal Server Error",
                "schema": {
                    "$ref": "#/definitions/model.ArticleItem"
                }
            }
        }
    }
},

"model.ArticleCollectedData": {
    "type": "object",
    "properties": {
       
        "body": {
            "type": "string"
        }
    }
},
"model.ArticleFormData": {
    "type": "object",
    "properties": {
        "category": {
            "description": "分类列表",
            "type": "array",
            "items": {
                "type": "string"
            }
        }
    }
},
"model.ArticleItem": {
    "type": "object",
    "properties": {
        "article_form_data": {
            "description": "提交的变量",
            "$ref": "#/definitions/model.ArticleFormData"
            
        },
        "collected_data": {
            "$ref": "#/definitions/model.ArticleCollectedData"
            
        },
        "highlight": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/model.HighlightItem"
            }
        }
    }
},

"model.HighlightItem": {
    "type": "object",
    "properties": {
        "pos": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/model.PosItem"
            }
        },
        "rich_text": {
            "type": "string"
        },
        "text": {
            "type": "string"
        }
    }
}

}
}`

为什么生成的全是可选属性

我在后端已经区分了Nullable,并且生成了正确的openapi json
image

但生成的TS type propertity全是可选的
image

缺点:调用登录接口的时候,无法提示params.mobile是必传的,
image

[BUG] Generate array of enums

Wrong generation for array of enums type

Actual generation:
language: 'en' | 'vi'[]

Expect generation:
language: ('en' | 'vi')[]

[1.4.3] enum 会被转化为 Record

  "apiLoginType": {
      "type": "integer",
      "format": "int32",
      "enum": [0, 1],
      "default": "0",
      "title": "- 0: 企业内部应用免登\n - 1: 第三方应用扫码登陆"
    },

会被转化为Record<string,any>
应该是0|1才对
1.4.0版本是没这个问题的

指定 customClassName 之后,生成的index.ts import和export错误

指定 customClassName 之后,生成的index.ts import和export 还是默认的生成方式,没有使用 自定义的className,但是自定义ClassName之后的文件名称已经是自定义的;

问题代码在:
openapi2typescript/src/serviceGenerator.ts

line 505-514

 if (genParams.length) {
          this.classNameList.push({
            fileName,
            controllerName: fileName,
          });
        }
        let className = fileName;
        if (this.config.hook && this.config.hook.customClassName) {
          className = this.config.hook.customClassName(tag);
        }

关于getType函数,默认返回类型any修改为unknown的建议

最近在弄hook,想解构类型,发现分析器被any类型阻断了,是不是改成unknown更为合理

  type Response = {
    code?: number;
    data?: unknown; // 生成any情形下, 下面hook的类型分析,就会被阻断
    msg?: string;
  };

/** 获取当前登录账号信息 GET /admin/login */
export async function LogInfo(options?: { [key: string]: any }) {
  return request<API.Response & { data?: API.AdminInfo }>('/admin/login', {
    method: 'GET',
    ...(options || {}),
  });
}

export function usePSP2<R extends (() => Promise<Awaited<ReturnType<R>>>)>(req: R) {
  type PSPBody = Awaited<ReturnType<R>>;
  type DataOf<T> = T extends { data?: infer E } ? E : never; // 这里就无法分析到正确的类型
  const [isLoading, setLoading] = useState(true);
  const [body, setBody] = useState<PSPBody>();
  const [data, setData] = useState<DataOf<PSPBody>>();

  req().then(_body => {
    setBody(_body)
  });
  return {
    isLoading,
    body,
    data,
  };
}

const { body, data } = usePSP2(wj.psp.LogInfo);  // 生成any情形下,这里data就无法分析到正确的类型,unknown是可以的

HTTP方法没有body,只有params时,生成类型的问题。

我们发现swagger.json生成的时候,没有对params等参数生成描述。所以转换的时候直接转换为dict类型。

是否可以修改为,直接根据函数名强行生成对应的类型结构,并融合到模版当中

项目比较忙,所以直接改到能满足个人需求了,但是位置不是很好,入侵性比较强。提了pr。

#21

Multipart encoding not taken into account

Hi,

I having a Spring Boot application where I have a REST endpoint that consumes "multipart/form-data". The endpoint expects two file parts, the userData of type "application/json" and a profile picture of type image. Unfortunately, the openapi generator ignores the encoding of userData which leads to a HTTP 415 error in Spring. I would expect that the generator produces something like

formData.append('userData', new Blob([
       jsonPayload
   ], {
       type: "application/json"
   }));

Here's a snipptet of my swagger defintion.

"requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "userData"
                ],
                "type": "object",
                "properties": {
                  "userData": {
                    "$ref": "#/components/schemas/UserWithPasswordData"
                  },
                  "profilePicture": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "userData": {
                  "contentType": "application/json"
                }
              }
            }
          }
        },

[Bug] type.props.length === 1时,结构错误

refundTransaction只有一个属性status,生成类型文件时,status没了

{
  "id": "string",
  "refundTransaction": {
    "status": "Success"
  }
}
  type GetRefundDetailResponse = {
    id?: string;
    refundTransaction?: RefundTransactionOfTypesOfGetRefundDetailResponse;
  };

  type RefundTransactionOfTypesOfGetRefundDetailResponse = StatusEnumOfRefundTenpay;

  type StatusEnumOfRefundTenpay = 'Success' | 'Closed' | 'Processing' | 'Abnormal';

跟源码模板这个if有关系

{%- if (prop[0].$ref !== undefined) and (prop | length === 1) %}

没看懂这个if在处理什么情况

YAPI 导出的 Swagger 2.0 json 不支持

能否升级支持 YAPI 导出的 Swagger 2.0 版本 json文件呢。

当前主要问题是生成出来的 json 没有 components 段,响应的定义是直接在 paths 接口段中定义的。

> umi openapi
[openAPI]: 💺 将 Swagger 转化为 openAPI
/Users/davi/myapp/node_modules/@umijs/openapi/dist/serviceGenerator.js:560
                    data.push([
                         ^

TypeError: Cannot read properties of undefined (reading 'push')
    at /Users/davi/myapp/node_modules/@umijs/openapi/dist/serviceGenerator.js:560:26
    at Array.forEach (<anonymous>)
    at /Users/davi/myapp/node_modules/@umijs/openapi/dist/serviceGenerator.js:525:55

operationId 是哪里来的

: this.resolveFunctionName(stripDot(newApi.operationId), newApi.method);

使用的时候我的newApi里 没有operationId
{ path: '/api/Employee_Privilege_Auth/Delete/{id}', method: 'delete', tags: [ 'Employee_Privilege_Auth' ], summary: ' (Auth)', parameters: [ { name: 'id', in: 'path', required: true, schema: [Object] } ], responses: { '200': { description: 'Success', content: [Object] }, '401': { description: 'Unauthorized' }, '403': { description: 'Forbidden' } }, security: [ { oauth2: [] } ] }

paths.tags contain /

paths.tags 存在以下情况 :

  1. "tags" : [ "user" ]
  2. "tags" : [ "user/pack/测试" ]
  3. "tags" : [ "user/pack/news" ]
  4. "tags" : [ "用户" ]

结果

$ umi openapi

image

  1. user
    没有修改
  2. userpackceshi
    删除 / 并且拼音
  3. userpacknews
    删除 /
  4. 用户
    没有修改

accident
2. 太长,不友好
4. 标签为中文且不存在\,结果文件名为中文

希望

  1. pinyin
  2. const list = tags.split("/")
  3. const res = list[list.length-1]

结果

  1. user
  2. ceshi
  3. news
  4. yonghu

allOf 生成类型声明有问题

版本号:1.7.1
测试Yaml:

{
  "components": {
    "schemas": {
      "Batch": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Response"
          },
          {
            "$ref": "#/components/schemas/Batch_allOf"
          }
        ]
      },
      "BatchList": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Response"
          },
          {
            "properties": {
              "data": {
                "items": {
                  "$ref": "#/components/schemas/Batch"
                },
                "type": "array"
              }
            },
            "type": "object"
          }
        ]
      },
      "Batch_allOf": {
        "properties": {
          "data": {
            "type": "object"
          }
        },
        "type": "object"
      },
      "Response": {
        "description": "所有API的返回数据,如果业务处理失败,success必然是false,\n如果业务处理成功,success为True,并添加data字段携带需要的数据\n",
        "properties": {
          "errorCode": {
            "description": "业务约定的错误码",
            "type": "string"
          },
          "errorMessage": {
            "description": "业务上的错误信息",
            "type": "string"
          },
          "success": {
            "description": "业务上的请求是否成功",
            "type": "boolean"
          }
        },
        "required": [
          "success"
        ],
        "type": "object"
      }
    }
  },
  "info": {
    "title": "NSFW Account API",
    "version": "1.0.0"
  },
  "openapi": "3.0.1",
  "paths": {},
  "servers": [
    {
      "url": "http://localhost:1234/"
    }
  ]
}

测试代码

  await openAPI.generateService({
    schemaPath: `${__dirname}/nsfw-api.json`,
    serversPath: './servers-nsfw',
  })

输出的typings.d.ts内容

declare namespace API {
  type Batch = {
    ''?: Response;
  } & {
    ''?: BatchAllOf;
  };

  type BatchAllOf = {
    data?: Record<string, any>;
  };

  type BatchList = {
    ''?: Response;
  } & {
    data?: Batch[];
  };

  type Response = {
    /** 业务约定的错误码 */
    errorCode?: string;
    /** 业务上的错误信息 */
    errorMessage?: string;
    /** 业务上的请求是否成功 */
    success: boolean;
  };
}

期望的内容

declare namespace API {
  type Batch = Response & BatchAllOf;

  type BatchAllOf = {
    data?: Record<string, any>;
  };

  type BatchList = Response & {
    data?: Batch[];
  };

  type Response = {
    /** 业务约定的错误码 */
    errorCode?: string;
    /** 业务上的错误信息 */
    errorMessage?: string;
    /** 业务上的请求是否成功 */
    success: boolean;
  };
}

🐛[BUG] mediaType 为application/x-www-form-urlencoded时, 是否可以不生成Content-Type

🐛 bug 描述
使用openapi生成FormData的请求时生成以下代码

/** 登录认证 POST /login */
export async function loginAccessTokenLoginPost(
  body: API.BodyLoginAccessTokenLoginPost,
  options?: { [key: string]: any },
) {
  const formData = new FormData();

  Object.keys(body).forEach((ele) => {
    const item = (body as any)[ele];

    if (item !== undefined && item !== null) {
      formData.append(
        ele,
        typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item,
      );
    }
  });

  return request<API.LoginType>(`/api/v1/login`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    data: formData,
    ...(options || {}),
  });
}

umi-request 构建 FormData 时,会自动构建Content-Type,添加该项会导致接口错误

apiPrefix的使用问题

  1. apiPrefix的类型为字符串,但是需要是嵌套的字符串('"api"')才能生效,如果只是单纯的字符串('api'),则会变成${api}的形式,这个是故意设计成这样的吗?感觉很怪
    代码行
  2. README文件中apiPrefix的支持类型只写了string,但是实际还支持方法,是为了引导用户更多使用string故意不暴露还是遗漏了代码行

Get请求中如果query方式参数生成问题

你好,发现有一个问题,
Get请求中如果query方式参数,如果operationId 生成的生typings.d.ts生在问题
下面是open api

{
  "openapi": "3.0.1",
  "info": {
    "title": "tcbj-store-open-api",
    "description": "",
    "version": "1.0.0"
  },
  "tags": [
    {
      "name": "commodityCenter"
    },
    {
      "name": "inventoryCenter"
    },
    {
      "name": "inventoryCenter/warehouseManage"
    },
    {
      "name": "inventoryCenter/warehouseManage/physical"
    },
    {
      "name": "inventoryCenter/warehouseManage/logic"
    }
  ],
  "paths": {
    "/inventoryCenter/warehouseManage/physical": {
      "get": {
        "summary": "物理仓列表",
        "x-apifox-folder": "inventoryCenter/warehouseManage/physical",
        "x-apifox-status": "designing",
        "deprecated": false,
        "description": "",
        "tags": ["inventoryCenter/warehouseManage/physical"],
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "description": "xx",
            "required": true,
            "style": "form",
            "explode": true,
            "example": "10",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageNum",
            "in": "query",
            "description": "xxx",
            "style": "form",
            "explode": true,
            "required": true,
            "example": "1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "endRow": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "isFirstPage": {
                          "type": "boolean"
                        },
                        "isLastPage": {
                          "type": "boolean"
                        },
                        "list": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PhysicalItem"
                          }
                        },
                        "navigateFirstPage": {
                          "type": "integer"
                        },
                        "navigateLastPage": {
                          "type": "integer"
                        },
                        "navigatePages": {
                          "type": "integer"
                        },
                        "navigatepageNums": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "nextPage": {
                          "type": "integer"
                        },
                        "pageNum": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "pages": {
                          "type": "integer"
                        },
                        "prePage": {
                          "type": "integer"
                        },
                        "size": {
                          "type": "integer"
                        },
                        "startRow": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "endRow",
                        "hasNextPage",
                        "hasPreviousPage",
                        "isFirstPage",
                        "isLastPage",
                        "list",
                        "navigateFirstPage",
                        "navigateLastPage",
                        "navigatePages",
                        "navigatepageNums",
                        "nextPage",
                        "pageNum",
                        "pageSize",
                        "pages",
                        "prePage",
                        "size",
                        "startRow",
                        "total"
                      ]
                    },
                    "exceptCauseApp": {
                      "type": "null"
                    },
                    "exceptCauseIp": {
                      "type": "null"
                    },
                    "exceptClass": {
                      "type": "null"
                    },
                    "extFields": {
                      "type": "object",
                      "properties": {}
                    },
                    "resultCode": {
                      "type": "string"
                    },
                    "resultMsg": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "exceptCauseApp",
                    "exceptCauseIp",
                    "exceptClass",
                    "extFields",
                    "resultCode",
                    "resultMsg"
                  ]
                },
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "新建物理仓库",
        "x-apifox-folder": "inventoryCenter/warehouseManage/physical",
        "x-apifox-status": "designing",
        "deprecated": false,
        "description": "",
        "tags": ["inventoryCenter/warehouseManage/physical"],
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhysicalItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "null"
                    },
                    "exceptCauseApp": {
                      "type": "string"
                    },
                    "exceptCauseIp": {
                      "type": "string"
                    },
                    "exceptClass": {
                      "type": "string"
                    },
                    "extFields": {
                      "type": "string"
                    },
                    "resultCode": {
                      "type": "integer"
                    },
                    "resultMsg": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "exceptCauseApp",
                    "exceptCauseIp",
                    "exceptClass",
                    "extFields",
                    "resultCode",
                    "resultMsg"
                  ]
                },
                "examples": {}
              }
            }
          }
        }
      },
      "put": {
        "summary": "更新物理仓库",
        "x-apifox-folder": "inventoryCenter/warehouseManage/physical",
        "x-apifox-status": "designing",
        "deprecated": false,
        "description": "",
        "tags": ["inventoryCenter/warehouseManage/physical"],
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhysicalItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {}
                    },
                    "exceptCauseApp": {
                      "type": "string"
                    },
                    "exceptCauseIp": {
                      "type": "string"
                    },
                    "exceptClass": {
                      "type": "string"
                    },
                    "extFields": {
                      "type": "object",
                      "properties": {}
                    },
                    "resultCode": {
                      "type": "integer"
                    },
                    "resultMsg": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "exceptCauseApp",
                    "exceptCauseIp",
                    "exceptClass",
                    "extFields",
                    "resultCode",
                    "resultMsg"
                  ]
                },
                "examples": {}
              }
            }
          }
        }
      }
    },
    "/inventoryCenter/warehouseManage/logic": {
      "get": {
        "summary": "逻辑仓列表",
        "x-apifox-folder": "inventoryCenter/warehouseManage/logic",
        "x-apifox-status": "designing",
        "deprecated": false,
        "description": "",
        "tags": ["inventoryCenter/warehouseManage/logic"],
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "description": "",
            "required": true,
            "example": "20",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "currentPage",
            "in": "query",
            "description": "",
            "required": true,
            "example": "1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "endRow": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "isFirstPage": {
                          "type": "boolean"
                        },
                        "isLastPage": {
                          "type": "boolean"
                        },
                        "list": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "brandFactory": {
                                "type": "string"
                              },
                              "channelType": {
                                "type": "string"
                              },
                              "channelTypeStr": {
                                "type": "string"
                              },
                              "realWarehouseCode": {
                                "type": "integer"
                              },
                              "createTime": {
                                "type": "string"
                              },
                              "modifyTime": {
                                "type": "string"
                              },
                              "id": {
                                "type": "string"
                              },
                              "modifyUserId": {
                                "type": "string"
                              },
                              "createUserId": {
                                "type": "string"
                              },
                              "modifyUserName": {
                                "type": "string"
                              },
                              "realWarehouseName": {
                                "type": "string"
                              },
                              "realWarehouseStatus": {
                                "type": "integer"
                              },
                              "realWarehouseStatusName": {
                                "type": "string"
                              },
                              "realWarehouseTypeName": {
                                "type": "string"
                              },
                              "stockTagName": {
                                "type": "string"
                              },
                              "realWarehouseType": {
                                "type": "string"
                              },
                              "storageLocation": {
                                "type": "string"
                              },
                              "tag": {
                                "type": "string"
                              },
                              "tagName": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "navigateFirstPage": {
                          "type": "integer"
                        },
                        "navigateLastPage": {
                          "type": "integer"
                        },
                        "navigatePages": {
                          "type": "integer"
                        },
                        "navigatepageNums": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "nextPage": {
                          "type": "integer"
                        },
                        "pageNum": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "pages": {
                          "type": "integer"
                        },
                        "prePage": {
                          "type": "integer"
                        },
                        "size": {
                          "type": "integer"
                        },
                        "startRow": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "endRow",
                        "hasNextPage",
                        "hasPreviousPage",
                        "isFirstPage",
                        "isLastPage",
                        "list",
                        "navigateFirstPage",
                        "navigateLastPage",
                        "navigatePages",
                        "navigatepageNums",
                        "nextPage",
                        "pageNum",
                        "pageSize",
                        "pages",
                        "prePage",
                        "size",
                        "startRow",
                        "total"
                      ]
                    },
                    "exceptCauseApp": {
                      "type": "null"
                    },
                    "exceptCauseIp": {
                      "type": "null"
                    },
                    "exceptClass": {
                      "type": "null"
                    },
                    "extFields": {
                      "type": "null"
                    },
                    "resultCode": {
                      "type": "string"
                    },
                    "resultMsg": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "exceptCauseApp",
                    "exceptCauseIp",
                    "exceptClass",
                    "extFields",
                    "resultCode",
                    "resultMsg"
                  ]
                },
                "examples": {
                  "1": {
                    "summary": "示例",
                    "value": "{\r\n    \"data\": {\r\n        \"endRow\": 96,\r\n        \"hasNextPage\": false,\r\n        \"hasPreviousPage\": true,\r\n        \"isFirstPage\": false,\r\n        \"isLastPage\": false,\r\n        \"list\": [\r\n            {\r\n                \"brandFactory\": \"6056\",\r\n                \"channelType\": \"20\",\r\n                \"channelTypeStr\": \"联营\",\r\n                \"realWarehouseCode\": 60561000,\r\n                \"createTime\": \"2013-07-14 17:07:11\",\r\n                \"modifyTime\": \"2010-01-11 09:46:03\",\r\n                \"id\": \"65\",\r\n                \"modifyUserId\": \"43\",\r\n                \"createUserId\": \"30\",\r\n                \"modifyUserName\": \"管理员\",\r\n                \"realWarehouseName\": \"贵阳杉杉奥特莱斯K\",\r\n                \"realWarehouseStatus\": 1,\r\n                \"realWarehouseStatusName\": \"启用\",\r\n                \"realWarehouseTypeName\": \"联营门店A版-商场回款\",\r\n                \"stockTagName\": \"联营门店仓\",\r\n                \"realWarehouseType\": \"12\",\r\n                \"storageLocation\": \"1000\",\r\n                \"tag\": \"店\",\r\n                \"tagName\": \"D\",\r\n            }\r\n        ],\r\n        \"navigateFirstPage\": 24,\r\n        \"navigateLastPage\": 93,\r\n        \"navigatePages\": 79,\r\n        \"navigatepageNums\": [\r\n            \"53\",\r\n            \"61\",\r\n            \"93\",\r\n            \"68\",\r\n            \"36\"\r\n        ],\r\n        \"nextPage\": 92,\r\n        \"pageNum\": 35,\r\n        \"pageSize\": 96,\r\n        \"pages\": 46,\r\n        \"prePage\": 6,\r\n        \"size\": 65,\r\n        \"startRow\": 55,\r\n        \"total\": 14\r\n    },\r\n    \"exceptCauseApp\": null,\r\n    \"exceptCauseIp\": null,\r\n    \"exceptClass\": null,\r\n    \"extFields\": null,\r\n    \"resultCode\": \"82\",\r\n    \"resultMsg\": \"magna sit\"\r\n}"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/inventoryCenter/warehouseManage/physical/{id}": {
      "get": {
        "summary": "查询物理仓库详情",
        "x-apifox-folder": "inventoryCenter/warehouseManage/physical",
        "x-apifox-status": "designing",
        "deprecated": false,
        "description": "",
        "operationId": "getPhysicalById",
        "tags": ["inventoryCenter/warehouseManage/physical"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PhysicalItem"
                    },
                    "exceptCauseApp": {
                      "type": "string"
                    },
                    "exceptCauseIp": {
                      "type": "string"
                    },
                    "exceptClass": {
                      "type": "string"
                    },
                    "extFields": {
                      "type": "object",
                      "properties": {}
                    },
                    "resultCode": {
                      "type": "string"
                    },
                    "resultMsg": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "data",
                    "exceptCauseApp",
                    "exceptCauseIp",
                    "exceptClass",
                    "extFields",
                    "resultCode",
                    "resultMsg"
                  ]
                },
                "examples": {}
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "PhysicalItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "physicalWarehouseCode": {
            "type": "string"
          },
          "physicalWarehouseName": {
            "type": "string"
          },
          "physicalWarehouseType": {
            "type": "string"
          },
          "physicalWarehouseStatus": {
            "type": "string",
            "enum": ["NW", "NE", "SW", "SE"]
          },
          "createUserId": {
            "type": "string"
          },
          "createUserName": {
            "type": "string"
          },
          "createTime": {
            "type": "string"
          },
          "modifyUserId": {
            "type": "string"
          },
          "modifyUserName": {
            "type": "string"
          },
          "modifyTime": {
            "type": "string"
          }
        },
        "required": [
          "physicalWarehouseCode",
          "physicalWarehouseName",
          "physicalWarehouseType",
          "physicalWarehouseStatus"
        ],
        "x-apifox-folder": "inventoryCenter/warehouseManage"
      },
      "CommonListPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "endRow": {
                "type": "integer"
              },
              "hasNextPage": {
                "type": "boolean"
              },
              "hasPreviousPage": {
                "type": "boolean"
              },
              "isFirstPage": {
                "type": "boolean"
              },
              "isLastPage": {
                "type": "boolean"
              },
              "list": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {}
                }
              },
              "navigateFirstPage": {
                "type": "integer"
              },
              "navigateLastPage": {
                "type": "integer"
              },
              "navigatePages": {
                "type": "integer"
              },
              "navigatepageNums": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "nextPage": {
                "type": "integer"
              },
              "pageNum": {
                "type": "integer"
              },
              "pageSize": {
                "type": "integer"
              },
              "pages": {
                "type": "integer"
              },
              "prePage": {
                "type": "integer"
              },
              "size": {
                "type": "integer"
              },
              "startRow": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            },
            "required": [
              "endRow",
              "hasNextPage",
              "hasPreviousPage",
              "isFirstPage",
              "isLastPage",
              "list",
              "navigateFirstPage",
              "navigateLastPage",
              "navigatePages",
              "navigatepageNums",
              "nextPage",
              "pageNum",
              "pageSize",
              "pages",
              "prePage",
              "size",
              "startRow",
              "total"
            ]
          },
          "exceptCauseApp": {
            "type": "string"
          },
          "exceptCauseIp": {
            "type": "string"
          },
          "exceptClass": {
            "type": "string"
          },
          "extFields": {
            "type": "object",
            "properties": {}
          },
          "resultCode": {
            "type": "string"
          },
          "resultMsg": {
            "type": "string"
          }
        },
        "required": [
          "data",
          "exceptCauseApp",
          "exceptCauseIp",
          "exceptClass",
          "extFields",
          "resultCode",
          "resultMsg"
        ],
        "x-apifox-folder": "Common"
      },
      "CommonResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "string"
          },
          "exceptCauseApp": {
            "type": "string"
          },
          "exceptCauseIp": {
            "type": "string"
          },
          "exceptClass": {
            "type": "string"
          },
          "extFields": {
            "type": "object",
            "properties": {}
          },
          "resultCode": {
            "type": "string"
          },
          "resultMsg": {
            "type": "string"
          }
        },
        "required": [
          "data",
          "exceptCauseApp",
          "exceptCauseIp",
          "exceptClass",
          "extFields",
          "resultCode",
          "resultMsg"
        ],
        "x-apifox-folder": "Common"
      }
    }
  }
}

生成的typings.d.ts 其中,undefinedParams

declare namespace API {
  type PhysicalItem = {
    id?: string;
    physicalWarehouseCode: string;
    physicalWarehouseName: string;
    physicalWarehouseType: string;
    physicalWarehouseStatus: 'NW' | 'NE' | 'SW' | 'SE';
    createUserId?: string;
    createUserName?: string;
    createTime?: string;
    modifyUserId?: string;
    modifyUserName?: string;
    modifyTime?: string;
  };

  type CommonListPage = {
    data: {
      endRow?: number;
      hasNextPage?: boolean;
      hasPreviousPage?: boolean;
      isFirstPage?: boolean;
      isLastPage?: boolean;
      list?: Record<string, any>[];
      navigateFirstPage?: number;
      navigateLastPage?: number;
      navigatePages?: number;
      navigatepageNums?: string[];
      nextPage?: number;
      pageNum?: number;
      pageSize?: number;
      pages?: number;
      prePage?: number;
      size?: number;
      startRow?: number;
      total?: number;
    };
    exceptCauseApp: string;
    exceptCauseIp: string;
    exceptClass: string;
    extFields: Record<string, any>;
    resultCode: string;
    resultMsg: string;
  };

  type CommonResponse = {
    data: string;
    exceptCauseApp: string;
    exceptCauseIp: string;
    exceptClass: string;
    extFields: Record<string, any>;
    resultCode: string;
    resultMsg: string;
  };

  type undefinedParams = {
    /** xx */
    pageSize: string;
    /** xxx */
    pageNum: string;
  };

  type undefinedParams = {
    pageSize: string;
    currentPage: string;
  };

  type getPhysicalByIdParams = {
    id: string;
  };
}

生成了两个undefinedParams ,Api引用param无引用正常生成,需要处理无operationId属性情况下生成声明参数跟生成接口层命名一样

image

当 swagger 文档中返回类型同时有定义 default 和 200 时,生成的方法返回类型是 default 中定义的

public getResponseTP(responses: ResponsesObject = {}) {
const response: ResponseObject | undefined =
responses && this.resolveRefObject(responses.default || responses['200']);
const defaultResponse = {
mediaType: '*/*',
type: 'any',
};
if (!response) {
return defaultResponse;
}

问个问题哈,200 的优先级不是应该比 default 高吗,还是我理解错了

例如当我有个接口是这样定义的

"paths": {
  "/v1/address/find_by_user_id": {
    "get": {
      "operationId": "Address_FindAddressByUserId",
      "responses": {
        "200": {
          "description": "A successful response.",
          "schema": {
            "$ref": "#/definitions/addressFindAddressByUserIdReply"
          }
        },
        "default": {
          "description": "An unexpected error response.",
          "schema": {
            "$ref": "#/definitions/rpcStatus"
          }
        }
      },
      "tags": [
        "Address"
      ]
    }
  }
},

最终生成的接口是这样

export async function AddressFindAddressByUserId(options?: { [key: string]: any }) {
  return request<Api.rpcStatus>('/v1/address/find_by_user_id', {
    method: 'GET',
    ...(options || {}),
  });
}

🐛[BUG]v1.4.1 schemaPath 无法使用http

🐛 bug 描述

chenshuai2144/openapi2typescript/blob/700ff14119bd047e315d022a2f165e127ed9e822

v1.4.1此处更新导致以下异常

fetch openapi error: TypeError: Protocol "http:" not supported. Expected "https:"
    at new NodeError (node:internal/errors:371:5)
    at new ClientRequest (node:_http_client:158:11)
    at request (node:http:96:10)
    at C:\Users\...\node_modules\node-fetch\lib\index.js:1468:15
    at new Promise (<anonymous>)
    at Function.fetch [as default] (C:\Users\...\node_modules\node-fetch\lib\index.js:1437:9)
    at C:\Users\...\node_modules\@umijs\openapi\dist\index.js:41:52
    at Generator.next (<anonymous>)
    at C:\Users\...\node_modules\tslib\tslib.js:117:75
    at new Promise (<anonymous>) {
  code: 'ERR_INVALID_PROTOCOL'
}

@chenshuai2144

不同controller下的同名方法的Get请求生成typings.d.ts 冲突

Product和Refund都有同名方法GetById

在类型文件里生成了两个GetByIdParams


"/api/Product/{productId}": {
      "get": {
        "tags": [
          "Product"
        ],
        "operationId": "Product_GetById",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "guid"
            },
            "x-position": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetProductByIdResponse"
                }
              }
            }
          }
        }
      },
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.