swagger-typescript-api命名规则修改

66 阅读1分钟

通过swagger-typescript-api获取的接口方法,默认的命名方式是后端的方法名,后端经常会在不同的controller下写很多相同的方法名(如list这种命名) 通过自定义调用generateApi,可以将命名规则改为 请求方法+路径

import path from 'node:path'
import { generateApi } from 'swagger-typescript-api'

function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

function singular(word) {
  // 简易处理,可换成更完善的库(如 pluralize)
  if (word.endsWith('s')) return word.slice(0, -1)
  return word
}

function joinSegments(segments) {
  return segments.join('')
}

/* NOTE: all fields are optional expect one of `input`, `url`, `spec` */
generateApi({
  name: 'ApiBusiness.ts',
  fileName: 'ApiBusiness.ts',
  // set to `false` to prevent the tool from writing to disk
  url: 'http://10.10.10.115:7000/business/v3/api-docs',
  output: path.resolve(process.cwd(), './src/api'),
  httpClientType: 'axios',
  generateRouteTypes: false,
  hooks: {
    onFormatRouteName: (routeInfo) => {
      /**
       * routeInfo 示例:
       * {
       *   method: 'get',
       *   route: '/users/{id}/roles',
       *   originalPath: '/users/{id}/roles',
       *   ... 其他字段
       * }
       */
      const httpMethod = (routeInfo.method || '').toLowerCase()
      const rawPath = routeInfo.route || ''
      // 1. 拆分路径段
      const segments = rawPath
        .split('/')
        .filter(Boolean)
        .map((s) => s.replace(/\{|\}/g, '')) // 去掉 {param}

      // 3. 标识业务主资源(第一个非参数段)
      const resourceSegments = segments.filter((s) => !rawPath.includes(`{${s}}`))

      // 简单判断动作(可按需扩展更复杂逻辑)
      const verbMap = {
        get: 'get',
        post: 'create',
        put: 'update',
        patch: 'patch',
        delete: 'delete',
      }

      // 特殊:嵌套 + POST 往往表示“添加子资源”
      // 例如 /users/{id}/roles POST -> addUserRole
      if (httpMethod === 'post' && segments.length > 2) {
        // 最后一个非参数段作为子资源
        const last = segments[segments.length - 1]
        if (!rawPath.includes(`{${last}}`)) {
          return (
            'add' +
            capitalize(joinSegments(resourceSegments.slice(0, 1))) +
            singular(capitalize(last))
          )
        }
      }

      // 构造核心资源名(主资源+可能的子资源)
      let core = resourceSegments.map(capitalize).join('')
      if (!core) {
        core = 'Request'
      }

      // 拼接参数修饰(ByXxx...)
      let byPart = ''
      const paramNames = segments.filter((s) => rawPath.includes(`{${s}}`))
      if (paramNames.length) {
        byPart = 'By' + paramNames.map(capitalize).join('And')
      }

      // 选择动词
      let verb = verbMap[httpMethod] || httpMethod

      // 如果是 GET 并且无参数且资源名复数 -> getUsers 这种就保留
      // 如果是 GET + 有参数 -> getUserById
      // 如果是 DELETE + 有子资源参数 -> deleteUserRoleByRoleId
      // 已在通用逻辑覆盖

      return verb + core + byPart
    },
  },
  prettier: {
    // By default prettier config is load from your project
    printWidth: 120,
    tabWidth: 2,
    trailingComma: 'all',
    parser: 'typescript',
  },
})