alibaba / alibaba/pont

SwaggerV3不支持AnyOf数据类型

Open
#435 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
3k
Forks
251
PR merge metrics
No merged PRs in 30d

Description

## What happens(发生了什么)?

SwaggerV3 JSON文档生成时,`api.d.ts`中的AnyOf类型字段会被直接生成any。具体对比如下:

![screenshot-20240905-151108.jpg](https://s2.loli.net/2024/09/05/3DbcQOBtvUdaF4e.jpg)

另外还有以下两种特殊情况:
1、生成类型错误:
对于ValidationError的定义如下:
```json
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
```
生成的错误类型如下:
```ts
export class ValidationError {
/** loc ---------------array类型错误 ----------- */
loc: array

/** msg */
msg: string

/** type */
type: string
}
```
2、这种特殊结构也需要单独处理:
```json
"vehicle_series_ids": {
"anyOf": [
{
"items": {
"type": "integer"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Vehicle Series Ids",
"description": "车系id列表, None时为全部"
},
```

## How To Reproduce(如何重现)

完整的Swagger文档如下:
```json
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI API Docs",
"description": "FastAPI todo swagger",
"version": "1.0.0"
},
"paths": {
"/todo/": {
"get": {
"tags": [
"todo"
],
"summary": "Get Todo List",
"operationId": "get_todo_list_todo__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TodoListResponse"
}
}
}
}
}
}
},
"/todo/{id}": {
"post": {
"tags": [
"todo"
],
"summary": "Get Todo List",
"operationId": "get_todo_list_todo__id__post",
"parameters": [
{
"description": "Todo的id",
"required": true,
"schema": {
"type": "integer",
"title": "Todo的id",
"description": "Todo的id"
},
"name": "id",
"in": "path"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TodoItem"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/": {
"get": {
"summary": "Index",
"operationId": "index__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"Role": {
"properties": {
"id": {
"type": "integer",
"title": "Id"
},
"role_name": {
"type": "string",
"title": "Role Name"
}
},
"type": "object",
"required": [
"id",
"role_name"
],
"title": "Role"
},
"TodoItem": {
"properties": {
"id": {
"type": "integer",
"title": "Id"
},
"title": {
"type": "string",
"title": "Title"
},
"completed": {
"type": "boolean",
"title": "Completed"
},
"complete_at": {
"type": "string",
"format": "date-time",
"title": "Complete At"
},
"creator": {
"$ref": "#/components/schemas/User"
},
"field1": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
],
"title": "Field1"
},
"field2": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
],
"title": "Field2"
},
"field3": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
],
"title": "Field3"
},
"field4": {
"items": {
"type": "string"
},
"type": "array",
"title": "Field4"
},
"field5": {
"type": "boolean",
"title": "Field5"
},
"field6": {
"type": "boolean",
"title": "Field6",
"default": true
},
"field7": {
"type": "boolean",
"title": "Field7",
"description": "是否为营运, None时为全部"
}
},
"type": "object",
"required": [
"id",
"title",
"completed",
"complete_at",
"field1"
],
"title": "TodoItem"
},
"TodoListResponse": {
"properties": {
"data": {
"items": {
"$ref": "#/components/schemas/TodoItem"
},
"type": "array",
"title": "Data"
},
"page": {
"type": "integer",
"title": "Page"
},
"page_size": {
"type": "integer",
"title": "Page Size"
},
"total": {
"type": "integer",
"title": "Total"
}
},
"type": "object",
"required": [
"data",
"page",
"page_size",
"total"
],
"title": "TodoListResponse"
},
"User": {
"properties": {
"id": {
"type": "integer",
"title": "Id"
},
"username": {
"type": "string",
"title": "Username"
},
"role": {
"$ref": "#/components/schemas/Role"
}
},
"type": "object",
"required": [
"id",
"username"
],
"title": "User"
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
}
}
}
```

Contributor guide

Open the contributing guide

Research direction

Start by tracing the SwaggerV3-to-TypeScript generation path that produces api.d.ts, using the supplied OpenAPI document as the reproduction input. Cover top-level anyOf, array items containing anyOf, and anyOf combining an array with null; done means generated declarations preserve these alternatives without invalid any typing or array types.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, typescript
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.