Postman to OpenAPI Converter
2026/9/15 12:23:16 网站建设 项目流程

Postman to OpenAPI Converter

【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar

一、核心导读

本篇文章将以@scalar/postman-to-openapi包为核心,带你掌握如何将 Postman Collection(含v2.1等版本)一键转换为标准的 OpenAPI 3.1 文档。文章将从安装、基础用法、输入检测、高级选项到源码级的转换原理进行逐步拆解,帮助你:

  • 快速将现有的 Postman 集合转换成 OpenAPI 文档,接入 Scalar API Reference、SDK 生成器等生态;
  • 深入理解转换器如何解析请求、路径、认证、请求体、响应与服务器,并利用mergeOperationrequestIndexPathstagNamingStrategy等选项进行精细控制;
  • 通过源码与实际 fixture 了解其内部实现,避免黑盒使用。

二、什么是@scalar/postman-to-openapi

@scalar/postman-to-openapi是 Scalar 开源 API 平台提供的一个 TypeScript 包,用于把 Postman Collection(Postman Collection Format)转换为开放标准 OpenAPI(Swagger)文档。它基于社区项目 joolfe/postman-to-openapi 改进而来,并在其基础上适配了 Scalar 生态,因此也被视为现代继任者。

该包的定位可以从其package.jsondescription中看出:"Converts Postman collections to OpenAPI documents"(package.json)。它不依赖任何运行时 GUI,只负责数据格式转换,因此非常适合集成到 CI、构建脚本、CLI 工具或编辑器插件中。

从 packages/postman-to-openapi/src/index.ts 可以看出,包对外导出的核心 API 只有三个:

  • convert
  • isPostmanCollection
  • extractPathFromUrl/normalizePath(URL 工具函数)

这也体现了它的设计哲学:轻量、无副作用、聚焦于转换本身

三、安装与快速开始

3.1 安装

该包发布在 npm 上,包名为@scalar/postman-to-openapi

npm install @scalar/postman-to-openapi

3.2 最小示例

import { convert } from '@scalar/postman-to-openapi' // Free the postman! const result = await convert(myPostmanCollection) console.log(result)

convert接受一个Postman Collection 对象Postman Collection 的 JSON 字符串。从源码 src/convert.ts 中的parseCollectionInput可以看到,当传入字符串时,内部会调用JSON.parse进行解析;若解析失败,会抛出名为PostmanCollectionParseError的异常,错误信息为Invalid Postman collection JSON: <details>

3.3 返回值:OpenAPI 3.1 文档

convert返回的是符合OpenAPI 3.1.0规范的文档对象(OpenAPIV3_1.Document)。在源码中可以看到,当不传入基础文档时,转换器会初始化一个最小文档:

const openapi: OpenAPIV3_1.Document = baseDocument ?? { openapi: '3.1.0', info: { title, version, ...(description && { description }), ...(license && { license }), ...(contact && { contact }), ...(logo && { 'x-logo': logo }), }, paths: {}, }

也就是说,info.title取自集合的info.name(缺省为'API'),info.version优先从集合的variable中寻找 key 为version的变量(缺省为'1.0.0'),info.descriptionlicensecontactx-logo等则分别从集合中提取。

小技巧:如果希望控制生成文档的版本号,可以在 Postman 集合的 Collection Variables 中定义一个名为version的变量,例如1.2.0

四、检测输入是否为 Postman Collection

在实际的 CLI 或集成场景中,输入往往是不确定来源的文本。此时可以使用isPostmanCollection来判断:

import { convert, isPostmanCollection } from '@scalar/postman-to-openapi' if (isPostmanCollection(input)) { const openApiDocument = convert(input) console.log(openApiDocument) }

4.1 判断逻辑

isPostmanCollection接受一个JSON 字符串,其判断逻辑在 src/is-postman-collection.ts 中:

  1. 尝试JSON.parse,失败则返回false
  2. 解析结果必须是对象且不能是数组;
  3. 集合必须包含一个Postman schema 地址info.schema的 host 必须是schema.getpostman.com);
  4. 满足以下任意一个条件即可:
    • 包含info._postman_id
    • 包含一个顶层item数组。

这意味着:导出的集合即使缺少info._postman_id,只要包含合法的 Postman schema URL 和item树,也能被正确识别。这一点非常重要,因为部分 Postman 导出选项并不会生成_postman_id

4.2 输入校验

当调用convert时,还会执行更严格的形状校验(validateCollectionShape),包括:

  • 必须是对象;
  • 必须包含info
  • item必须是数组;
  • info.name必填;
  • info.schema必填;
  • 如果提供了variable,则必须是数组。

这些校验能帮助你在转换前尽早发现格式问题,而不是在转换中途才报错。

五、核心转换流程(源码级拆解)

5.1 整体流程

convert的完整处理流程可以概括为(源码见 src/convert.ts):

  1. 解析输入parseCollectionInput(对象直接使用,字符串则JSON.parse);
  2. 校验形状validateCollectionShape
  3. 提取文档级信息:title / version / description / license / contact / logo;
  4. 处理 externalDocs
  5. 处理认证:如果集合带有auth,调用processAuth生成securitySchemessecurity,并合并进文档;
  6. 遍历item:逐个调用processItem生成 paths / components / serverUsage,并通过mergePathItem合并;
  7. 路径参数统一unifyEquivalentPathParameters将等价但参数名不同的路径合并;
  8. 服务器放置analyzeServerDistribution根据服务器使用频率决定把servers放到文档级、路径级还是操作级;
  9. 清理cleanupOperations删除空parameters、空描述以及内部 bookkeeping 扩展字段;最后pruneDocument修剪空字段并返回。

5.2 item 树遍历:processItem

processItem(src/helpers/path-items.ts)是整个转换的核心,它递归处理Item | ItemGroup

  • 如果是ItemGroup(包含item数组),则递归遍历子项,并把组名累积到parentTags中;
  • 如果是Item(包含request),则:
    • 解析请求 URL,拆出pathserver
    • 把路径参数从 Postman 的:param形式归一化为 OpenAPI 的{param}形式;
    • 提取operationId(请求名中[xxx]方括号内的内容)、summarydescription
    • 根据文件夹层级生成tags
    • 提取 query / path / header参数(同时支持从请求描述中的 Markdown 参数表格解析参数);
    • 处理请求级auth(生成securitySchemessecurity);
    • 处理请求体(支持 raw / urlencoded / formdata / file / graphql 等模式);
    • 提取responses(含保存的响应、状态码解析);
    • 处理pre-request / post-response 脚本,生成x-pre-requestx-post-response扩展字段。

5.3 请求名中的状态码约定

一个非常有用的约定:如果请求的名称以200 - 描述200: 描述的形式开头,parseStatusCodeFromRequestName会将其解析为响应的状态码和描述(src/helpers/path-items.ts 中的parseStatusCodeFromRequestName)。例如:

  • 请求名200 - OK→ 生成responses['200'] = { description: 'OK' }
  • 请求名404: Not Found→ 生成responses['404'] = { description: 'Not Found' }

这让你可以在不改动响应数据的情况下,仅通过命名规范就让转换结果包含有意义的状态码描述。

5.4 请求体模式支持

在 src/helpers/request-body.ts 中,转换器支持以下 Postman body 模式:

Postman body 模式转换结果
raw(JSON / XML / text 等)requestBody.content对应媒体类型与 schema
urlencodedapplication/x-www-form-urlencoded
formdatamultipart/form-data
file文件上传类型的媒体类型
graphqlGraphQL 请求体(含 query / variables)

同时,ensureRequestBodyContent会保证requestBody.content不为空,缺省时回退为text/plain。值得注意的是,即使请求方法是 GET,只要存在 body,转换器也会保留requestBody(见 src/helpers/path-items.ts 中的注释 "Allow request bodies for all methods (including GET)")。

5.5 认证转换:processAuth

processAuth(src/helpers/auth.ts)负责把 Postman 的认证配置转换为 OpenAPI 的securitySchemessecurity。它支持的类型包括(对应 src/types.ts 中Auth的定义):

  • basic(HTTP Basic)
  • bearer
  • apikey
  • oauth1/oauth2
  • digest
  • awsv4(AWS Signature V4)
  • edgegrid(Akamai EdgeGrid)
  • hawkntlm

转换发生在两个层级:

  1. 集合级 authcollection.auth):生成文档级components.securitySchemessecurity
  2. 请求级 authrequest.auth):生成操作级security,并合并securitySchemescomponents

两者可以并存,从而实现"全局默认认证 + 单请求覆盖"的效果。

5.6 响应提取:extractResponses

src/helpers/responses.ts 负责从 Postman 保存的响应(response[])中提取 OpenAPI 的responses对象。每个保存的响应会映射为一个状态码,响应体与 Content-Type 会被转换为对应的媒体类型与示例。当没有保存响应时,会使用默认描述(DEFAULT_RESPONSE_DESCRIPTIONS)。

同时,请求头中的Accept会被用于推断响应的媒体类型(pickAcceptMediaType),这是让转换结果更精确的关键细节之一。

六、convert的高级选项

convert的第二个参数是一个ConvertOptions对象。其完整定义在 src/convert.ts 中:

选项类型默认值说明
mergeOperationbooleanfalse相同 path + method 的操作是否合并为一个 operation。为true时,多次出现的同名操作会合并,并通过generateUniqueValue生成唯一的示例名(如Default example#1
requestIndexPathsreadonly PostmanRequestIndexPath[]未定义(转换整个集合)只转换指定索引路径上的请求。每个路径是从collection.item出发的零基索引数组,最后一个索引可以指向请求或文件夹(文件夹会包含其全部后代请求)
tagNamingStrategy'leaf' \| 'chain''leaf'从嵌套文件夹生成 OpenAPI tag 的策略。leaf只使用文件夹名,重名时回退为父级 / 叶子chain保留完整的文件夹链,用>连接
documentOpenAPIV3_1.Document未定义已有的 OpenAPI 文档,转换结果会合并进该文档(见下节)
keepHeadersreadonly string[][]需要保留为parameters[in=header]的请求头 key(不区分大小写)。默认会过滤掉传输层、内容协商与认证相关头(AcceptContent-TypeAuthorizationHost等)

6.1mergeOperation的底层原理

mergeOperation: true时,mergePathItem(src/helpers/merge-path-item.ts)会调用mergeOperations把同一路径同一方法的多个 operation 合并。为了避免示例名冲突,它会:

  1. 收集目标 path 上已有的示例名;
  2. generateUniqueValue生成不冲突的新示例名(例如Default example#1);
  3. 通过renameOperationExamples重命名新加入操作的示例;
  4. 同时更新x-postman-pre-request-scripts/x-postman-post-response-scripts等扩展字段的 key。

6.2requestIndexPaths:按需转换子集

对于大型集合,你可能只想转换其中部分请求。requestIndexPaths允许你通过零基索引路径精确选择:

import { convert } from '@scalar/postman-to-openapi' // 只转换 collection.item[0].item[2](文件夹或请求)下的所有请求 const result = convert(collection, { requestIndexPaths: [[0, 2]], })

从源码看,[0, 2, 1]表示collection.item[0].item[2].item[1]。越界或穿过非文件夹节点的路径会被跳过;同时 tag 只从被选中的路径的祖先文件夹中提取(extractTagContextsForSelectedPaths),避免引入无关 tag。

6.3tagNamingStrategy:控制 tag 生成

Postman 集合通常用嵌套文件夹组织请求。转换器默认使用leaf策略——只用最内层文件夹名作为 tag,例如Parent > Child > Leaf只生成 tagLeaf;如果不同父目录下存在同名叶子文件夹,会回退为Parent / Leaf以避免冲突。而chain策略则保留完整链,生成 tagParent > Child > Leaf

如果你希望 API 文档按完整目录树组织,选chain;如果希望更简洁,用默认的leaf即可。

6.4document:合并进已有 OpenAPI 文档

这是一个非常实用的特性:你可以把 Postman 转换的结果合并进一份已有的 OpenAPI 文档。合并规则(见 src/convert.ts):

  • 根级info与已有 paths 会被保留(除非 Postman 侧新增或合并了操作);
  • tags按名称取并集;
  • securitySchemesservers会去重合并;
  • 已有文档的externalDocs优先保留。

在 src/convert.test.ts 中有对应测试('merges into an existing OpenAPI document'),验证了合并后info.title仍为已有文档的'Existing'/health路径保留、新增的/v2/echo被加入、tagCore保留。

6.5keepHeaders:保留特殊请求头

默认情况下,转换器会过滤掉一些"传输层 / 内容协商 / 认证"头,避免它们在 OpenAPI 中变成无意义的parameters[in=header]。但如果你有一个 API 故意使用这些头名(例如自定义的Authorization语义),可以通过keepHeaders显式保留:

const result = convert(collection, { keepHeaders: ['Authorization', 'X-Custom-Accept'], })

七、服务器(servers)的智能放置

Postman 集合中的每个请求都有自己的 URL。转换器会为每个请求提取 server 对象(extractServerObjectFromUrl),并记录每个 server 在哪些 path / method 上被使用(ServerUsage)。

随后,analyzeServerDistribution(src/helpers/servers.ts)会根据使用频率决定 servers 的放置层级:

  • 所有或多数 path 都在用→ 放到文档级openapi.servers
  • 一个 path 内的多个操作在用→ 放到路径级pathItem.servers
  • 只有一个操作在用→ 放到操作级operation.servers

这种"就近放置"策略让生成的 OpenAPI 文档更符合规范推荐的覆盖语义,也避免在文档级堆砌一堆只在个别接口使用的 server。

此外,src/helpers/urls.ts 中的createCollectionVariableLookup会建立集合变量的查找表,因此在请求 URL 中出现的{{baseUrl}}等变量也会被解析到对应的 server 值中。

八、路径参数统一(Path Unification)

一个常见痛点是:同一资源在不同请求里使用了不同的路径参数名(如/users/{id}/users/{userId})。转换器通过unifyEquivalentPathParameters(src/convert.ts)自动处理:

  1. 对每个 path 计算"结构签名"(getPathStructuralSignature),忽略参数名只保留结构;
  2. 结构相同的 path 归为一组;
  3. 优先采用文件夹模板提示(如果某个文件夹名本身是/applications/{id}这样的模板,会从中提取参数名);否则取出现次数最多的参数名(chooseMostCommonName);
  4. 将所有同组 path 重写为规范参数名,并合并到一条规范 path 上。

这样最终输出的 OpenAPI 文档不会出现结构相同但参数名各异的冗余路径。

九、实际 fixture 一览

仓库在 packages/postman-to-openapi/fixtures/input 下提供了 26 个覆盖不同场景的输入 fixture(JSON),并被 src/convert.test.ts 以快照测试的方式逐一验证。它们是学习转换规则的最佳样例:

Fixture覆盖的转换场景
AuthBasic.json/AuthBearer.json/AuthMultiple.json/AuthRequest.json集合级与请求级的认证转换
DeleteOperation.jsonDELETE 操作与响应
EmptyUrl.json/NoPath.jsonURL 缺失或路径缺失时的兜底行为
ExternalDocs.jsonexternalDocs提取
Folders.json嵌套文件夹与 tag 生成
FormData.json/FormUrlencoded.jsonmultipart/form-dataapplication/x-www-form-urlencoded请求体
GetMethods.json/SimplePost.json基础 GET / POST 转换
Headers.json请求头到parameters[in=header]的转换与过滤
LicenseContact.json/XLogo.jsonlicensecontactx-logo提取
MultipleServers.json/NestedServers.json多 server 的放置策略
NoVersion.json缺少版本号时回退1.0.0
OperationIds.json请求名中[operationId]的解析
ParseStatusCode.json请求名中200 - xxx状态码解析
PathParams.json:param{param}的归一化
RawBody.jsonraw 请求体转换
Responses.json/ResponsesEmpty.json保存响应的提取与空响应兜底
UrlWithPort.json带端口的 URL 处理

每个 fixture 对应的快照输出位于 src/snapshots/convert.test.ts.snap,你可以对照输入与快照,直观理解每种 Postman 结构会生成怎样的 OpenAPI。

十、测试与验证方式

该包使用 Vitest 作为测试框架(见 package.json 中的"test": "vitest --run")。你可以通过以下命令运行全部测试:

pnpm test

测试覆盖包括:

  • 26 个 fixture 的快照测试;
  • convert的合并、tag 生成、参数处理等行为测试;
  • isPostmanCollection的识别测试;
  • 各 helper(auth、contact、external-docs、form-data、license、logo、markdown、parameters、responses、servers、status-codes、urls 等)的单元测试。

这些测试即是最好的"文档",它们精确说明了每个输入结构会得到怎样的输出。

十一、在 Scalar 生态中的位置

@scalar/postman-to-openapi是 Scalar API 平台数据导入能力的一环。转换得到的 OpenAPI 3.1 文档可以直接用于:

  • ScalarAPI References(交互式 API 文档);
  • ScalarAPI Client(离线优先的 API 客户端);
  • ScalarSDK Generator(生成 TypeScript / Python / Go / PHP / Java / Ruby 的类型安全 SDK);
  • 任何符合 OpenAPI 规范的生态工具。

这意味着:把 Postman 集合"解放"(Free the postman)为标准 OpenAPI 文档后,整个开放生态都向你敞开,这正是该包的核心价值主张。

十二、小结

能力说明
输入Postman Collection 对象或 JSON 字符串(v2.x格式)
输出OpenAPI 3.1 文档对象
认证basic / bearer / apikey / oauth / digest / awsv4 等
请求体raw / urlencoded / formdata / file / graphql
响应保存响应提取 + 请求名状态码约定 + Accept 推断媒体类型
高级选项mergeOperation/requestIndexPaths/tagNamingStrategy/document/keepHeaders
智能处理服务器就近放置、路径参数统一、tag 去重、内部扩展字段清理

使用@scalar/postman-to-openapi,你可以把组织内沉淀在 Postman 中的接口资产,一键沉淀为开放、标准、可被任意 OpenAPI 工具链消费的规范文档,实现"一次转换、处处可用"。


参考实现与测试:src/convert.ts · src/index.ts · src/is-postman-collection.ts · src/helpers/path-items.ts · src/helpers/servers.ts · src/convert.test.ts · fixtures/input

【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询