REST、GraphQL 和 gRPC 的自动化样式指南

2025-06-10

REST、GraphQL 和 gRPC 的自动化样式指南

如果你问 100 位开发者分号应该放在哪里,你要么会得到 100 个答案,要么会引发一场群殴。为了避免这种情况在工作中发生,大多数人会制定代码风格指南,这不仅有助于保持一致的风格,还能避免新开发者因为“做错了”而被训斥。Linter 可以建议最佳实践,指出技术上允许但可能引发问题的代码,并在编写代码时调整 API(比如用蛇形命名法!)。代码的编写通常都会这样做,而且在 API 描述中也越来越流行。

JavaScript 用户有eslint,PHP 用户有PHP Code Sniffer,Ruby 用户有rubocop。这些 linters 不仅仅检查用户编写的语法是否有效,还会根据现有的规则集进行检查,这些规则集有时由公司制定,例如几乎成为事实上的标准eslint-airbnb。有时,规则由标准机构制定,例如PHP-FIG制定的 PSR-12 规则集,这些工具会创建一个与之匹配的规则集,例如CodeSniffer 的 PSR-12 规则集

今天我甚至不得不使用awesome-lint来确保awesome-earth符合他们的规则,这些规则是使用Remark Markdown linter 构建的。

说到 API 描述,大多数规模一定规模的公司最终都会有一份“样式指南”、“样式书”、“设计指南”等等。这些文档通常保存在 Google 文档、Wiki 或其他文档/内容管理系统中。我见过很多这样的文档,也写过不少。很多公司甚至会发布它们

基于文本的样式指南很浪费时间

这些基于文本的文档的问题在于,它们篇幅庞大、简洁、乏味,开发人员很少会阅读。即使开发人员从头到尾读完,记住了所有内容,当新规则加入时,这些知识也会部分过时,因为他们需要重新从头到尾阅读一遍才能了解这些规则。

API 文档大会上,我看到了 Salesforce 的Kelsey Lambert的演讲。他们的风格指南就是一个 OpenAPI 描述文档的例子,他们要求大家在开发过程中不时查看一下,了解应该使用哪些东西。Salesforce……这家巨头公司拥有 238479347 个 API,每个 API 维护 40 个主要版本,他们执行风格指南的方法就是目测和记忆。唉,我真同情你们!我以前也遇到过这种情况,感觉很糟糕。

任何开发者都不应该为这种混乱负责。API 开发者非常忙碌,而编写样式指南的人则只能边做边摸索。这种混乱是行业普遍存在的问题,但值得庆幸的是,一些工具已经出现,可以通过自动化来强制执行相同的样式指南概念。

这些项目中的每一个都着手做相对类似的事情,但针对不同类型的 API。

HTTP API 的 Spectral

Spectral 是一个 JSON/YAML 数据检查器,内置了 OpenAPI v2/v3 和 JSON Schema 的规则。

在普通文档上运行默认的 OpenAPI 规则集会发现很多建议,这对于不太熟悉 OpenAPI 的开发者来说很有帮助。一些小建议,比如提醒人们添加,parameter-descriptions都能帮助文档变得更易读,而他们可能甚至还没有意识到这一点。

替代文本

您可以使用 Spectral 创建规则集,并且这些规则集可以具有自定义规则,甚至自定义功能!

这些自定义规则看起来有点像这样:

rules:
  schema-names-pascal-case:
    description: Schema names MUST be written in PascalCase
    message: '{{property}} is not PascalCase: {{error}}'
    recommended: true
    type: style
    given: '$.components.schemas.*~'
    then:
      function: pattern
      functionOptions:
        match: '^[A-Z][a-zA-Z0-9]*$'

这个比较流行。OpenAPI 并不介意你的模型名称如何大写,但很多代码生成器会使用模型名称来编写代码,而不一致的类名会让人感到不爽。

让我们更进一步:

rules:
  paths-kebab-case:
    description: Should paths be kebab-case.
    message: '{{property}} is not kebab-case: {{error}}'
    severity: warn
    recommended: true
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        match: "^(\/[a-z0-9-{}]+)+$"

这条规则实际上超越了 API 描述的元数据,而是关注 API 本身的实际设计。这意味着“路径”(端点)必须使用连字符,这/recent-files虽然好,但/recent_files并不可行。

您可以开始真正发挥创造力。

rules:
  no-x-headers:
    description: "Please do not use headers with X-"
    message: "Headers cannot start with X-, so please find a new name for {{property}}. More: https://tools.ietf.org/html/rfc6648"
    recommended: true
    given: "$..parameters.[?(@.in === 'header')].name"
    then:
      function: pattern
      functionOptions:
        notMatch: '^(x|X)-'

我不知道为什么,但在任何给定 API 的生命周期中,总有开发人员会建议添加X-Foo标头,尽管它在过去十多年里一直存在问题。好吧,我们可以用这条规则把他们拒之门外。

如果尽早完成,这将在实际开发过程中塑造 API。如果您先写代码,那么好吧,您必须回头修改一堆代码。希望您没有发布它,因为现在您需要为 进行一堆重定向/recent_files /recent_files。如果您使用API 设计优先的工作流程,那么当您刚获得一些 YAML 时,您就会尽早注意到这一点,并且您的 API 从一开始就构建正确。

由于 Spectral 是一个 CLI/JS 工具,因此可以
通过各种方式来执行此样式指南。

如果您使用Stoplight Studio,那么它已内置于编辑器中,因此设计 API 的人员可以立即正确完成所有操作。无需切换到 CLI 或等待 PR 生成。

我正在努力抽出时间,从HerokuPayPal中获取一些样式指南,并将它们整理成一个庞大的示例规则集。至少,这能为我正在整理的新规则集(OpenAPI Contrib > 样式指南)提供一些灵感。这应该会是一个有趣的社区成果。

Spectral 还拥有GitHub ActionGitHub Bot,我们正在努力改进。评论范围和建议功能即将推出!😎

GraphQL Doctor 和 Schema Linter

GraphQL 有自己的内置类型系统,其中有一些与基于 OpenAPI / JSON Schema 相同类型的关键字。

GraphQL 简化了一些设计决策,例如如何处理关系。无需在嵌套/嵌入相关资源、使用复合文档内联所有内容或使用超链接链接到相关数据之间做出选择,GraphQL 会为您做出决定。然而,除了 GraphQL 的默认决策之外,还可能出现很多不一致的情况。GraphQL 开发人员无法逃避 lint 的需要,但幸运的是,有一个很棒的 lint 工具:GraphQL Schema Linter

你也可以为此编写自定义规则,这样你就可以在 CI 中自动化你的样式指南。我目前没有看到任何机器人或 GitHub Action,但它们的组合并不难。

GraphQL 领域中一款拥有出色机器人的架构工具是 GraphQL Doctor。它似乎希望在整体上提供更多 linting 方面的帮助,但目前为止,它专注于检测重大变更。与任何类型系统一样,谨慎的演进和鲁莽的更改之间存在着一线之隔,而 GraphQL Doctor 能够识别后者。

graphql doctor bot 的预览,评论 GitHub 拉取请求,显示发生故障的行

看到这两个工具合并会很好,或者 GraphQL Doctor 机器人可以支持 GraphQL Schema Linter,但目前它是一个两站式商店。

Google 的“API Linter”

Google 在 API 领域做了一些非常有趣的工作。他们是 API 领域首批坚持“有时你需要 REST,有时你需要 RPC”的巨头之一,并且他们还在持续推进这一理念,开发一个适用于gRPC 和 HTTP 的通用工具。API linter 运行在 protobuf 表层,但可以设置为与 HTTP 端点配合使用:

使用协议缓冲区时,每个 RPC 必须使用 google.api.http 注释定义 HTTP 方法和路径:

rpc CreateBook(CreateBookRequest) returns (Book) {
  option (google.api.http) = {
    post: "/v1/{parent=publishers/*}/books/*"
    body: "book"
  };
}

message CreateBookRequest {
  // The publisher who will publish this book.
  // When using HTTP/JSON, this field is automatically populated based
  // on the URI, because of the `{parent=publishers/*}` syntax.
  string parent = 1;

  // The book to create.
  // When using HTTP/JSON, this field is populated based on the HTTP body,
  // because of the `body: "book"` syntax.
  Book book = 2;

  // The user-specified ID for the book.
  // When using HTTP/JSON, this field is populated based on a query string
  // argument, such as `?book_id=foo`. This is the fallback for fields that
  // are not included in either the URI or the body.
  string book_id = 3;
}

API Linter 的核心规则相当令人印象深刻,它重点关注了 HTTP 规范中一些不太清晰的棘手部分。比如,GET 请求应该包含正文吗?答案很模糊,也许可以,但也可能没有,这取决于你构建的工具,唉。求助。

谷歌决定直接回答:不。

他们还决定说服团队从 proto2 升级到 proto3。

规则理念

您可以使用这些东西自动执行几乎任何操作,并且我一直在思考许多
规则,这些规则超出了强制命名或复数化的常见用例。

安全

  • 完全禁止 HTTP Basic
  • 确保每个端点都具有某种安全性(OAuth 2、API 密钥,但不能同时具有)
  • 每个响应都应该支持application/vnd.api+json(JSON:API),而不仅仅是普通的 JSON
  • 使用整数 ID 可以让人们非常轻松地抓取你的 API,请切换到 UUID

错误

  • 你的20X回复好像有错误,你为什么讨厌你的消费者
  • 您的错误中没有 URL,如何才能找到有关出错的更多信息
  • 错误格式应为RFC 7807

版本控制

这些规则很多都是针对 HTTP API 的,不过你应该已经明白了。以后我会完善其中一些规则,并将它们添加到 OpenAPI Contrib 的样式指南中。如果你也想贡献代码,我很乐意在 GitHub 上指导你完成整个过程。

概括

如果你听说过“API 治理”这个词,那么这几乎就是大多数人都在谈论的内容。目前,许多试图进行治理的人都在仔细查看每个 PR 上的 API 描述,并培训人们记住他们提出的所有质量规则。

手动 API 培训是一项吃力不讨好、效率低下且永无止境的任务,它可以被编辑器、git hook、CI 管道、GitHub Action 或机器人内置的 linter 所取代(或大幅简化)。

不要浪费客户的时间,强迫他们尝试找出你的不一致之处。不要浪费所有 API 开发人员的时间去学习死记硬背样式指南。不要浪费 API 治理团队的时间去手动审查 API。不要浪费所有人的时间在生产环境中修复不一致之处。

鏂囩珷鏉ユ簮锛�https://dev.to/philsturgeon/automated-style-guides-for-rest-graphql-and-grpc-3ci0
PREV
原始 JS 中的双向数据绑定(POC)
NEXT
Web 货币化 API 的 Web 组件 <💰> Web 货币化组件 </💰>