Scalar SDK Generator 完整指南:从 OpenAPI 文档生成多语言类型安全 SDK
【免费下载链接】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 官方 SDK Generator 文档为核心,系统讲解如何从团队既有的 OpenAPI 3.0/3.1 文档生成 TypeScript、Python、Go 等十余种语言的类型安全客户端库:覆盖目标语言与包注册表矩阵、"生成而非模板"的方法命名策略、重试/分页/流式/Webhook 等运行时能力、基于三方合并的自定义代码保留机制、通过 Pull Request 发布的版本管理模型,以及让编码 Agent 正确调用你的 API 的配套设计。读完后你将清楚 Scalar SDK Generator 的完整工作流、配置对象结构,以及如何把已有 Stainless 配置平滑迁移过来。
定位:OpenAPI-first 的 SDK 生成器
Scalar SDK Generator 的核心价值主张是:生成符合各语言习惯的类型安全客户端库,且代码生成在你自己的仓库中完成。你选择目标语言,几分钟内即可在预览仓库中审阅真实代码,再通过你自己控制的 Pull Request 从你自己的仓库发布包。
文档给出的典型生成产物长这样——同一个timeOff.listAssignments操作,在三种目标语言中的调用形态:
// TypeScript (index.ts) import WarpAPI from "warp-hr"; const client = new WarpAPI({ apiKey: process.env["API_KEY"], // defaults to the API_KEY env var }); const assignments = await client.timeOff.listAssignments();# Python (main.py) import os from warp import Warp client = Warp( api_key=os.environ.get("WARP_API_KEY"), ) time_off = client.time_off.list_assignments()// Go (main.go) package main import ( "context" "os" sdk "github.com/TeamWarp/warp-go-sdk" "github.com/TeamWarp/warp-go-sdk/option" ) func main() { client := sdk.NewClient( option.WithAPIKey(os.Getenv("WARP_API_KEY")), ) timeOff, err := client.TimeOff.ListAssignments(context.Background(), sdk.TimeOffListAssignmentsParams{}) if err != nil { panic(err) } _ = timeOff }三个细节值得注意:客户端以你的 API 命名并作为默认导出,import 读起来就像产品名;凭据默认来自约定俗成的环境变量,happy path 下不需要显式传入 secret;Go 版本遵循该语言的显式 error 处理惯例。每个目标语言都按其自身惯例编写,而不是从一个共享形状模板展开——这就是"Idiomatic per language"。
文档列出的八大核心特性:
- OpenAPI-first:从团队已维护的 OpenAPI 3.0 或 3.1 文档生成,Swagger 2.0 文档在加载时自动升级;
- 各语言习惯化:每个目标按该语言惯例编写,而非共享模板填充;
- 自定义代码存活:直接编辑生成文件,每次重建通过三方合并(three-way merge)把改动带下去;
- 内建认证:API Key、Basic、Bearer、OAuth 2.0、OIDC,全部从描述文件的 security schemes 接线;
- 通过 Pull Request 发布:版本、changelog、release 都以可审阅的 PR 形式落在你自己的仓库;
- CLI 目标:与 SDK 并发生成完整命令行客户端,带类型化 flag 和结构化输出;
- 流式与上传:SSE、NDJSON、WebSocket、multipart 文件上传;
- 为编码 Agent 就绪:每个 SDK 附带 Agent Skill 和生成式参考文档。
关于开源仓库与托管服务的边界:当前仓库(Scalar 开源 monorepo)中,documentation/guides/sdks/下的这一整套文档描述了 SDK Generator 产品本身;而 SDK 生成服务是 Scalar 的托管产品,生成发生在 dashboard 侧。开源仓库中包含的是 OpenAPI 工具链相关的包(如packages/openapi-parser/、packages/oas-utils/、packages/snippetz/、packages/themes/等),它们服务于 API 参考渲染与 OpenAPI 文档生态,可作为理解 Scalar OpenAPI 技术栈的入口。
目标语言与包注册表矩阵
每个目标都发布到其生态预期的注册表,工作流被直接生成进你的仓库。完整矩阵如下:
正式发布(Generally available)
| 目标 | 包注册表 |
|---|---|
| TypeScript | npm |
| Python | PyPI |
| Go | Go modules |
| CLI | npm 与 Homebrew |
实验性(Experimental)
| 目标 | 包注册表 |
|---|---|
| Java | Maven Central |
| Kotlin | Maven Central |
| Ruby | RubyGems |
| C# | NuGet |
| PHP | Packagist |
| Rust | crates.io |
| Swift | Swift Package Manager |
| Dart | pub.dev |
| C++ | 无标准注册表 |
正式发布的目标带有端到端测试:在每次变更时执行生成、构建,并对真实服务器运行。实验性目标生成可用的代码,其中 Java、Kotlin、Ruby、C# 位于同一套 CI 测试矩阵中——FAQ 部分进一步说明,这几者是最接近正式发布状态的,而 PHP、Rust、Swift、Dart、C++ 已能生成可用代码,但官方建议在依赖它们之前先与 Scalar 团队沟通。
生成,而非模板填充
模板式生成器机械地把每个 operation 映射成方法:结果能编译,但没人愿意对着它写代码——资源名词在每次调用中出现两遍,可选参数按位置传入,响应埋在 transport 对象后面。
模板式生成器产出:
import { Configuration, TimeOffApi } from "./generated"; const config = new Configuration({ basePath: "https://api.warp.dev", apiKey: process.env.WARP_API_KEY, }); const api = new TimeOffApi(config); const response = await api.timeOffListAssignmentsGet( undefined, // limit undefined, // cursor undefined, // options ); const assignments = response.data;Scalar 的产出:
import WarpAPI from "warp-hr"; const client = new WarpAPI({ apiKey: process.env["API_KEY"], // defaults to the API_KEY env var }); const assignments = await client.timeOff.listAssignments();文档指出两点完成大部分工作:客户端以 API 命名并作为默认导出,import 即产品名;凭据来自约定环境变量,happy path 无需传 secret。第三点是方法命名——Scalar 剥掉冗余的资源名词并归一化动词,使得同一组方法出现在每个资源上:
operationId | 模板式生成器 | Scalar |
|---|---|---|
listPets | client.pets.listPets() | client.pet.list() |
getPetById | client.pets.getPetById() | client.pet.retrieve() |
addPet | client.pets.addPet() | client.pet.create() |
在大型 API 上,这种一致性是"猜方法名"与"知道方法名"的区别。如需与其他生成器的完整对比,可参阅 Scalar vs Fern、Scalar vs Speakeasy 和 Scalar vs Stainless。
手写 SDK 具备的一切能力
类型
- 每个 operation 都有类型化的请求与响应模型,从 schemas 生成;
oneOf、anyOf、allOf降低为真正的联合类型,支持 discriminator;- 类型化错误,暴露状态码、headers、解析后的响应体与请求元数据;
- 按 operation 枚举的文档化错误状态码,失败处理不靠猜;
- 零运行时依赖(除非启用需要依赖的特性)——文档举例,生成的 Warp 包
"dependencies": {}为空。
网络
- 自动分页迭代器,覆盖十种分页方案:cursor、cursor id、cursor URL、offset、page number、
Linkheader、header token、body link、复合 cursor、hasMore; - 流式响应:SSE 与 NDJSON,保留事件元数据;
- WebSocket:Node 与浏览器分别有独立 adapter;
- AsyncAPI 通道(实验性):降低为类型化的 connect 与 streaming 方法,收发事件按事件类型区分;
- 文件上传:multipart、URL-encoded 或原始二进制;
- 多内容类型 operation获得内容类型选择器,而非靠猜。
可靠性
- 临时故障重试:默认两次尝试,覆盖网络错误、408、409、429 与 5xx 响应;
- 服务端发送
Retry-After时遵守之,否则使用可配置退避; - 超时默认 60 秒,可按请求覆盖;
- 幂等键:按请求使用你 API 期望的 header;
- 原始响应访问:可读取底层响应自行解析;
- 自定义 HTTP 客户端注入:接入你自己的 transport、中间件或埋点。
这些默认值(超时、重试次数)不是写死的,而是由 SDK 配置对象中的clientSettings驱动,例如:
{ "clientSettings": { "defaultTimeout": 30000, "defaultRetries": { "maxRetries": 2, "initialDelaySeconds": 1, "maxDelaySeconds": 10 } } }认证
- API Key:header、query 参数或 cookie;
- HTTP Basic 与 Bearer,Basic 拆分为独立的 username 与 password 选项;
- 描述文件中声明的OAuth 2.0 与 OIDC方案;
- 每个凭据都有环境变量默认值,quickstart 无需内联 secret;
- 异步凭据 provider:token 需要你自行获取或刷新时使用;
- 来自
webhooks与 operationcallbacks的类型化 Webhook 事件,带 HMAC-SHA256 签名校验、多密钥轮换与时间戳容差。
认证接线同样由配置对象描述。在clientSettings.opts中,每个选项可声明readEnv(环境变量名)、securityScheme(映射到 OpenAPI security scheme)与role,并可发送进 header、query、body 或 path 参数:
{ "clientSettings": { "opts": { "apiKey": { "type": "string", "description": "API key for Acme.", "readEnv": "ACME_API_KEY", "securityScheme": "apiKey", "role": "value" } }, "defaultHeaders": { "X-Acme-SDK": "true" }, "defaultEnvPrefix": "ACME" } }文档与 Agent
- Agent Skill:写入
SKILL.md与.claude/skills/,让编码 Agent 发现如何调用你的 API; - 生成的
api.md:按资源分组列出每个方法,请求与响应类型链接到源码; - 注入 OpenAPI 的代码示例:作为
x-codeSamples渲染在你的 API 参考中,手工整理的示例会被保留; - 生成的 README:认证、客户端选项、请求选项表格从描述文件自动填充;
- 在有异步对应形态的语言中提供异步版本,暴露相同的资源树。
发布
- 由 release-please 在你指定分支上管理版本与 changelog Pull Request;
- 面向十一个注册表的发布工作流生成进你的仓库,actions 按 commit SHA 固定;
- 注册表支持时启用可信发布(Trusted publishing),无需长期 token;
- 描述 SDK 表面实际变更的约定式提交(Conventional Commit)信息,破坏性变更会被标注;
- 冒烟测试:调用每个 operation 对 mock 服务器运行并汇报结果。
完整工作流:六步走通
第 1 步:从你的 OpenAPI 文档开始
把 API 文档放入 Registry,或在创建 SDK 时直接导入。支持 OpenAPI 3.0 与 3.1,Swagger 2.0 文档在加载时升级;AsyncAPI 文档实验性可用(见 AsyncAPI 文档),每个通道变成一个 WebSocket connect 方法或 HTTP streaming 方法。
具体操作路径(见 Getting Started):登录 dashboard 后点击 "Create new SDK",若 registry 中还没有文档可直接从弹窗导入,然后选择目标语言并点 Continue,Scalar 立即开始生成。
第 2 步:选择目标
可以选一个目标,也可以一次选十几个。生成立即开始,每个目标拥有独立的配置、版本历史与构建日志。
第 3 步:先读代码,再承诺任何东西
每个目标都会自动开一个预览仓库。在接入自己的仓库之前,你可以先浏览生成代码、api.md参考与 README。
第 4 步:链接你自己的仓库
连接 SDK 应存放的仓库。Scalar 通过 GitHub App 安装授权提交,从不使用个人 token。每次构建把生成产物推送到scalar-generated分支,在scalar-next上与你自己的定制代码合并,并针对你指定的分支保持一个开放的 release Pull Request。
第 5 步:从你的仓库发布
release-please 从你的提交历史计算 release PR 的版本并维护 changelog。合并后,仓库中的工作流切 tag、创建 GitHub Release 并发布包。包名、注册表账号、发布历史都留在你手里。详见 发布总览。
生成的发布机制是一组可以逐行阅读的文件:
| 文件 | 触发条件 | 作用 |
|---|---|---|
.github/workflows/sdk-ci.yml | push、pull_request | 安装依赖并构建 SDK,确保每个变更被检查 |
.github/workflows/release-please.yml | 推送到默认分支 | release PR 合并时切 tag、更新 changelog、创建 GitHub Release,并从内联publishjob 发布,再把 release 同步回scalar-next |
.github/workflows/release-title-edit.yml | pull_request | 运行 "Release PR version" 检查,把被编辑的 release PR 标题转化为Release-Ascommit |
.github/workflows/sdk-release.yml | workflow_dispatch | 手动重新发布已有 tag(仅当目标在 release 时发布才生成) |
release-please-config.json、.release-please-manifest.json | — | release-please 的配置与版本状态,manifest 初始化后归仓库所有 |
VERSIONING.md | — | 记录分支模型与版本选择方式 |
认证方面,默认在注册表支持时使用 OIDC 可信发布:publish job 在发布时换取短期 GitHub 身份 token,无需创建、存储或轮换任何 token;不支持 OIDC 的注册表(RubyGems、需要 GPG 签名的 Maven Central)改用仓库 secrets。版本由 release-please 从提交历史按 Conventional Commits 计算;若想指定精确版本,直接编辑 release PR 标题(如release: 1.0.0),等 "Release PR version" 检查变绿再合并。
第 6 步:让它跟随你的 API
每个 SDK 可以指向你 API 文档的精确版本,也可以指向^1.2.0这样的 semver 范围。当匹配的文档发生变更时,Scalar 铸造新的 SDK 版本并重建,一次提交即可更新所有目标。
配置对象:驱动生成的单一事实来源
上述流程背后的控制面是一个统一的配置对象,描述 SDK 名称、版本、目标输出、环境、资源树、客户端设置、分页、序列化与发布行为。最小配置示例:
{ "name": "Acme API", "environments": { "production": "https://api.acme.com" }, "environmentOrder": ["production"], "targets": { "typescript": { "packageName": "@acme/api" }, "python": { "packageName": "acme_api", "projectName": "acme-api" }, "cli": { "binaryName": "acme" } }, "resources": {} }必填属性:
| 属性 | 说明 |
|---|---|
name | 用于生成元数据与客户端的人类可读 SDK/产品名 |
resources | 定义生成客户端与资源形状的资源树 |
targets | 每语言的打包、发布与 emitter 选项 |
environments | 生成的客户端可切换的命名 base URL |
environmentOrder | 环境插入顺序,第一项即默认环境 |
targets下每个键对应一个产物,支持的键包括typescript、python、cli、go、rust、java、kotlin、swift、ruby、php、csharp、cpp、dart;把某目标的skip设为true可保留其配置但不生成它。resources定义公共客户端树,每个资源可包含生成方法、公共模型、嵌套资源、默认请求选项与按目标的可见性规则;用skip全局或按目标省略某个方法/模型/资源,用only限制到目标列表。
分页方案在pagination中定义为可复用条目,再由方法通过paginated引用,支持类型有cursor、cursorId、cursorUrl、offset、pageNumber:
{ "pagination": [ { "name": "cursor", "type": "cursor", "request": { "cursor": { "type": "cursor", "param": "cursor", "location": "query" } }, "response": { "items": { "type": "items", "location": "body", "path": ["data"] }, "next": { "type": "cursor", "location": "body", "path": ["next_cursor"] } } } ] }序列化行为由querySettings与multipartSettings控制:数组格式支持comma、repeat、indices、brackets,嵌套 query 格式支持brackets与dots。此外还有openapi覆盖块(如codeSampleLanguages、securitySchemes)、customCasings、ignoredEndpoints、errors、streaming、settings等选项。完整的字段说明在 配置文档,各语言的publish等专属选项见 configuration 子目录。
自定义代码在重新生成中存活
生成的 SDK 很少覆盖所有需求:你可能会加一个便捷方法、调整一个类型、写个 helper 或改进 README。Scalar 的设计是不让你在"定制"与"保持最新"之间做选择。
直接把生成文件当普通代码编辑。每次构建执行一次三方合并:比较上一次生成、本次生成、你仓库的当前状态,然后把组合结果放进一个 PR。未改动的文件干净更新,你的编辑随行,你自己新增的文件保持原样。
对想显式保留的代码,标记一个区域:
// scalar-sdk-generator:custom-code retry-helper:start export const withBackoff = async <T>(fn: () => Promise<T>) => { // Anything in here is carried forward on every regeneration. }; // scalar-sdk-generator:custom-code retry-helper:end冲突只会发生在重新生成的文件修改了你编辑过的同一行时。此时构建把冲突以 Pull Request 形式呈现,你在 GitHub 上像处理任何合并冲突一样解决。整个流程跑在可自检验证的受管分支上:
scalar-generated:纯净的生成器输出,永远不要直接提交到这里;scalar-next:生成输出与你的提交合并后的结果,你的定制提交应进入这个分支(直接推或走针对它的 PR);scalar-merge-conflict:承载需要人工处理的冲突。
冲突也可以在 dashboard 的 conflicts 视图中逐文件选择"生成版本"或"你的版本"来解决(详见 Custom Code)。官方建议:能独立成文件就独立成文件——新文件在自己的路径上永远不会冲突,优先新增 helper 文件而非在生成文件深处编辑。
为编码 Agent 而生
Agent 正在编写越来越多调用你 API 的代码,而它们也是最容易发明出不存在方法名的消费者。每个生成的 SDK 都附带防止这种情况所需的上下文:
- 位于
SKILL.md的Agent Skill,外加.claude/skills/<name>/SKILL.md用于自动发现,内容覆盖安装、客户端构造、认证,以及如何查找调用签名; - 生成的
api.md:列出每个 operation 及其请求与响应类型,设计上可直接放入 Agent 的上下文; openapi.augmented.json:把你的描述文件与生成的代码示例、安装元数据放在一起。
三者默认全部开启。
以"会发布的 SDK"为基准的测试
SDK 生成器的价值取决于其产物能存活什么,因此这里的工程重心是测试而非模板:
- 与已发布 SDK 的对齐(parity):测试框架把生成产物与公司在生产环境实际发布的客户端库对比,对比维度包括公共 API 形状与真实 wire traffic——在固定的 commit 上克隆生产 SDK,从双方提取公共表面,在 operation 覆盖度、wire 形状、联合类型、枚举、分页行为、必填性、参数位置上出现漂移即失败;然后驱动两个客户端对录制 mock 跑完所有共享 operation,diff 它们发出的请求;
- 每目标冒烟测试:生成的测试框架对 mock 服务器调用每个 operation,汇报哪些失败。
从 Stainless 迁移
Stainless 正在关停其托管 SDK 生成器。Scalar 直接读取你现有的stainless.yml:资源、方法名、分页方案、各语言包名都会带过去,你的用户已经写好的调用点继续可用。实际步骤见 Stainless 迁移指南,产品对比见 Scalar vs Stainless。
定价结构
每个方案都包含一个 SDK 目标,价格随 SDK 规模(以 OpenAPI 文档中的 endpoint 数衡量)递增:Pro 上每个额外目标 $150/月,Business 上每个额外目标 $600/月。
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| 包含的 SDK 目标数 | 1 | 1 | 1 | 定制 |
| 包含的 SDK 规模 | 最多 25 个 endpoint | 100 个 endpoint | 250 个 endpoint | 定制 |
| 额外目标 | - | 每个 $150/月 | 每个 $600/月,量大从优 | 量大从优 |
| 试用期内所有目标免费 | 包含 | 包含 | 包含 | 包含 |
| SSO/SAML | - | - | 包含 | 包含 |
| RBAC、优先支持、专属 Slack/Teams 支持 | - | - | - | 包含 |
目标在你保存版本并排队构建时才开始计费,草稿永不计费。完整方案对比见 定价页。
常见问题
哪些目标是生产就绪的?TypeScript、Python、Go 与 CLI 目标为正式发布;其余在 dashboard 中标记为实验性。Java、Kotlin、Ruby、C# 位于与正式发布目标相同的 CI 矩阵中,是最接近的;PHP、Rust、Swift、Dart、C++ 能生成可用代码,但建议先沟通再依赖。
我拥有生成的代码吗?是。SDK 在你的仓库中、用你的包名、发布到你的注册表账号。Scalar 只对它开 Pull Request,从不代表你切 tag 或发 release。
我手写的代码会怎样?会保留。每次构建都对新生成物与你仓库的当前状态做三方合并,你的编辑存活;被标记的 custom-code 区域显式保留,你自己新增的文件绝不被触碰;冲突以 Pull Request 形式到达,由你在 GitHub 上解决。
SDK 可以发布到哪里?npm、PyPI、Go modules、Maven Central、RubyGems、NuGet、Packagist、crates.io、Swift Package Manager、pub.dev,CLI 目标还有 Homebrew。发布从生成进你仓库的工作流运行,actions 按 commit SHA 固定,注册表支持时启用可信发布。
支持哪些认证方案?header/query/cookie 中的 API Key、HTTP Basic、Bearer token,以及描述文件中声明的 OAuth 2.0 与 OIDC 方案。每个凭据有环境变量默认值,也可提供异步 provider 自行获取或刷新 token。
我的 OpenAPI 文档需要完美吗?不需要。Scalar 从你现有的文档生成起步配置,覆盖命名、分页与认证;之后你在配置编辑器中精化,而不是重写描述文件。
SDK 如何与 API 保持同步?每个 SDK 按精确版本或 semver 范围跟随其 API 文档。匹配文档变更时,Scalar 铸造新的 SDK 版本、重建所有目标并开 Pull Request——对 API 的一次提交会更新所有客户端。
下一步
- 按 Getting Started 从 dashboard 生成第一个目标;
- 用 Managing 构建、版本化并下载 SDK;
- 按 Publishing 链接 GitHub 仓库并发布到注册表(发布是选择性开启的,默认关闭,合并 release 前不会发布任何东西);
- 阅读每次构建对你 API 描述报告的 Diagnostics——每个构建都会分析 OpenAPI 文档与配置,汇报生成时不得不停止、猜测或降级的地方,并可用
diagnostics.failOn(取值off/info/warn/error,默认error)、maxWarnings与按规则的rules覆盖来控制哪些发现会令构建失败; - 已有 Stainless 配置的话,直接迁移,资源与方法名的连续性会保留。
【免费下载链接】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),仅供参考