🥊 Gato GraphQL vs WPGraphQL:对决!
2024年05月01日更新: 请查看 Gato GraphQL vs WPGraphQL 对比文章。
女士们,先生们!!!!!!!!!!!!!!

欢迎来到MGM大花园竞技场,见证本世纪的年度之战!今晚,我们将创造历史。两位年轻斗士将在擂台上正面交锋,争夺他们为之付出无数心血的奖项:
成为 "WordPress GraphQL" 世界冠军 🏆
在我们的右侧,是现任冠军。尽管只有4年历史,但他已经经验丰富——最近发布了1.0版本,并在wp.org目录上线,在众多用户中享有极高的人气。
🥁 请以热烈 🥁 的掌声 🥁 欢迎 🥁 !!! 🥁 ...... WPGraphQL!

在我们的左侧,是挑战者。他进入这个世界还不到1个月,但他充满活力和野心,从第一天起就展示了自己的实力。正是他主动寻求了今天的相遇。今晚是他的机会,全世界都在关注。
🥁 请以热烈 🥁 的掌声 🥁 欢迎 🥁 !!! 🥁 ...... Gato GraphQL!

今晚,两位选手将首次正面交锋,进行12回合的比赛。当他们在擂台中央就位,等待开场铃声时,他们互相审视,试图找出对方的弱点。然而,双方都只展现出自信的神态。

谁会胜出?WPGraphQL能凭借支持者的力量维持优势吗?还是新来者Gato GraphQL会让毫无戒备的观众折服于他拳头的威力,让人群转而站到他这边?
今晚,女士们先生们,我们将揭晓答案。
下好你们的赌注,享受比赛!
🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣
最近有人请我解释我的插件 Gato GraphQL 和 WPGraphQL 之间的区别。
这两个插件都是 WordPress 的 GraphQL 服务器,因此它们服务于相同的目的。然而,在底层它们具有不同的特性,这可能使其中一个在满足某些特定需求时优于另一个。
尽管我对自己的插件有所偏向,但我尝试基于我认为对 GraphQL 和 WordPress 都重要的主题进行公正的比较。(如果读者希望就其他主题进行比较,我很乐意满足。)
这个比较并不详尽。例如,我也想进行一些基准测试,衡量两个服务器解析同一个 GraphQL query 的速度。(如果读者对这个提议感兴趣,我可以在后续文章中进行。)
我将比较分为4个主要领域:人气、代码风格与标准、关键问题,以及扩展范围,每个领域各有3个项目,共12个"回合"。最后,评委给出裁决,决出冠军。
点击以下链接直接跳转到某个主题:
🔔 当 🔔 当 🔔 当当当...
开场铃声响起了...
比赛开始!
人气
任何软件(或技术)都必须有人使用,否则它比其他选择更好只是一件趣事而已。
例如,尽管有一些打字更快的替代方案,我们仍然主要使用 QWERTY 键盘。
这两个插件有多受欢迎?
第1回合:谁在使用它,以及它有多完整
WPGraphQL 迄今为止一直是 WordPress 中 GraphQL 的代名词。在超过4年的开发期间(自2016年11月开始),它在仓库中积累了超过2800颗 star,建立了超过4600名关注者的社区,并拥有近100位项目贡献者。
它达到了1.0版本,并于2020年11月上传至 wp.org 插件目录。此后,它已积累了超过8000个活跃安装。目前,它是将 WordPress 内容引入 Gatsby 的唯一解决方案,最近,多个项目已将其纳入技术栈,包括 WPEngine 的 Headless 框架和 WebDevStudios 的 Next.js WordPress 入门模板。
总而言之,WPGraphQL 很受欢迎。
Gato GraphQL 的正式开发约在1.5年前开始(作为一个更大项目的一部分),并在6个月前达到了"足够好"的状态,此后在仓库中获得了150颗 star。该插件目前处于0.7版本,距离发布1.0版本还有几个月(例如,schema 中还没有分类功能)。
上个月我建立了这个当前的网站 gatographql.com,此后我通过博客(就像你现在正在阅读的这篇文章)宣传插件,也在 CSS-Tricks 上发布了一篇介绍文章。这些努力带来了几百人访问网站,超过100位访客下载了插件。
总而言之,Gato GraphQL 正在缓慢但稳定地积累人气,目前仍在开发中。
本回合获胜者:WPGraphQL。

第2回合:扩展插件的可用性
扩展插件使 Gato GraphQL 能够与其他插件进行交互。
WPGraphQL 有适用于 ACF、WooCommerce、Yoast 等的扩展插件。
Gato GraphQL 目前还没有扩展插件,我预计在发布1.0版本之前不会有太多扩展插件。
但是,Gato GraphQL 的架构非常重视扩展插件,允许用户从一个集中的位置——"Modules"页面——来管理它们(启用、禁用、配置和查看文档):

总而言之,WPGraphQL 已经拥有扩展插件,而 Gato GraphQL 正在为此做好准备。
本回合获胜者:WPGraphQL。

第3回合:目标用户
WPGraphQL 面向开发者:如果你想从 WordPress 网站中提取数据,你需要将 GraphQL query 存储在代码的某处(很可能是在某个 JavaScript 函数中)。然后,为了能够使用它,你需要具备足够的编程能力。
而 Gato GraphQL 则遵循 WordPress 的理念,任何人都应该能够使用它,包括非技术用户。为了实现这一目标,它允许通过 WordPress 编辑器创建和管理 GraphQL query,使通过 API 访问 WordPress 网站数据变得和创建博客文章一样简单。
此外,Gato GraphQL 更强调为用户提供以可视化方式与 GraphQL 服务交互的客户端。虽然两个插件都提供 GraphiQL 客户端来执行 query,但只有 Gato GraphQL 还提供了 Voyager 客户端,用于交互式地探索 schema:

本回合获胜者:Gato GraphQL。

代码风格与标准
让我们来聊聊代码!
如果你在使用 GraphQL,很可能你正在做 headless WordPress,并使用某个 JavaScript 框架来渲染网站,这是一种现代范式。此外,WordPress 可能是一个老旧的 CMS,但 GraphQL 是访问网站数据的现代接口。因此,我可以放心地假设你是一位明智的开发者,热衷于编写优雅的代码,并且不会接受使用次优的解决方案。
这两个插件的代码(来自它们自己的代码库,以及我们自定义实现所期望的代码)有多优雅?
第4回合:PHP 要求
WPGraphQL 和 Gato GraphQL 都要求 PHP 7.1+。
但是有一个区别:Gato GraphQL 实际上是使用 PHP 7.4 编写的,然后在生产环境中转译为 PHP 7.1。
因此,编写 Gato GraphQL 的代码更加愉快:你可以使用更新的 PHP 特性,包括 object 类型、类型化属性和箭头函数。一旦添加了对 PHP 8.0 的支持(这将在新版本的 Lando 发布时实现),你还将能够使用联合类型、match 表达式等。
本回合获胜者:Gato GraphQL。

第5回合:编码实践
让我们先从 WPGraphQL 开始。前往 wp-graphql/wp-graphql 仓库,有一件事让我注意到:

放大来看:

抱歉,对此我只有一种反应:

将 Composer 的 vendor 文件夹提交到仓库是一种不良实践,Composer 明确不鼓励这样做。
修复这个问题并不难(我甚至描述了一种基于 GitHub actions 的方法),所以我很想知道为什么会这样。
我认为,在这一回合中,WPGraphQL 是在打自己!

继续。为 WPGraphQL 开发需要了解一个超级庞大的钩子(actions 和 filters)集合。前往 WPGraphQL 的开发者参考文档,可以了解其规模之大。
为了截取 actions 列表的截图,我不得不将浏览器缩放到50%:

对于 filters 列表,我缩放到30%(Firefox 支持的最低值),即便如此也无法显示完整列表:

让我们切换到 GatoGraphQL/GatoGraphQL 仓库,这是包含 Gato GraphQL(以及其他项目)的 monorepo。
以下是代码的一些特点:
✅ 所有代码被拆分为多个原子包,所有这些包(插件超过100个,整个项目超过200个)都托管在同一个 monorepo 中。
✅ 使用 Composer 管理所有依赖项。
✅ 使用 Symfony Dependency Injection 管理应用中的所有服务。要注册新的类型解析器、字段解析器或指令解析器,只需在容器中注册一个新服务即可。
✅ 每个类都是一个服务,Symfony Dependency Injection 负责整个应用的自动装配。
✅ 底层 GraphQL 服务器与 CMS 无关。Gato GraphQL 实现了 WordPress 的契约,并添加了一些自定义逻辑(例如,提供客户端)。
WordPress 特定的代码只占整体代码的约10%。将这10%复制到另一个框架或 CMS(Laravel/Drupal 等)可以为它们提供 GraphQL 服务器的实现。
✅ 由于与 CMS 无关,编写解析器意味着编写其通用业务逻辑,由可复用的服务提供支持。我们从不以 WordPress 代码的方式思考,也很少需要处理其技术债务。
✅ 同样地,GraphQL schema 不是 WordPress 数据模型的1:1副本,绕过了 WordPress 在数据层积累的技术债务,提供了一个干净的接口。
✅ GraphQL 的 N+1 问题不会发生,这是架构设计的结果,且完全不会给开发者带来麻烦。
✅ 服务器不仅仅是一个 GraphQL 服务器:它实际上是一个 API 服务器,可以从单一的真实来源以其他格式或规范(如 REST)输出响应。(第11回合将详细介绍。)
✅ 不提交 vendor 目录。相反,源代码被转换为分发代码(即在 WordPress 网站上安装的最终插件),通过 GitHub actions 部署到一个 dist 仓库,在那里确实包含了 vendor 文件夹。
✅ 生成分发代码时,使用 PHP-Scoper 进行作用域限定,包含 PHP 7.4 代码的源代码被转译为 PHP 7.1。
✅ 由于已解决作用域问题,插件可以依赖任何第三方依赖项。目前,它使用了 Symfony 的 DependencyInjection、Cache 和 Dotenv、Guzzle(用于与外部 API 交互)、The League 的 Pipeline 等。
这不仅对现在重要,对未来也很重要:我可以确信能够使用 Packagist 仓库中的任何依赖项,所以无需重复造轮子。
✅ 字段订阅到类型,使 GraphQL schema 易于扩展。
本回合获胜者:Gato GraphQL(如果你不介意的话,我敢说是大比分获胜)。

第6回合:扩展 schema
让我们向 GraphQL schema 添加一个字段。
我们遵循 WPGraphQL 的教程。建议的代码如下所示。它声明了一个 action 钩子来执行一个声明数组的函数。字段的描述及其解析都在数组中提供:
add_action( 'graphql_register_types', function() {
register_graphql_field( 'RootQuery', 'myNewField', [
'type' => 'String',
'args' => [
'myArg' => [
'type' => 'String',
'description' => __( 'Description for how the argument will impact the field resolver', 'your-textdomain' ),
],
],
'resolve' => function( $source, $args, $context, $info ) {
if ( isset( $args['myArg'] ) ) {
return 'The value of myArg is: ' . $args['myArg'];
}
return 'test';
},
]);
});这个示例已经尽可能简单:解析器基本上什么都不做。但是,我已经很难一眼看懂这段代码的功能。不,我不是在嘲讽:编辑器中该代码的所有颜色都在争夺我的注意力。此外,没有关注点分离,代码似乎也不是很可复用。
因此,在开发应用程序时,让代码易于阅读、可复用、无 bug 等,将取决于开发者(也就是你);库本身在这方面似乎帮助不大。
我把这种风格称为"ADD":Array-Driven Development(数组驱动开发)。我不能说我是它的粉丝。
(公平地说,对于 WPGraphQL 而言,这是一种标准的编码实践,也是底层引擎 webonyx/graphql-php 所采用的方式。)
在 Gato GraphQL 中,所有代码都是 SOLID 的。要在 GraphQL schema 中注册一个字段,我们创建一个实现 FieldResolverInterface 接口的类(实际上是继承自 AbstractSchemaFieldResolver,它已经实现了许多方法),然后在容器中注册它。
例如,这段代码为 User 类型提供了 username、email 和 url 字段:
class UserFieldResolver extends AbstractSchemaFieldResolver
{
public static function getClassesToAttachTo(): array
{
return [
UserTypeResolver::class,
];
}
public static function getFieldNamesToResolve(): array
{
return [
'username',
'email',
'url',
];
}
public function getSchemaFieldDescription(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
$descriptions = [
'username' => $this->translationAPI->__("User's username handle", "users"),
'email' => $this->translationAPI->__("User's email", "users"),
'url' => $this->translationAPI->__("URL of the user's profile in the website", "users"),
];
return $descriptions[$fieldName];
}
public function getSchemaFieldType(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
$types = [
'username' => SchemaDefinition::TYPE_STRING,
'email' => SchemaDefinition::TYPE_EMAIL,
'url' => SchemaDefinition::TYPE_URL,
];
return $types[$fieldName];
}
public function resolveValue(TypeResolverInterface $typeResolver, object $user, string $fieldName, array $fieldArgs = [])
{
switch ($fieldName) {
case 'username':
return $this->usersAPI->getUserLogin($user);
case 'email':
return $this->usersAPI->getUserEmail($user);
case 'url':
return $this->usersAPI->getUserURL($user);
}
return null;
}
}我确实认为我的解决方案比 WPGraphQL 的更优雅。但这是个人喜好问题。我知道很多开发者不介意 Array-Driven Development,实际上更喜欢它,因为在一块紧凑的代码中可以实现所有逻辑。
本回合结果:平局。

中场休息
多么精彩的一夜啊,女士们先生们。

我们已经到达了比赛的中途,这是上厕所休息并对目前经历进行评论的好时机。
(与此同时,我应该展示我的赞助商的广告。遗憾的是,我还没有任何赞助商。如果你希望你的公司资助 Gato GraphQL 的开发,并在这样的黄金媒体活动中获得曝光,请给我发消息。)

多么精彩的比赛啊!WPGraphQL 一开始就如火如荼!他以极佳的状态开局,向 Gato GraphQL 发出了可怕的重拳,而 Gato GraphQL 几乎难以站稳脚跟。一拳接一拳。我不想成为 Gato GraphQL。
我必须承认,在前2个回合之后,我以为比赛很快就会结束。我随时都在等待倒地击倒的出现。等着看那条摇晃的毛巾求饶。但 Gato GraphQL 坚持住了。我们必须承认这一点。多么坚不可摧的意志,真是令人叹为观止!
然后,转变发生了。从第3回合某处开始,Gato GraphQL 似乎从某处获得了能量,不仅开始防守,还开始反击,许多拳头落在了 WPGraphQL 的脸上。我看到 WPGraphQL 在颤抖和摇晃!我们从未见过现任世界冠军出现这种情况。我们刚刚目睹了多么真实的惊人转变啊!
然后,在动摇了对手的信心之后,从第4回合开始,Gato GraphQL 决意给出一系列致命打击。那真是令人震惊!幸运的是,与他对阵的是我们的世界冠军 WPGraphQL,他在观众的欢呼和同情声中承受住了打击。他真是英雄!其他任何人早就倒下了,但他没有,他以冠军的身份承受了这些打击。
但他还能做冠军多久呢?还没有人被击倒,还没有人扔毛巾。比赛随时可能出现决定性转折。两位斗士知道自己想要什么,我相信他们会以全部实力和决心再次出击,击败对手,取得胜利。
多么精彩的比赛啊!
现在,女士们先生们,两位勇士回到了擂台上。

继续剩余的比赛!
关键问题
GraphQL 服务器需要关注许多方面,仅仅为了满足"获取你所需的数据,不多也不少"这一命题。
例如:
- 它有多安全?我们如何确保不在公共端点上暴露私人数据?
- 它性能如何?在反复发送相同 query 时,我们如何减少服务器负载,同时使其尽可能快速?
- 它有多简单?它与 WordPress 的集成有多好,以便充分利用 CMS 提供的功能?
还有许多其他问题。这只是我选择的一个小样本,我将在以下3个回合中处理这些问题。
第7回合:Persisted queries
Persisted queries 结合了 GraphQL 和 REST 的优点:它们使用 GraphQL 创建,因此没有数据的欠获取/过获取,但它们作为具有自己 URL 的端点发布在服务器上。
Persisted queries 具有以下好处:
✅ 安全:与其通过单一端点提供对任何数据的访问,我们可以预定义要公开的数据。
✅ 快速:通过其自己的 URL 访问,可以使用标准 HTTP 缓存在客户端和后端之间的每一层(服务器、CDN、浏览器)进行缓存。
WPGraphQL 通过这两个扩展插件提供对 persisted queries 的支持:
此外,Jason Bahl(WPGraphQL 的创建者)最近宣布,在不久的将来,他将在 WPGraphQL 中添加对 persisted queries 的支持。
我很想知道他的想法,因为已经有2个扩展插件了。这将与它们有何不同?也许他想把它作为插件核心的一部分,以便在不依赖第三方的情况下加强整体插件的安全措施?
或者也许他看到了 Gato GraphQL 的实现,想提供类似的体验,通过可视化编辑器而不是纯代码来操作?
这就引出了 Gato GraphQL。它不仅提供 persisted queries,而且努力使其成为产品的核心部分:
✅ 插件支持禁用单一端点,鼓励用户只通过 persisted queries 公开数据。
(相比之下,WPGraphQL 默认只禁用 introspection,而不是实际的端点。换句话说,攻击者仍然可能访问私人数据;只是让他们的任务更难了,因为他们事先不知道有哪些私人数据。)
✅ 它与 WordPress 编辑器深度集成,因此创建 persisted query 与创建博客文章一样容易,任何人都可以做到,不只是程序员。
✅ Persisted queries 不是静态的:它们可以使用 GraphQL 变量,变量的值可以在执行端点时通过 URL 参数提供。
查看在我的插件中创建和执行 persisted query 的体验:
本回合获胜者:Gato GraphQL。
第8回合:缓存
GraphQL 有一个很大的痛点:它不容易缓存。原因是它依赖于向单一端点发送 POST 操作。由于单一端点会产生不同的结果,并且 query 是在请求体中而不是 URL 参数中发送的,所以我们无法缓存单一端点。
许多 GraphQL 服务器提供的标准解决方案是将缓存转移到客户端,并依赖对象的 ID 作为要缓存的实体的标识符,而不是端点的 URL。提供此功能最流行的库是 Apollo 客户端。
WPGraphQL 仓库中有一个关于 WPGraphQL 所有可用缓存选项的讨论。有趣的是,其中大多数都是外部工具(如 Apollo 客户端或 WordPress Object Cache),这意味着向应用程序添加额外层,增加其复杂性,并可能使其变慢。
(这些原因可能在一定程度上促使了在 WPGraphQL 中原生实现 persisted queries 的决定。)
例如,Apollo 客户端在客户端运行。如果从低端手机访问网站,没有太多算力,那些额外的 JavaScript 代码会对应用程序的性能产生影响。
同样,使用 WordPress 的开发者可能精通 PHP,但不太擅长 JavaScript。现在,缓存他们的 API 意味着他们也需要关注 JavaScript 层。
Gato GraphQL 在这个话题上更加聪明。由于它提供了 persisted queries,这意味着 query 在各自的端点上执行,它允许通过 HTTP 缓存来缓存这些端点 URL。
HTTP 缓存头的 max-age 值会自动从 query 中所有字段的所有 max-age 值计算,并且这些信息是使用 WordPress 编辑器逐字段配置的。
因此,API 可以在多个层(客户端、CDN 和服务器)进行缓存,并且在插件内原生处理,无需添加另一层。
查看这段展示 API 端点如何被缓存的视频:
本回合获胜者:Gato GraphQL。
第9回合:与 Gutenberg 的集成
曾经,Gutenberg 将成为 WordPress 的未来。但现在不再如此:Gutenberg 现在是 WordPress 的现在(因此我们可以将其称为 WordPress 编辑器),而 Full Site Editing 已成为新的未来。
不用说,我们的 API 需要与 WordPress 编辑器良好集成。这不仅意味着获取和发布区块数据,还可能为 WordPress 编辑器本身提供功能支持。
例如,由于 GraphQL 订阅可以让服务器实时向客户端推送数据,它将适合为协同编辑和通知功能提供支持。
WPGraphQL 可以通过 WPGraphQL Gutenberg 扩展插件查询区块数据。该扩展插件为每个区块创建了一个新类型,因此我们有 CoreParagraphBlock、CoreQuoteBlock 等。
Gato GraphQL 很快将能够查询区块数据(正在开发中)。但是,它不会为每个区块创建新类型,而是有一个单一的 Block 类型来表示所有区块,然后我们可以根据其名称提取某个区块的特定元数据。
例如,查看如何翻译段落区块内的内容(使用连接到 Google Translate API 的 @strTranslate 指令):
query TranslateStringsInBlocks {
post(by: { id: 1657 }) {
title
paragraphBlocks: blockDataItems(
filterBy: { include: "core/paragraph" }
)
translatedParagraphBlocks: blockDataItems(
filterBy: { include: "core/paragraph" }
)
@underJSONObjectProperty(by: { path: "attributes.content" })
@underEachArrayItem
@strTranslate(from: "en", to: "fr")
}
}本回合结果:平局。
扩展范围
"我有一个梦想。"
Gutenberg 区块被设计为提供一个在 WordPress 中创建内容的单一界面,大大简化了 CMS 代码的开发以及用户所需的学习。
虽然是为创建内容而引入的,但区块正在稳步接管 CMS 的所有其他领域,包括小工具、菜单,以及即将到来的通过 Full Site Editing 的主题。未来,它们还将支持多语言功能和协同编辑(这些功能我们在想到区块时可能甚至没有想到),以及谁知道还有什么。
我们可以以同样的方式思考 GraphQL:作为与数据交互的单一界面。这意味着,不仅仅是获取和发布数据,而是任何涉及数据的交互,包括编辑。
WordPress 有独特的机会真正成为网络的操作系统:一个由 Gutenberg 驱动的系统,让用户输入任何类型的内容(文本、图片、视频、音频等),通过其自身的工具或某些基于云的服务处理它,并将其发布到最终目的地,无论是 WordPress 网站还是其他地方。
但在这个强大梦想背后,必须有一个真正强大的 API,来满足我们对它提出的任何需求。一个可以基于 GraphQL 的 API,但被设计为也能超越其局限性。
第10回合:对自定义指令的支持

WPGraphQL 没有内置任何一个指令。我不是说它不支持(它的引擎 webonyx/graphql-php 是支持的),而是说它没有提供任何自定义指令的实现。
"那又怎样?"你可能会想。"我们需要指令做什么?如果有人需要修改 query 的结果,他们可以在自己的客户端上做!"

这是一个见仁见智的问题,没有对错之分。但让我告诉你:指令是一个非常有用的功能,有助于使 GraphQL 区别于 REST。如果你没有使用它们,你很可能没有充分利用你的 API。
指令不受规范约束,因此 GraphQL 服务器可以以任何方式实现它们,使其尽可能强大。这就是为什么 GraphQL 中的许多新功能首先通过指令引入,例如 @stream 和 @defer。
Gato GraphQL 对指令充满敬意。它们仅被执行一次,对所有实体的数据以及它们应用的所有字段执行(这解释了为什么 @strTranslate 指令能如此快速地从 Google Translate API 获取结果),而且 GraphQL 引擎本身基于指令管道。
啊,但是你害怕让用户使用所有这些功能,对吗?这是一个合理的担忧。但你可以移除对单一端点的访问,只通过 persisted queries 提供对数据的访问,在那里你(网站管理员)是唯一拥有指令访问权限的人。
所以,要么你受益,要么什么都不会发生。
如果你喜欢指令,那太好了,你会爱上 Gato GraphQL!❤️
但另一方面,如果你不喜欢,什么都不会发生。
本回合获胜者:Gato GraphQL。
(如果你认为"我们不需要那些臭指令",请不要生我的气……我只是在做我的工作。)
第11回合:对 REST 的支持
"啊?REST?什么 REST?我们不是在讨论 GraphQL 吗?你为什么要谈 REST?你为什么要让我的生活变得复杂?"

是的,乍一看这个话题似乎格格不入。但我把它加入这个比较的原因非常简单:Matt Mullenweg 表示,他正在考虑将 GraphQL 纳入 WordPress 核心,贡献者会担心的一件事是必须维护两个代码库。
这引出了一个显而易见的问题:GraphQL 服务器也能处理 REST 吗?
WPGraphQL 的答案是"部分可以",Gato GraphQL 的答案是"完全可以"。
关于 WPGraphQL。可以定义一个 REST 端点,当被解析时,它简单地执行包含所需字段的 GraphQL query,可以作为对 GraphQL 引擎的内部调用,或者作为对同一 Web 服务器执行的外部 POST 操作。
但这不足以满足 WP REST API,因为它还有一个 JSON schema,我们不能没有它。
关于 Gato GraphQL。我必须承认我很幸运,因为其底层引擎(称为 PoP 的服务端组件模型)的工作始于大约2013年,即在我知道有一种叫做 GraphQL 的东西之前的几年,这个项目随着自己的一些想法而发展(我在我的这篇复古文章中记录了这些想法)。
然后,当我大约1.5年前开始编写 CMS 无关的 GraphQL 服务器(Gato GraphQL 建立在其上)时,我将为 PoP 开发的想法与 GraphQL 建立的基础合并,创建了一个完全支持 GraphQL 规范同时能够向其添加不同功能集的系统。
在这方面,PoP 使用的 schema 与 API 无关,是 GraphQL schema 的超集。PoP schema 在 /api/graphql/?query=fullSchema 下。
然后,GraphQL 服务器层按照 GraphQL 规范格式化 PoP schema,生成 GraphQL schema。同样,我们可以生成 WP REST API 所需的 JSON schema。
生成这个 JSON schema 尚未完成,但是可行的。
现在,已经完成的是以多种格式生成 query 的响应。例如,这个 GraphQL query:
{
posts {
id
title
date
author {
name
}
}
}也可以通过这个 REST 端点解析:/posts/api/rest/?query=id|title|date|author.name。
我们不需要止步于此。你需要以另一种格式(如 XML)生成结果吗?没问题:/api/?query=posts.id|title|date|author.name&datastructure=xml。
(这可以帮助实现基于 schema 的 WordPress 新导入/导出工具的提案。这也使我之前说的话更加明显:单一接口可以驱动 CMS 内的所有数据交互,以及 CMS 与外部 API 的交互。)
本回合获胜者:Gato GraphQL。
第12回合:对新特性的支持
GraphQL 规范是最终版本吗?答案是否定的:规范在不断演进。此刻,有100个开放的 issue,其中许多包含将来某个时候会被正式化的提案。
现在,在这100个 issue 中,肯定有一些我们今天就能受益的新功能,对吧?如果是这样,为什么要等待呢?
这正是我的想法。

"但如果某些东西不在 GraphQL 规范中,那么我们不应该将它添加到 GraphQL 服务器中,否则用户会感到困惑!"
说得好。但是,如果我们只将新功能作为可选项提供,那么用户必然会意识到它,不会发生任何问题或误解。
再次强调,这是我的想法。不过,这是一个见仁见智的问题,所以如果你宁愿只使用每个 GraphQL 服务器都在使用的功能,那也没问题。
我认为 WPGraphQL 就是这样运作的。至少,我没有看到任何一个超出规范批准范围的功能。
对于 Gato GraphQL,我定期扫描规范中的 issue 列表,如果我发现一些很酷的功能,我的服务器可以毫不费力地满足它,那么我就会实现它。(事实上,这是我的爱好之一。)
这些是我迄今为止实现的"前瞻性"功能:
✅ 多 Query 执行
✅ Schema 命名空间
✅ 嵌套 mutations
✅ 可组合指令
✅ 主动反馈
✅ 基于字段和指令的版本控制
我已经计划添加:
✳️ Subscriptions(这已经是规范的一部分)
✳️ @stream 和 @defer 指令
✳️ 扁平链式语法
本回合获胜者:Gato GraphQL。
裁决!
女士们,先生们。

多么令人难忘的夜晚!我们经历了多么精彩的比赛!两位重量级选手为了自己的梦想全力以赴。
他们都在追逐的梦想,但只有其中一人能够实现。
现在,我们将知道那个人是谁。现在,是真相揭晓的时刻!
谁将成为"WordPress GraphQL"世界冠军?
是广受赞誉、深受大众喜爱、被各大媒体报道的现任冠军 WPGraphQL?
还是那位无所畏惧、不请自来、不按牌理出牌的挑战者 Gato GraphQL?

我们等待着评委的裁决。多么紧张!哦,圣母玛利亚,让我的心脏承受住这一刻!
🥁 胜者 🥁 是 🥁 !!!!!!!!!!!! 🥁 ...
平局!
两位斗士,两位重量级选手,平局!

多么美好的时刻!两位选手互相拥抱,表明在 WordPress 社区这个大家庭中,我们都是朋友。
那么,平局的理由是什么?评委解释道:
👑 WPGraphQL 更受欢迎,其使用更为广泛。
👑 Gato GraphQL 拥有更好的架构,从长远来看可能更好地服务于 WordPress。
女士们先生们,你们已经听到了评委的裁决!
我们的奖杯有两只手套:每位选手各一只。

但是,你的裁决是什么?
你会继续无条件地使用 WPGraphQL 满足你的 headless 需求吗?
还是你会给 Gato GraphQL 它所争取的机会,下载插件,试用一下?
女士们先生们,今晚就到此为止了。
我们衷心希望你们享受了这场比赛。
让我们希望两位冠军之间很快会有新的相遇。
晚安。
2024年05月01日更新: 在 Gato GraphQL vs WPGraphQL 对比文章中了解更多。