需求分析

swagger的api文档数据都是按照的固定的格式处理的,这个我们可以通过swagger的请求或者json文件可以看到。
image.pngimage.png

对应的文档接口也就是这边数据中的paths中的数据。
image.png

从文档中我们可以看到相同的请求地址,会分成不同的请求方式列出,而paths中相同的请求地址只显示了一条。不着急,我们点开某一条链接看看他的数据。
image.png
可以清楚的看到所有的请求方式都包含在其中了,甚至备注,请求参数都在其中。

可见文档的所有的数据都是从改请求数据中获取整理的,那么我们的api文件也完全可以根据这份请求数据来生成。

实践

首先我们需要利用node获取到这份数据,使用request模块发起请求获取数据。

  1. request(`${process.env.SWAGGER_API_JSON}`, (error, response) => {
  2. const result = JSON.parse(response.body) //result就是请求返回的数据
  3. })

剩下就是整理到获取的json数据。我们最终生成的api文件需要像swaagger页面上显示的那样,相同类别的接口都存放在一个文件中,并且以类别命名。

首先遍历paths数据

  1. Object.keys(result.paths).forEach(item => {
  2. const app = item.replace(/\//, '').split('/') //首先根据/分割取处理每个path
  3. const api = app[0] //一般接口都是跟地址不同来区分是否相同类别的接口。比如企业相关的都是/ent/...
  4. if (!apiList[api]) { //这边就以第一段path左右key来整理所有的path数据,相同根path的都收集为一类
  5. apiList[api] = []
  6. }
  7. apiList[api].push(item)
  8. })

接下来处理初次整理完的数据

  1. Object.keys(apiList)
  2. .forEach(item => {
  3. const tempApiList = apiList[item].slice(0) //浅拷贝每一类接口集数据
  4. tempApiList.forEach(suItem => {
  5. suItem = (result.basePath === '/' ? '' : result.basePath) + suItem.split('/').filter(
  6. sss => !/{(.*?)}/g.test(sss)).join('/')
  7. }) //处理一遍不符合规范的数据
  8. let resultContent = `
  9. import request from '@/utils/request'
  10. `
  11. const methods = []
  12. const currentApis = apiList[item] //生成的文件需要根据类别分类,所以使用整理的数据遍历
  13. currentApis.forEach(key => {
  14. //原始的数据任然是在paths中,所以需要根据整理的收集集合去原始数据中获取对应的path数据
  15. Object.keys(result.paths[key]).forEach(type => {
  16. const method = result.paths[key][type] //获取请求详情数据
  17. let params = [] //整理请求参数
  18. if (key.match(/{(.*?)}/, '$1')) {
  19. const matchedParams = key.match(/{(.*?)}/g) || []
  20. params = params.concat(matchedParams.map(item => item.replace(/{(.*?)}/g, '$1')))
  21. }
  22. const name = toUpCase(key) //格式化命名,以驼峰方式命名
  23. resultContent += createMethod(name, key, type, method.parameters, params, method.summary)
  24. const uniqueName = name + type.toUpperCase() 命名拼接上请求方式名,用于区别相同请求path的不同请求类型
  25. methods.push(uniqueName)
  26. })
  27. })
  28. resultContent += `export {${methods.join(',')}}`
  29. try {
  30. resultContent = formatJson(resultContent) //格式化文本
  31. } catch (e) {
  32. // todo
  33. }
  34. const path = `${prefix}${result.basePath}/${item}.js` //存储路径
  35. checkDir(path) //检查写出的文本路径是否存在,不存在则直接创建路径
  36. fs.writeFileSync(path, resultContent) //写出
  37. // console.log('`${prefix}${result.basePath}/${item}.js`', `${prefix}${result.basePath}/${item}.js`)
  38. })

具体的请求方法体文本生成主要就是使用的createMethod函数

  1. const createMethod = (name, url, method, params = [], paramKeys, summary) => {
  2. const uniqueName = name + method.toUpperCase()
  3. const comment = []
  4. //生成注释部分
  5. params.forEach(param => {
  6. comment.push(`@${param.name} ${param.type} ${param.description}`)
  7. })
  8. let tempUrl = `'${url}'`
  9. //传参
  10. if (paramKeys.length) {
  11. tempUrl = [tempUrl, '+', '`', paramKeys.map(item => ['/${', item, '}'].join('')).join(''), '`'].join('')
  12. }
  13. const _params = params.filter(item => item.in !== 'path')
  14. const paramPlaceholder = _params.length ? `${paramKeys.length ? ',' : ''} params` : ''
  15. const commentContent = !comment.length ? '' : ` /**
  16. * ${summary || ''}
  17. ${comment.map(item => `* ${item}`).join('\n')}
  18. */`
  19. return `
  20. ${commentContent}
  21. const ${uniqueName} = async (${paramKeys.join(',')} ${paramPlaceholder}) => {
  22. return request({
  23. url: ${tempUrl},
  24. method: '${method}'
  25. ${method === 'get' ? paramPlaceholder ? ',params' : '' : paramPlaceholder ? `,data: params` : ''}, //get和其他请求的参数处理
  26. })
  27. }
  28. `
  29. }

以上就基本完成了swagger的api文件的生成,剩下通过node的配置来把部分公共的变量独立出来,通过方便的修改配置来实现不同场景的使用

  1. 根目录的.env文件
  2. SWAGGER_API_JSON=http://... //api请求地址
  3. API_PREFIX=./src //生成的文件存储的根目录
  4. REQUEST_URL=@/utils/request //api文件中的ajax函数的引用路径

上面完成之后就可以直接node运行程序生成api文件了。
生成完的样例展示
image.png

完整代码仓库