openapi接口文档解析支持
This commit is contained in:
@@ -138,7 +138,7 @@ export default {
|
||||
/**
|
||||
* 解析请求返回的结果集
|
||||
* @param responses swagger.parameters
|
||||
* @param definitionsDataMap 解析的path里对应的数据map,{url + "." + method: swagger.paths.post}
|
||||
* @param openApiComponents 解析的path里对应的数据map,{url + "." + method: swagger.paths.post}
|
||||
* @returns [] 参数列表:[{
|
||||
* code: '',
|
||||
* type: '',
|
||||
@@ -147,26 +147,35 @@ export default {
|
||||
* schemas: [],
|
||||
* }]
|
||||
*/
|
||||
getResponseParamList(responses, definitionsDataMap) {
|
||||
getResponseParamList(responses, openApiComponents) {
|
||||
let responsesList = [];
|
||||
let indexKey = 1;
|
||||
Object.keys(responses).forEach(code => {
|
||||
let codeResponses = responses[code];
|
||||
let type = undefined;
|
||||
let children = undefined;
|
||||
if (this.isSchemaRef(codeResponses.schema)) {
|
||||
type = this.getSchemaRef(codeResponses.schema);
|
||||
children = this.getParamDefinitions(type, definitionsDataMap, indexKey, {}, 0);
|
||||
}
|
||||
let content = codeResponses.content;
|
||||
let contentList = [];
|
||||
let resIndexKey = 1;
|
||||
Object.keys(content).forEach(resType => {
|
||||
let contentValue = content[resType];
|
||||
let keySub = indexKey + '_' + resIndexKey;
|
||||
// 通用解析方法
|
||||
let analysis = this.analysisParamObj(contentValue, openApiComponents, keySub);
|
||||
contentList.push({
|
||||
mediaType: resType,
|
||||
key: keySub,
|
||||
schemas: analysis.children,
|
||||
});
|
||||
resIndexKey++;
|
||||
});
|
||||
responsesList.push({
|
||||
code: code,
|
||||
type: type,
|
||||
key: indexKey,
|
||||
desc: codeResponses.description,
|
||||
schemas: children,
|
||||
childrens: contentList,
|
||||
});
|
||||
indexKey++;
|
||||
});
|
||||
console.log(responsesList);
|
||||
return responsesList;
|
||||
},
|
||||
/**
|
||||
@@ -183,14 +192,14 @@ export default {
|
||||
* @returns {string}
|
||||
*/
|
||||
getSchemaRef(schema) {
|
||||
if (schema['$ref'] && schema['$ref'].indexOf('#/definitions/') === 0) return schema['$ref'].replace('#/definitions/', '');
|
||||
if (schema['$ref'] && schema['$ref'].indexOf('#/components/schemas/') === 0) return schema['$ref'].replace('#/components/schemas/', '');
|
||||
logUtil.logMessage('9467', '', schema);
|
||||
return '';
|
||||
},
|
||||
/**
|
||||
* 获取swagger.definitions里的对象信息
|
||||
* @param ref 对象名
|
||||
* @param definitionsDataMap 解析的path里对应的数据map,{url + "." + method: swagger.paths.post}
|
||||
* @param openApiComponents 解析的path里对应的数据map,{url + "." + method: swagger.paths.post}
|
||||
* @param indexKey 层级key
|
||||
* @param parentRef 父级已用过的ref,防止无限递归
|
||||
* @param deep 层级深度,大于10层则不再解析,防止层级太深或无线递归
|
||||
@@ -209,8 +218,9 @@ export default {
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
getParamDefinitions(ref, definitionsDataMap, indexKey, parentRef, deep) {
|
||||
let definition = definitionsDataMap[ref];
|
||||
getParamDefinitions(ref, openApiComponents, indexKey, parentRef, deep) {
|
||||
let componentSchemas = openApiComponents.schemas || {};
|
||||
let definition = componentSchemas[ref];
|
||||
// 层级大于5层 或者 没有类型定义
|
||||
if (deep >= 10 || !definition) {
|
||||
return undefined;
|
||||
@@ -221,79 +231,20 @@ export default {
|
||||
return undefined;
|
||||
}
|
||||
let paramList = [];
|
||||
let type = definition.type;
|
||||
let properties = definition.properties;
|
||||
let indexSub = 1;
|
||||
if (type === 'object' && properties) {
|
||||
if (properties) {
|
||||
let currentLevelTypes = {};
|
||||
Object.keys(properties).forEach(key => {
|
||||
let parameter = properties[key];
|
||||
let type = parameter.type;
|
||||
let format = parameter.format;
|
||||
let description = parameter.description || '';
|
||||
let example = parameter['example'] || parameter['x-example'];
|
||||
let subType = undefined;
|
||||
let additional = undefined;
|
||||
let enums = undefined;
|
||||
let keySub = indexKey + '_' + indexSub;
|
||||
let children = undefined;
|
||||
// 把当前层级用过的类型清除,防止多个同类型在一层,后面的不能解析
|
||||
Object.keys(currentLevelTypes).forEach(currentLevelType => {
|
||||
parentRef[currentLevelType] = undefined;
|
||||
});
|
||||
if (type === 'array') {
|
||||
// 解析parameter.items {$ref: "#/definitions/Model"}
|
||||
if (this.isSchemaRef(parameter.items)) {
|
||||
subType = this.getSchemaRef(parameter.items);
|
||||
children = this.getParamDefinitions(subType, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
} else if (parameter.items && parameter.items.type) {
|
||||
subType = parameter.items.type;
|
||||
} else {
|
||||
logUtil.logMessage('004', type, parameter);
|
||||
}
|
||||
} else if (type === 'object') {
|
||||
if (parameter.additionalProperties) {
|
||||
additional = {};
|
||||
children = this.getAdditionalProperties(parameter.additionalProperties, additional, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
format = additional.type;
|
||||
} else {
|
||||
logUtil.log('0041', type, parameter);
|
||||
}
|
||||
} else if (!type) {
|
||||
if (this.isSchemaRef(parameter)) {
|
||||
type = this.getSchemaRef(parameter);
|
||||
children = this.getParamDefinitions(type, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
} else {
|
||||
logUtil.logMessage('005', type, parameter);
|
||||
}
|
||||
} else {
|
||||
if (notNeedHandleTypeArr.indexOf(type) >= 0) {
|
||||
// 无需特殊处理的类型
|
||||
} else {
|
||||
logUtil.logMessage('006', type, parameter);
|
||||
}
|
||||
}
|
||||
if (example) {
|
||||
description = description ? (description + ',') : '';
|
||||
description += '例:' + example;
|
||||
}
|
||||
if (parameter.items && parameter.items.enum && parameter.items.enum.length > 0) {
|
||||
enums = parameter.items.enum;
|
||||
description = description || '枚举类型';
|
||||
description += ',可选值:' + parameter.items.enum.join('、');
|
||||
}
|
||||
paramList.push({
|
||||
type: type,
|
||||
name: key,
|
||||
key: keySub,
|
||||
subType: subType,
|
||||
format: format,
|
||||
description: description,
|
||||
enum: enums,
|
||||
additional: additional,
|
||||
example: example,
|
||||
children: children,
|
||||
});
|
||||
let child = this.analysisParamObj(parameter);
|
||||
child.name = key;
|
||||
paramList.push(child);
|
||||
indexSub++;
|
||||
currentLevelTypes[type] = 1;
|
||||
});
|
||||
@@ -304,7 +255,7 @@ export default {
|
||||
* parameter.schema.additionalProperties 类型的参数值处理
|
||||
* @param additionalProperties
|
||||
* @param additional
|
||||
* @param definitionsDataMap
|
||||
* @param openApiComponents
|
||||
* @param keySub
|
||||
* @param parentRef
|
||||
* @param deep
|
||||
@@ -315,20 +266,20 @@ export default {
|
||||
* |{children: (undefined|{type: "", name: "", key: "", subType: "", format: "", description: "", enum: "", additional: "", example: "", children: *[]}), type: string}
|
||||
* }
|
||||
*/
|
||||
getAdditionalProperties(additionalProperties, additional, definitionsDataMap, keySub, parentRef, deep) {
|
||||
getAdditionalProperties(additionalProperties, additional, openApiComponents, keySub, parentRef, deep) {
|
||||
if (this.isSchemaRef(additionalProperties)) {
|
||||
additional.type = this.getSchemaRef(additionalProperties);
|
||||
additional.children = this.getParamDefinitions(additional.type, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
additional.children = this.getParamDefinitions(additional.type, openApiComponents, keySub, parentRef, deep + 1);
|
||||
return additional.additional;
|
||||
} else if (additionalProperties.additionalProperties) {
|
||||
additional.type = additionalProperties.type;
|
||||
additional.additional = {};
|
||||
return this.getAdditionalProperties(additionalProperties.additionalProperties, additional.additional, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
return this.getAdditionalProperties(additionalProperties.additionalProperties, additional.additional, openApiComponents, keySub, parentRef, deep + 1);
|
||||
} else if (additionalProperties.type === 'array') {
|
||||
additional.type = additionalProperties.type;
|
||||
if (this.isSchemaRef(additionalProperties.items)) {
|
||||
let subType = this.getSchemaRef(additionalProperties.items);
|
||||
let children = this.getParamDefinitions(subType, definitionsDataMap, keySub, parentRef, deep + 1);
|
||||
let children = this.getParamDefinitions(subType, openApiComponents, keySub, parentRef, deep + 1);
|
||||
additional.additional = {
|
||||
type: subType,
|
||||
children: children
|
||||
@@ -347,5 +298,130 @@ export default {
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
analysisParamObj(parameter, openApiComponents, indexKey) {
|
||||
let description = parameter.description || '';
|
||||
let type = parameter.type;
|
||||
let format = parameter.format;
|
||||
let example = parameter['x-example'];
|
||||
let subType = undefined;
|
||||
let children = undefined;
|
||||
let additional = undefined;
|
||||
let enums = undefined;
|
||||
if (type === 'array') {
|
||||
// 解析parameter.items.$ref 或 parameter.items.$ref {$ref: "#/definitions/Model"}
|
||||
// 解析parameter.items.type {type: 'file'}
|
||||
if (this.isSchemaRef(parameter.items)) {
|
||||
subType = this.getSchemaRef(parameter.items);
|
||||
children = this.getParamDefinitions(subType, openApiComponents, indexKey, {}, 0);
|
||||
} else if (parameter.schema) {
|
||||
if (this.isSchemaRef(parameter.schema.items)) {
|
||||
subType = this.getSchemaRef(parameter.schema.items);
|
||||
children = this.getParamDefinitions(subType, openApiComponents, indexKey, {}, 0);
|
||||
} else if (parameter.schema.type) {
|
||||
subType = parameter.schema.type;
|
||||
}
|
||||
} else if (parameter.items && parameter.items.type) {
|
||||
subType = parameter.items.type;
|
||||
} else if (parameter.items && parameter.items.properties) {
|
||||
children = [];
|
||||
let proIndex = 1;
|
||||
let properties = parameter.items.properties;
|
||||
Object.keys(properties).forEach(key => {
|
||||
let parameter = properties[key];
|
||||
let subKey = indexKey + '_' + proIndex;
|
||||
let child = this.analysisParamObj(parameter, openApiComponents, subKey);
|
||||
child.name = key;
|
||||
children.push(child);
|
||||
proIndex++;
|
||||
});
|
||||
} else {
|
||||
logUtil.logMessage('001', type, parameter);
|
||||
}
|
||||
} else if (!type) {
|
||||
if (parameter.schema) {
|
||||
if (this.isSchemaRef(parameter.schema)) {
|
||||
// 解析parameter.schema {$ref: "#/definitions/Model"}
|
||||
type = this.getSchemaRef(parameter.schema);
|
||||
children = this.getParamDefinitions(type, openApiComponents, indexKey, {}, 0);
|
||||
} else if (parameter.schema.type) {
|
||||
type = parameter.schema.type;
|
||||
if (parameter.schema.additionalProperties) {
|
||||
additional = {};
|
||||
children = this.getAdditionalProperties(parameter.schema.additionalProperties, additional, openApiComponents, indexKey, {}, 0);
|
||||
format = additional.type;
|
||||
} else if (parameter.schema.items) {
|
||||
if (this.isSchemaRef(parameter.schema.items)) {
|
||||
subType = this.getSchemaRef(parameter.schema.items);
|
||||
children = this.getParamDefinitions(subType, openApiComponents, indexKey, {}, 0);
|
||||
} else if (parameter.schema.items.type) {
|
||||
subType = parameter.schema.items.type;
|
||||
} else {
|
||||
logUtil.log('0014', type, parameter);
|
||||
}
|
||||
} else {
|
||||
logUtil.log('0011', type, parameter);
|
||||
}
|
||||
} else {
|
||||
logUtil.logMessage('0013', type, parameter);
|
||||
}
|
||||
} else if (parameter.items && parameter.items.type) {
|
||||
// 解析parameter.items {type: "object", $ref: "#/definitions/Model"}
|
||||
type = parameter.items.type;
|
||||
if (parameter.items.additionalProperties) {
|
||||
additional = {};
|
||||
children = this.getAdditionalProperties(parameter.items.additionalProperties, additional, openApiComponents, indexKey, {}, 0);
|
||||
format = additional.type;
|
||||
} else {
|
||||
logUtil.logMessage('0012', type, parameter);
|
||||
}
|
||||
} else if (parameter.properties) {
|
||||
children = [];
|
||||
let proIndex = 1;
|
||||
let properties = parameter.properties;
|
||||
Object.keys(properties).forEach(key => {
|
||||
let parameter = properties[key];
|
||||
let subKey = indexKey + '_' + proIndex;
|
||||
let child = this.analysisParamObj(parameter, openApiComponents, subKey);
|
||||
child.name = key;
|
||||
children.push(child);
|
||||
proIndex++;
|
||||
});
|
||||
} else {
|
||||
logUtil.logMessage('002', type, parameter);
|
||||
}
|
||||
} else {
|
||||
if (notNeedHandleTypeArr.indexOf(type) >= 0) {
|
||||
// 无需特殊处理的类型
|
||||
} else {
|
||||
logUtil.logMessage('003', type, parameter);
|
||||
}
|
||||
}
|
||||
// 丰富说明内容
|
||||
if (example) {
|
||||
description = description ? (description + ',') : '';
|
||||
description += '例:' + example;
|
||||
}
|
||||
if (parameter.items && parameter.items.enum && parameter.items.enum.length > 0) {
|
||||
enums = parameter.items.enum;
|
||||
description = description || '枚举类型';
|
||||
description += ',可选值:' + parameter.items.enum.join('、');
|
||||
}
|
||||
console.log("xxx",parameter)
|
||||
return {
|
||||
type: type,
|
||||
key: indexKey,
|
||||
in: parameter.in,
|
||||
name: parameter.name,
|
||||
subType: subType,
|
||||
required: parameter.required ? '是' : '否',
|
||||
format: format,
|
||||
enum: parameter.enum,
|
||||
example: example,
|
||||
collectionFormat: parameter.collectionFormat,// 枚举多选时=multi
|
||||
description: description,
|
||||
additional: additional,
|
||||
children: children,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<a-tag color="purple" v-else-if="method === 'options'">options</a-tag>
|
||||
<a-tag color="purple" v-else-if="method === 'trace'">trace</a-tag>
|
||||
</template>
|
||||
<span style="margin: 0 6px 0 3px;">{{title}}</span>
|
||||
<span style="margin: 0 6px 0 3px;word-break: break-all;">{{title}}</span>
|
||||
<a-badge v-if="children" :count="children.length" :number-style="{backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset'}"/>
|
||||
</template>
|
||||
</a-directory-tree>
|
||||
|
||||
@@ -30,7 +30,7 @@ export default createStore({
|
||||
// openApi原始文档
|
||||
openApiDoc: {},
|
||||
// openApi原始definitions
|
||||
openApiDefinitions: {},
|
||||
openApiComponents: {},
|
||||
// url对应的map信息 {'url + "." + method': {swagger.paths.url.method对象信息}}
|
||||
openApiUrlMethodMap: {},
|
||||
// 方法统计{post: 10, total: 20}
|
||||
@@ -94,7 +94,7 @@ export default createStore({
|
||||
// openApi
|
||||
setOpenApiDoc(state, openApiDoc) {
|
||||
state.openApiDoc = openApiDoc;
|
||||
state.openApiDefinitions = openApiDoc.definitions || {};
|
||||
state.openApiComponents = openApiDoc.components || {};
|
||||
},
|
||||
setOpenApiUrlMethodMap(state, openApiUrlMethodMap) {
|
||||
state.openApiUrlMethodMap = openApiUrlMethodMap;
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
<a-radio :value="2">Swagger JSON</a-radio>
|
||||
<a-radio :value="3">OpenApi URL</a-radio>
|
||||
<a-radio :value="4">OpenApi JSON</a-radio>
|
||||
<a-radio :value="5">自建API</a-radio>
|
||||
<a-tooltip title="即将上线,敬请期待">
|
||||
<a-radio :value="5" disabled>自建API</a-radio>
|
||||
</a-tooltip>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="文档地址" required name="docUrl" v-if="docEdit.docType === 1">
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
produces: produces,
|
||||
};
|
||||
// 解析请求参数
|
||||
let definitionsDataMap = store.state.openApiDefinitions;
|
||||
requestParamList.value = openApiAnalysis.getRequestParamList(docInfo.parameters, definitionsDataMap);
|
||||
responseParamList.value = openApiAnalysis.getResponseParamList(docInfo.responses, definitionsDataMap);
|
||||
let openApiComponents = store.state.openApiComponents;
|
||||
requestParamList.value = openApiAnalysis.getRequestParamList(docInfo.parameters, openApiComponents);
|
||||
responseParamList.value = openApiAnalysis.getResponseParamList(docInfo.responses, openApiComponents);
|
||||
}
|
||||
onMounted(() => {
|
||||
initLoadDocument();
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
</template>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<template v-if="record.schemas">
|
||||
<a-table :dataSource="record.schemas" :columns="responseParamListColumns" size="small" :pagination="false">
|
||||
<template v-if="record.childrens">
|
||||
<a-table :dataSource="record.childrens" :columns="responseMediaTypeColumns" size="small" :pagination="false">
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
{{text}}
|
||||
@@ -51,9 +51,23 @@
|
||||
<template v-if="record.format">({{record.format}})</template>
|
||||
</template>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<template v-if="record.schemas">
|
||||
<a-table :dataSource="record.schemas" :columns="responseParamListColumns" size="small" :pagination="false">
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
{{text}}
|
||||
<template v-if="record.subType">[{{record.subType}}]</template>
|
||||
<template v-if="record.format">({{record.format}})</template>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
<div v-else style="text-align: center;padding: 10px 0;">无结果说明</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
<div v-else style="text-align: center;padding: 10px 0;">无参数说明</div>
|
||||
<div v-else style="text-align: center;padding: 10px 0;">无结果说明</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form-item>
|
||||
@@ -98,6 +112,9 @@
|
||||
{title: '类型', dataIndex: 'type', width: 250},
|
||||
{title: '说明', dataIndex: 'desc'},
|
||||
],
|
||||
responseMediaTypeColumns: [
|
||||
{title: '媒体类型', dataIndex: 'mediaType'},
|
||||
],
|
||||
responseParamListColumns: [
|
||||
{title: '参数名', dataIndex: 'name', width: 250},
|
||||
{title: '类型', dataIndex: 'type', width: 250},
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
produces: produces,
|
||||
};
|
||||
// 解析请求参数
|
||||
let definitionsDataMap = store.state.openApiDefinitions;
|
||||
let definitionsDataMap = store.state.openApiComponents;
|
||||
requestParamList.value = openApiAnalysis.getRequestParamList(docInfo.parameters, definitionsDataMap);
|
||||
responseParamList.value = openApiAnalysis.getResponseParamList(docInfo.responses, definitionsDataMap);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user