需求分析
swagger的api文档数据都是按照的固定的格式处理的,这个我们可以通过swagger的请求或者json文件可以看到。
对应的文档接口也就是这边数据中的paths中的数据。
从文档中我们可以看到相同的请求地址,会分成不同的请求方式列出,而paths中相同的请求地址只显示了一条。不着急,我们点开某一条链接看看他的数据。
可以清楚的看到所有的请求方式都包含在其中了,甚至备注,请求参数都在其中。
可见文档的所有的数据都是从改请求数据中获取整理的,那么我们的api文件也完全可以根据这份请求数据来生成。
实践
首先我们需要利用node获取到这份数据,使用request
模块发起请求获取数据。
request(`${process.env.SWAGGER_API_JSON}`, (error, response) => {
const result = JSON.parse(response.body) //result就是请求返回的数据
})
剩下就是整理到获取的json数据。我们最终生成的api文件需要像swaagger页面上显示的那样,相同类别的接口都存放在一个文件中,并且以类别命名。
首先遍历paths数据
Object.keys(result.paths).forEach(item => {
const app = item.replace(/\//, '').split('/') //首先根据/分割取处理每个path
const api = app[0] //一般接口都是跟地址不同来区分是否相同类别的接口。比如企业相关的都是/ent/...
if (!apiList[api]) { //这边就以第一段path左右key来整理所有的path数据,相同根path的都收集为一类
apiList[api] = []
}
apiList[api].push(item)
})
接下来处理初次整理完的数据
Object.keys(apiList)
.forEach(item => {
const tempApiList = apiList[item].slice(0) //浅拷贝每一类接口集数据
tempApiList.forEach(suItem => {
suItem = (result.basePath === '/' ? '' : result.basePath) + suItem.split('/').filter(
sss => !/{(.*?)}/g.test(sss)).join('/')
}) //处理一遍不符合规范的数据
let resultContent = `
import request from '@/utils/request'
`
const methods = []
const currentApis = apiList[item] //生成的文件需要根据类别分类,所以使用整理的数据遍历
currentApis.forEach(key => {
//原始的数据任然是在paths中,所以需要根据整理的收集集合去原始数据中获取对应的path数据
Object.keys(result.paths[key]).forEach(type => {
const method = result.paths[key][type] //获取请求详情数据
let params = [] //整理请求参数
if (key.match(/{(.*?)}/, '$1')) {
const matchedParams = key.match(/{(.*?)}/g) || []
params = params.concat(matchedParams.map(item => item.replace(/{(.*?)}/g, '$1')))
}
const name = toUpCase(key) //格式化命名,以驼峰方式命名
resultContent += createMethod(name, key, type, method.parameters, params, method.summary)
const uniqueName = name + type.toUpperCase() 命名拼接上请求方式名,用于区别相同请求path的不同请求类型
methods.push(uniqueName)
})
})
resultContent += `export {${methods.join(',')}}`
try {
resultContent = formatJson(resultContent) //格式化文本
} catch (e) {
// todo
}
const path = `${prefix}${result.basePath}/${item}.js` //存储路径
checkDir(path) //检查写出的文本路径是否存在,不存在则直接创建路径
fs.writeFileSync(path, resultContent) //写出
// console.log('`${prefix}${result.basePath}/${item}.js`', `${prefix}${result.basePath}/${item}.js`)
})
具体的请求方法体文本生成主要就是使用的createMethod函数
const createMethod = (name, url, method, params = [], paramKeys, summary) => {
const uniqueName = name + method.toUpperCase()
const comment = []
//生成注释部分
params.forEach(param => {
comment.push(`@${param.name} ${param.type} ${param.description}`)
})
let tempUrl = `'${url}'`
//传参
if (paramKeys.length) {
tempUrl = [tempUrl, '+', '`', paramKeys.map(item => ['/${', item, '}'].join('')).join(''), '`'].join('')
}
const _params = params.filter(item => item.in !== 'path')
const paramPlaceholder = _params.length ? `${paramKeys.length ? ',' : ''} params` : ''
const commentContent = !comment.length ? '' : ` /**
* ${summary || ''}
${comment.map(item => `* ${item}`).join('\n')}
*/`
return `
${commentContent}
const ${uniqueName} = async (${paramKeys.join(',')} ${paramPlaceholder}) => {
return request({
url: ${tempUrl},
method: '${method}'
${method === 'get' ? paramPlaceholder ? ',params' : '' : paramPlaceholder ? `,data: params` : ''}, //get和其他请求的参数处理
})
}
`
}
以上就基本完成了swagger的api文件的生成,剩下通过node的配置来把部分公共的变量独立出来,通过方便的修改配置来实现不同场景的使用
根目录的.env文件
SWAGGER_API_JSON=http://... //api请求地址
API_PREFIX=./src //生成的文件存储的根目录
REQUEST_URL=@/utils/request //api文件中的ajax函数的引用路径
上面完成之后就可以直接node运行程序生成api文件了。
生成完的样例展示