🥊 Gato GraphQL vs WPGraphQL: trận đấu!
Cập nhật 01/05/2024: Xem so sánh Gato GraphQL vs WPGraphQL.
Quý vị và các bạn.

Chào mừng đến với MGM Grand Garden Arena cho trận đấu của thế kỷ! Tối nay, chúng ta đang tạo ra lịch sử. Hai chiến binh trẻ sẽ đối mặt nhau trên sàn đấu, tranh giành phần thưởng mà họ đã nỗ lực không ngừng:
Trở thành nhà vô địch thế giới "GraphQL trong WordPress" 🏆
Ở bên phải chúng ta, có nhà vô địch đương nhiệm. Dù chỉ mới 4 tuổi, anh ta đã đầy kinh nghiệm, vừa đạt phiên bản 1.0 và được đăng lên thư mục wp.org, rất được yêu thích trong cộng đồng.
🥁 Xin 🥁 nhiệt 🥁 liệt 🥁 chào 🥁 đón 🥁 ...... WPGraphQL!

Ở bên trái chúng ta, có người thách đấu. Anh ta chỉ vừa xuất hiện trên thế giới được 1 tháng, nhưng tràn đầy năng lượng và tham vọng, thể hiện sức mạnh ngay từ ngày đầu tiên. Chính anh ta là người tìm kiếm cuộc gặp gỡ hôm nay. Tối nay là cơ hội của anh ta, và cả thế giới đang chú ý.
🥁 Xin 🥁 nhiệt 🥁 liệt 🥁 chào 🥁 đón 🥁 ...... Gato GraphQL!

Tối nay, hai đối thủ của chúng ta sẽ gặp mặt trực tiếp lần đầu tiên, trong một trận đấu 12 hiệp. Khi họ tiến vào trung tâm sàn đấu, chờ đợi tiếng chuông khai mạc, họ quan sát nhau, cố tìm điểm yếu của nhau. Tuy nhiên, họ chỉ thể hiện sự tự tin.

Ai sẽ thắng? Liệu WPGraphQL có duy trì lợi thế nhờ sự ủng hộ của những người hâm mộ? Hay người mới đến Gato GraphQL sẽ thuyết phục được cộng đồng về sức mạnh của những cú đấm, để lại dấu ấn kinh ngạc và kéo đám đông về phía mình?
Tối nay, quý vị và các bạn, chúng ta sẽ tìm ra câu trả lời.
Hãy đặt cược. Và tận hưởng trận đấu!
🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣
Gần đây tôi được hỏi để giải thích sự khác biệt giữa plugin của mình, Gato GraphQL, và WPGraphQL.
Cả hai plugin đều là máy chủ GraphQL cho WordPress, vì vậy chúng phục vụ cùng một mục đích. Tuy nhiên, bên dưới lớp vỏ ngoài, chúng có những đặc điểm khác nhau, có thể khiến cái này tốt hơn cái kia để đáp ứng một số yêu cầu nhất định.
Mặc dù tôi có thiên kiến về plugin của mình, tôi đã cố gắng đưa ra một sự so sánh công bằng, dựa trên những chủ đề tôi cho là quan trọng đối với cả GraphQL lẫn WordPress. (Nếu độc giả muốn so sánh về một chủ đề khác, tôi sẽ vui lòng thực hiện.)
Sự so sánh không toàn diện. Chẳng hạn, tôi cũng muốn thực hiện một số benchmarking, đo tốc độ xử lý cùng một GraphQL query với cả hai máy chủ. (Nếu độc giả thấy đề xuất này hấp dẫn, tôi có thể thực hiện cho một bài viết sắp tới.)
Tôi đã chia so sánh của mình thành 4 lĩnh vực chính: Độ phổ biến, Phong cách code và chuẩn mực, Các vấn đề cấp thiết, và Mở rộng phạm vi, mỗi lĩnh vực có 3 hạng mục, tổng cộng 12 "hiệp". Cuối cùng, các giám khảo đưa ra phán quyết để xướng tên nhà vô địch.
Nhấp vào bên dưới để chuyển thẳng đến một chủ đề:
🔔 Ding 🔔 ding 🔔 diiiiiing...
Tiếng chuông khai mạc đã vang lên...
Trận đấu bắt đầu!
Độ phổ biến
Bất kỳ phần mềm nào (hay công nghệ, cho dù là gì) cũng cần được mọi người sử dụng, nếu không việc nó tốt hơn các lựa chọn thay thế sẽ chỉ là một giai thoại.
Chẳng hạn, dù có những lựa chọn thay thế cho phép gõ nhanh hơn, chúng ta vẫn chủ yếu sử dụng bàn phím QWERTY.
Hai plugin này phổ biến đến mức nào?
Hiệp 1: Ai đang sử dụng, và nó hoàn thiện đến mức nào
WPGraphQL cho đến nay là từ đồng nghĩa với GraphQL trong WordPress. Trong hơn 4 năm phát triển (bắt đầu từ tháng 11 năm 2016), nó đã thu hút được hơn 2.8k sao trên repo, một cộng đồng hơn 4600 người theo dõi, và gần 100 người đóng góp cho dự án.
Nó đạt phiên bản 1.0 và được tải lên thư mục plugin trên wp.org vào tháng 11 năm 2020. Kể từ đó, đã có hơn 8000 lượt cài đặt hoạt động. Hiện tại đây là giải pháp duy nhất để lấy nội dung WordPress vào Gatsby và, gần đây hơn, nhiều dự án đã thêm nó vào stack của mình, bao gồm framework Headless của WPEngine và Next.js WordPress starter của WebDevStudios.
Nói cách khác, WPGraphQL rất phổ biến.
Việc phát triển Gato GraphQL bắt đầu nghiêm túc khoảng 1,5 năm trước (như một phần của dự án rộng lớn hơn), và đạt trạng thái "đủ tốt" 6 tháng trước, nhận được 150 sao trên repo kể từ đó. Plugin hiện đang ở phiên bản 0.7, và vẫn còn vài tháng nữa mới đạt 1.0 (ví dụ, chưa có danh mục trong schema).
Tháng trước tôi đã ra mắt trang web hiện tại gatographql.com này, và kể từ đó tôi đã quảng bá plugin thông qua blog (như bài viết bạn đang đọc này), và cũng xuất bản một bài giới thiệu trên CSS-Tricks. Những nỗ lực này đã đưa vài trăm người đến trang web, và hơn 100 khách truy cập đã tải plugin.
Nói cách khác, Gato GraphQL đang dần nhưng chắc chắn trở nên phổ biến hơn, và vẫn đang trong quá trình hoàn thiện.
Người chiến thắng hiệp này: WPGraphQL.

Hiệp 2: Khả năng mở rộng
Các extension cho phép tương tác với các plugin khác thông qua Gato GraphQL.
WPGraphQL có các extension cho ACF, WooCommerce, Yoast và một số extension khác.
Gato GraphQL chưa có extension nào, và tôi không kỳ vọng sẽ có nhiều trước khi phát hành phiên bản 1.0.
Tuy nhiên, Gato GraphQL đặt trọng tâm lớn vào extension trong kiến trúc của mình, cho phép người dùng quản lý chúng (bật, tắt, cấu hình, và đọc tài liệu) từ một nơi tập trung, trang "Modules":

Nói cách khác, trong khi WPGraphQL đã có extension, Gato GraphQL đang chuẩn bị nền tảng cho chúng.
Người chiến thắng hiệp này: WPGraphQL.

Hiệp 3: Đối tượng mục tiêu
WPGraphQL nhắm đến các nhà phát triển: nếu bạn muốn trích xuất dữ liệu từ trang WordPress của mình, bạn cần lưu trữ GraphQL query ở đâu đó trong code của mình (thường là trong một hàm JavaScript). Sau đó, để sử dụng được, bạn cần đủ kỹ năng lập trình.
Gato GraphQL, thay vào đó, tuân theo triết lý WordPress rằng bất kỳ ai cũng có thể sử dụng nó, bao gồm cả những người không có kỹ thuật. Để đạt được mục tiêu này, nó cho phép tạo và quản lý GraphQL query thông qua WordPress editor, để việc cung cấp dữ liệu của trang WordPress qua API trở nên dễ dàng như tạo một bài đăng blog.
Ngoài ra, Gato GraphQL nhấn mạnh hơn vào việc cung cấp các client để tương tác với dịch vụ GraphQL theo cách trực quan. Trong khi cả hai plugin đều cung cấp GraphiQL client để thực thi query, chỉ Gato GraphQL còn cung cấp thêm Voyager client để khám phá schema một cách tương tác:

Người chiến thắng hiệp này: Gato GraphQL.

Phong cách code và chuẩn mực
Hãy nói về code!
Nếu bạn đang sử dụng GraphQL, có khả năng bạn đang làm WordPress headless và render trang web bằng một JavaScript framework nào đó, đây là một mô hình hiện đại. Hơn nữa, WordPress có thể là một CMS cũ, nhưng GraphQL là một giao diện hiện đại để truy cập dữ liệu từ trang web. Do đó, tôi có thể tự tin giả định rằng bạn là một nhà phát triển sáng suốt, muốn tạo ra code thanh lịch, và sẽ không chấp nhận sử dụng một giải pháp chưa tối ưu.
Code của hai plugin này (từ codebase của họ và được kỳ vọng từ các triển khai tùy chỉnh của chúng ta) thanh lịch đến mức nào?
Hiệp 4: Yêu cầu PHP
Cả WPGraphQL và Gato GraphQL đều yêu cầu PHP 7.1+.
Tuy nhiên, có một điểm khác biệt: Gato GraphQL thực tế được viết bằng PHP 7.4, và sau đó được transpile sang PHP 7.1 cho production.
Do đó, việc lập trình Gato GraphQL thú vị hơn nhiều: bạn có thể sử dụng các tính năng PHP mới hơn, bao gồm kiểu object, typed properties và arrow functions. Và khi hỗ trợ PHP 8.0 được thêm vào (điều này sẽ xảy ra khi phiên bản mới của Lando được phát hành), bạn cũng có thể sử dụng union types, match expression, và nhiều tính năng khác.
Người chiến thắng hiệp này: Gato GraphQL.

Hiệp 5: Thực hành lập trình
Hãy bắt đầu với WPGraphQL. Khi vào repo wp-graphql/wp-graphql, có một điều nổi bật đối với tôi:

Phóng to:

Xin lỗi, nhưng chỉ có một cách tôi có thể phản ứng về điều này:

Commit thư mục vendor của Composer vào repo là một thực hành xấu, và Composer khuyến cáo rõ ràng không nên làm vậy.
Việc khắc phục vấn đề này không khó (tôi thậm chí đã mô tả một cách dựa trên GitHub actions), vì vậy tôi tự hỏi tại sao nó lại ở đó.
Tôi có thể nói rằng, trong hiệp này, WPGraphQL đang tự đấm vào mặt mình!

Hãy tiếp tục. Phát triển cho WPGraphQL đòi hỏi phải biết một bộ sưu tập hooks cực kỳ rộng lớn (actions và filters). Khi vào Developer reference của WPGraphQL, chúng ta có thể thấy rõ sự rộng lớn này.
Để chụp màn hình danh sách actions, tôi phải thu nhỏ trình duyệt xuống còn 50%:

Với danh sách filters, tôi thu nhỏ xuống 30% (mức thấp nhất Firefox hỗ trợ), và ngay cả khi đó tôi vẫn không thể lấy được toàn bộ danh sách:

Hãy chuyển sang repo GatoGraphQL/GatoGraphQL, là monorepo chứa Gato GraphQL (trong số các dự án khác).
Đây là một số đặc điểm của code:
✅ Tuân thủ các chuẩn PSR-1, PSR-4 và PSR-12.
✅ Toàn bộ code được chia thành nhiều package nhỏ, nguyên tử, và tất cả chúng (hơn 100 cho plugin, hơn 200 cho toàn bộ dự án) được lưu trữ trong cùng một monorepo.
✅ Sử dụng Composer để quản lý tất cả các phụ thuộc.
✅ Sử dụng Symfony Dependency Injection để quản lý tất cả các service trong ứng dụng. Để đăng ký một type resolver, field resolver hoặc directive resolver mới, chúng ta chỉ cần đăng ký một service mới trong container.
✅ Mỗi class là một service, và Symfony Dependency Injection đảm nhận việc autowire toàn bộ ứng dụng.
✅ Máy chủ GraphQL bên dưới là CMS-agnostic. Gato GraphQL triển khai các hợp đồng cho WordPress, và thêm một ít logic tùy chỉnh (ví dụ: để cung cấp các client).
Code dành riêng cho WordPress chỉ chiếm khoảng 10% tổng lượng code. Sao chép 10% này cho một framework hoặc CMS khác (Laravel/Drupal/v.v.) có thể cung cấp một triển khai máy chủ GraphQL cho chúng.
✅ Do hệ quả của việc là CMS-agnostic, việc viết một resolver đồng nghĩa với việc viết logic kinh doanh tổng quát của nó, được cung cấp bởi các service có thể tái sử dụng. Chúng ta không bao giờ nghĩ theo hướng code WordPress, và hiếm khi phải đối phó với nợ kỹ thuật của nó.
✅ Tương tự, GraphQL schema không phải là bản sao 1:1 của mô hình dữ liệu WordPress, bỏ qua nợ kỹ thuật tích lũy của WordPress ở lớp dữ liệu, và cung cấp một giao diện sạch.
✅ Vấn đề N+1 của GraphQL không thể xảy ra, theo thiết kế kiến trúc, và không gây phiền phức cho nhà phát triển.
✅ Máy chủ không chỉ là một máy chủ GraphQL: trên thực tế đó là một máy chủ API, nơi phản hồi có thể được xuất ra ở các định dạng hoặc đặc tả khác (ví dụ: REST) từ một nguồn sự thật duy nhất. (Thêm về điều này ở hiệp 11).
✅ Không có thư mục vendor nào được commit. Thay vào đó, source code được chuyển đổi thành distribution code (tức là plugin cuối cùng để cài đặt trên trang WordPress) thông qua GitHub actions, và được triển khai đến một repo dist, nơi nó có chứa thư mục vendor.
✅ Khi tạo code để phân phối, nó được scope bằng PHP-Scoper, và source code, chứa code PHP 7.4, được transpile sang PHP 7.1.
✅ Vì đã giải quyết vấn đề scoping, plugin có thể dựa vào bất kỳ phụ thuộc bên thứ ba nào. Hiện tại, nó sử dụng DependencyInjection của Symfony, Cache và Dotenv, Guzzle (để tương tác với các API bên ngoài), Pipeline của League, và nhiều thứ khác.
Điều này quan trọng không chỉ cho hiện tại mà còn cho tương lai: tôi có thể chắc chắn rằng mình có thể sử dụng bất kỳ phụ thuộc nào từ kho lưu trữ Packagist, vì vậy tôi không cần phải phát minh lại bánh xe.
✅ Các field được đăng ký vào các type, giúp GraphQL schema dễ dàng mở rộng.
Người chiến thắng hiệp này: Gato GraphQL (với khoảng cách lớn, tôi dám nói, nếu bạn không phiền).

Hiệp 6: Mở rộng schema
Hãy thêm một field vào GraphQL schema.
Chúng ta theo dõi hướng dẫn cho WPGraphQL. Code được đề xuất như bên dưới. Nó khai báo một action hook để thực thi một hàm khai báo một mảng. Cả mô tả của các field lẫn cách giải quyết chúng đều được cung cấp bên trong mảng:
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';
},
]);
});Ví dụ này đơn giản nhất có thể: resolver về cơ bản không làm gì cả. Tuy nhiên, tôi đã khó nhìn vào code và hiểu ngay nó làm gì. Không, tôi không mỉa mai: tất cả các màu sắc của đoạn code trong trình soạn thảo của tôi đang tranh giành sự chú ý. Ngoài ra, không có sự tách biệt các mối quan tâm, và code không có vẻ tái sử dụng được nhiều.
Do đó, sẽ tùy thuộc vào nhà phát triển (tức là bạn) để làm cho code dễ đọc, tái sử dụng được, không có lỗi, và nhiều điều khác nữa, trong khi phát triển ứng dụng; bản thân thư viện không có vẻ giúp ích nhiều trong lĩnh vực này.
Tôi gọi phong cách này là "ADD": Array-Driven Development. Tôi không thể nói mình là người hâm mộ phong cách này.
(Để công bằng với WPGraphQL, đây là một thực hành lập trình chuẩn, và cũng là thực hành được sử dụng bởi engine bên dưới webonyx/graphql-php.)
Trong Gato GraphQL, tất cả code là SOLID. Để đăng ký một field trong GraphQL schema, chúng ta tạo một class triển khai interface FieldResolverInterface (thực ra là mở rộng từ AbstractSchemaFieldResolver, vốn đã có nhiều phương thức được triển khai sẵn), và đăng ký nó trong container.
Ví dụ, đoạn code này cung cấp các field username, email và url cho type User:
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;
}
}Tôi tin rằng giải pháp của mình thanh lịch hơn giải pháp của WPGraphQL. Tuy nhiên, đó là vấn đề về sở thích. Tôi biết rằng nhiều nhà phát triển không ngại Array-Driven Development, và thực ra thích nó vì trong một khối code nhỏ gọn, họ có thể triển khai toàn bộ logic.
Người chiến thắng hiệp này: hòa.

Giải lao
Thật là một đêm tuyệt vời, quý vị và các bạn.

Chúng ta đã đến giữa trận đấu, vì vậy đây là thời điểm tốt để nghỉ giải lao, và bình luận về những gì chúng ta đã chứng kiến cho đến nay.
(Trong thời gian này, tôi nên hiển thị một quảng cáo từ nhà tài trợ của mình. Thật không may, tôi chưa có ai. Nếu bạn muốn công ty của mình tài trợ cho việc phát triển Gato GraphQL, và được quảng bá trên phương tiện truyền thông hàng đầu như sự kiện này, hãy nhắn tin cho tôi.)

Thật là một trận đấu! WPGraphQL ban đầu như lửa và giông tố! Anh ta bắt đầu trận đấu trong trạng thái tuyệt vời, tung những cú đấm cực kỳ mạnh vào Gato GraphQL, kẻ hầu như không thể đứng vững trên hai chân. Đòn này tiếp đòn kia. Tôi không muốn ở trong hoàn cảnh của Gato GraphQL.
Tôi phải thừa nhận, sau 2 hiệp đầu tiên, tôi nghĩ trận đấu sắp kết thúc. Tôi chờ đợi cú ngã bất cứ lúc nào. Chờ một chiếc khăn bay lên xin tha. Nhưng Gato GraphQL đã kháng cự. Phải công nhận điều đó. Sự kiên định không lay chuyển thật đáng khâm phục!
Và rồi, sự biến đổi xảy ra. Đâu đó từ hiệp thứ 3, Gato GraphQL dường như lấy thêm sức mạnh từ không đâu, và bắt đầu không chỉ phòng thủ mà còn phản công, nhiều cú đấm trong số đó đã chạm vào mặt WPGraphQL. Tôi thấy WPGraphQL run rẩy! Chúng ta chưa bao giờ thấy điều như vậy từ nhà vô địch thế giới hiện tại của chúng ta. Thật là một sự biến đổi đáng kinh ngạc chúng ta vừa chứng kiến!
Và rồi, sau khi đã làm lung lay sự tự tin của đối thủ, từ hiệp thứ 4 Gato GraphQL đã tự mình tung ra một loạt những cú đấm chí mạng. Thật kinh ngạc! May mắn thay, đối mặt với anh ta là nhà vô địch thế giới của chúng ta, WPGraphQL, và anh ta có thể chịu đựng những cú đấm, được nâng đỡ bởi những tiếng cổ vũ và sự thông cảm từ đám đông. Thật là người hùng! Bất kỳ ai khác cũng đã gục ngã ngay tại chỗ, nhưng không phải anh ta, anh ta đã chịu đựng những cú đấm như người vô địch mà anh ta là.
Nhưng nhà vô địch, anh ta còn giữ được danh hiệu bao lâu nữa? Chưa ai bị knock down, chưa ai ném khăn. Trận đấu có thể chuyển hướng quyết định bất cứ lúc nào. Hai võ sĩ biết mình muốn gì, và tôi chắc chắn họ sẽ trở lại với tất cả sức mạnh và quyết tâm, để tấn công đối thủ, để giành chiến thắng.
Thật là một trận đấu!
Và bây giờ, quý vị và các bạn, hai chiến binh đang trở lại sàn đấu.

Tiếp tục phần còn lại của trận đấu!
Các vấn đề cấp thiết
Máy chủ GraphQL cần chú ý đến nhiều cân nhắc, chỉ để đáp ứng đề xuất "lấy dữ liệu bạn cần, không hơn không kém".
Ví dụ:
- Nó bảo mật đến mức nào? Làm thế nào để đảm bảo chúng ta không để lộ dữ liệu riêng tư trên một endpoint công khai?
- Hiệu suất của nó như thế nào? Làm thế nào để giảm tải trên máy chủ khi gửi đi gửi lại cùng một query, trong khi làm cho nó nhanh nhất có thể?
- Nó đơn giản đến mức nào? Nó được tích hợp tốt với WordPress như thế nào để tận dụng các tính năng do CMS cung cấp?
Và nhiều câu hỏi khác. Đây chỉ là một mẫu nhỏ tôi đã chọn, và tôi sẽ giải quyết trong 3 hiệp tiếp theo.
Hiệp 7: Persisted queries
Persisted queries kết hợp những gì tốt nhất của cả GraphQL lẫn REST: chúng được tạo bằng GraphQL, vì vậy không có việc lấy thiếu hoặc thừa dữ liệu, nhưng chúng được công bố trên máy chủ như một endpoint, với URL riêng.
Persisted queries mang lại những lợi ích sau:
✅ An toàn: thay vì cấp quyền truy cập vào bất kỳ dữ liệu nào thông qua endpoint duy nhất, chúng ta có thể xác định trước dữ liệu nào được phép truy cập.
✅ Nhanh: được truy cập thông qua URL riêng, nó có thể được cache ở mọi lớp giữa client và back-end (trên máy chủ, CDN, trình duyệt) sử dụng HTTP caching chuẩn.
WPGraphQL cung cấp hỗ trợ cho persisted queries thông qua hai extension này:
Ngoài ra, Jason Bahl (người tạo ra WPGraphQL) gần đây đã thông báo rằng trong tương lai gần anh ta sẽ thêm hỗ trợ cho persisted queries trong WPGraphQL.
Tôi tự hỏi anh ta đang nghĩ gì, vì đã có 2 extension rồi. Nó sẽ khác các extension đó như thế nào? Có lẽ anh ta muốn đưa nó vào core của plugin, để tăng cường các biện pháp bảo mật tổng thể của plugin mà không phụ thuộc vào bên thứ ba?
Hay có lẽ anh ta đã thấy cách triển khai của Gato GraphQL, và muốn cung cấp một trải nghiệm tương tự, vận hành nó thông qua visual editor thay vì code thuần túy?
Điều đó dẫn chúng ta đến Gato GraphQL. Nó không chỉ cung cấp persisted queries, mà còn cố gắng biến nó thành phần trung tâm của sản phẩm:
✅ Plugin cho phép vô hiệu hóa endpoint đơn, và người dùng được khuyến khích chỉ phơi bày dữ liệu thông qua persisted queries.
(Ngược lại, WPGraphQL chỉ vô hiệu hóa introspection theo mặc định, không phải endpoint thực tế. Nói cách khác, kẻ tấn công vẫn có thể truy cập dữ liệu riêng tư; họ chỉ bị làm khó hơn vì không biết trước dữ liệu riêng tư nào tồn tại.)
✅ Nó được tích hợp sâu với WordPress editor, sao cho việc tạo một persisted query cũng mất công sức như tạo một bài đăng blog, và bất kỳ ai cũng có thể làm điều đó, không chỉ lập trình viên.
✅ Persisted queries không tĩnh: chúng có thể sử dụng các biến GraphQL, giá trị của chúng có thể được cung cấp thông qua các URL params khi thực thi endpoint.
Xem trải nghiệm tạo và thực thi một persisted query trong plugin của tôi:
Người chiến thắng hiệp này: Gato GraphQL.
Hiệp 8: Caching
GraphQL có một điểm đau lớn: nó không dễ dàng được cache. Lý do là nó phụ thuộc vào việc gửi các thao tác POST đến một endpoint duy nhất. Vì endpoint duy nhất sẽ cho ra kết quả khác nhau, và vì query được gửi trong body của request thay vì các URL parameter, chúng ta không thể cache endpoint duy nhất.
Giải pháp chuẩn được nhiều máy chủ GraphQL cung cấp là chuyển việc caching về phía client, và dựa vào ID của các đối tượng như định danh của thực thể cần được cache thay vì URL của endpoint. Thư viện phổ biến nhất cung cấp chức năng này là Apollo client.
Có một cuộc thảo luận trên repo WPGraphQL về tất cả các tùy chọn có sẵn cho caching với WPGraphQL. Thú vị là, hầu hết chúng đều là các công cụ bên ngoài (như Apollo client, hoặc WordPress Object Cache), có nghĩa là thêm một lớp nữa vào ứng dụng, tăng độ phức tạp của nó, và cũng có thể làm nó chậm hơn.
(Những lý do này chắc hẳn là một phần đằng sau quyết định triển khai persisted queries một cách nội bộ trong WPGraphQL.)
Chẳng hạn, Apollo client chạy, thực ra là, trên client. Nếu truy cập trang web từ một điện thoại di động cấp thấp, không nhiều sức mạnh, đoạn code JavaScript thêm đó sẽ ảnh hưởng đến hiệu suất của ứng dụng.
Tương tự, các nhà phát triển làm việc với WordPress có thể thành thạo PHP, nhưng không nhiều về JavaScript. Bây giờ, việc cache API của họ sẽ có nghĩa là họ cần phải lo lắng về lớp JavaScript cũng vậy.
Gato GraphQL đã thông minh hơn về chủ đề này. Vì nó cung cấp persisted queries, có nghĩa là các queries được thực thi trên endpoint riêng của chúng, nó cho phép cache các URL endpoint này thông qua HTTP caching.
Header HTTP caching có giá trị max-age được tính toán tự động từ tất cả các giá trị max-age cho tất cả các field trong query, và thông tin này được cấu hình bằng WordPress editor, trên cơ sở từng field.
Kết quả là, API có thể được cache trên nhiều lớp (ở client, CDN và máy chủ), và được xử lý nội bộ trong plugin, không cần thêm lớp khác.
Xem video này hiển thị cách các endpoint API đang được cache:
Người chiến thắng hiệp này: Gato GraphQL.
Hiệp 9: Tích hợp với Gutenberg
Trước đây Gutenberg được coi là tương lai của WordPress. Không còn như vậy nữa: Gutenberg bây giờ là hiện tại của WordPress (vì vậy chúng ta có thể gọi nó là WordPress editor), và Full Site Editing đã trở thành tương lai mới.
Không cần phải nói, các API của chúng ta cần có sự tích hợp tốt với WordPress editor. Điều này có nghĩa là không chỉ lấy và đăng dữ liệu cho các block, mà còn tiềm năng để cung cấp sức mạnh cho các tính năng trong chính WordPress editor.
Ví dụ, vì GraphQL subscriptions có thể để máy chủ đẩy dữ liệu đến client theo thời gian thực, nó sẽ phù hợp để cung cấp sức mạnh cho các tính năng chỉnh sửa cộng tác và thông báo.
WPGraphQL có thể truy vấn dữ liệu block thông qua extension WPGraphQL Gutenberg. Extension này tạo một type mới để map mỗi block, vì vậy chúng ta có CoreParagraphBlock, CoreQuoteBlock, v.v.
Gato GraphQL sẽ sớm có thể truy vấn dữ liệu block (đang trong quá trình phát triển). Tuy nhiên, thay vì tạo một type mới cho mỗi block, nó sẽ có một type Block duy nhất để đại diện cho tất cả các block, và sau đó chúng ta có thể trích xuất metadata cụ thể cho một block dựa trên tên của nó.
Ví dụ, xem cách bạn có thể dịch nội dung bên trong một paragraph block (sử dụng directive @strTranslate, kết nối với Google Translate API):
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")
}
}Người chiến thắng hiệp này: hòa.
Mở rộng phạm vi
"Tôi có một ước mơ."
Các Gutenberg block được thiết kế để cung cấp một giao diện duy nhất để tạo nội dung trong WordPress, đơn giản hóa đáng kể việc phát triển code cho CMS, và quá trình học tập cần thiết từ người dùng.
Trong khi được giới thiệu để tạo nội dung, các block đang dần chiếm lĩnh tất cả các khu vực khác của CMS, bao gồm widget, menu và, sắp tới, các theme thông qua Full Site Editing. Và trong tương lai, chúng cũng sẽ hỗ trợ khả năng đa ngôn ngữ và chỉnh sửa cộng tác (các tính năng mà chúng ta thậm chí có thể không nghĩ đến khi nghĩ về block), và ai biết gì khác nữa.
Chúng ta có thể nghĩ về GraphQL theo cùng những thuật ngữ đó: như một giao diện duy nhất để tương tác với dữ liệu. Điều đó có nghĩa là, không chỉ lấy và đăng dữ liệu, mà bất kỳ tương tác nào liên quan đến dữ liệu, bao gồm cả chỉnh sửa.
WordPress có cơ hội độc đáo để thực sự trở thành hệ điều hành của web: một hệ thống được cung cấp bởi Gutenberg, cho phép người dùng nhập bất kỳ loại nội dung nào (văn bản, hình ảnh, video, âm thanh, v.v.), xử lý nó thông qua công cụ của mình hoặc một số dịch vụ đám mây, và xuất bản nó đến đích cuối cùng, dù là trang WordPress hay ở nơi khác.
Nhưng đằng sau ước mơ mạnh mẽ này, phải có một API thực sự mạnh mẽ, để đáp ứng bất kỳ yêu cầu nào chúng ta đặt ra. Một API có thể dựa trên GraphQL, nhưng được thiết kế để vượt qua các giới hạn của nó.
Hiệp 10: Hỗ trợ directive tùy chỉnh

WPGraphQL không đi kèm với một directive nào. Tôi không nói rằng nó không hỗ trợ chúng (engine webonyx/graphql-php của nó có), nhưng rằng nó không cung cấp bất kỳ triển khai directive tùy chỉnh nào.
"Thế thì sao?" bạn có thể nghĩ. "Chúng ta cần directive để làm gì? Nếu ai đó cần sửa đổi kết quả của query, họ có thể làm điều đó trên client của mình!"

Đây là vấn đề quan điểm, và không có đúng hay sai. Nhưng hãy để tôi nói với bạn một điều: directive là một tính năng cực kỳ hữu ích, một trong những tính năng giúp phân biệt GraphQL với REST. Nếu bạn không sử dụng chúng, rất có thể bạn chưa khai thác tối đa API của mình.
Directive không được quy định bởi spec, vì vậy các máy chủ GraphQL có thể triển khai chúng theo bất kỳ cách nào họ muốn, làm cho chúng mạnh mẽ theo cách họ cần. Đó là lý do tại sao nhiều chức năng mới trong GraphQL được giới thiệu đầu tiên thông qua directive, chẳng hạn như @stream và @defer.
Gato GraphQL đối xử với directive một cách trân trọng. Chúng được thực thi chỉ một lần với dữ liệu từ tất cả các thực thể, cho tất cả các field mà chúng được áp dụng (điều này giải thích tại sao directive @strTranslate có thể lấy kết quả từ Google Translate API nhanh như vậy), và bản thân engine GraphQL dựa trên một directive pipeline.
Ahhhh, nhưng bạn sợ khi cung cấp tất cả quyền năng này cho người dùng, phải không? Đó là một lo ngại hợp lý. Nhưng khi đó, bạn chỉ cần xóa quyền truy cập vào endpoint đơn, và cung cấp quyền truy cập dữ liệu chỉ thông qua persisted queries, nơi bạn (quản trị viên trang web) là người duy nhất có quyền truy cập vào các directive.
Vì vậy, hoặc bạn được hưởng lợi, hoặc không có gì xảy ra.
Nếu bạn yêu thích directive, tuyệt vời, bạn sẽ yêu thích Gato GraphQL! ❤️
Nhưng mặt khác, nếu bạn không thích nó, không có gì xảy ra.
Người chiến thắng hiệp này: Gato GraphQL.
(Nếu bạn tin rằng "chúng ta không cần những directive hôi hám đó", xin đừng giận tôi... Tôi chỉ đang làm công việc của mình.)
Hiệp 11: Hỗ trợ REST
"Ahhhhh? REST? REST nào vậy? Chúng ta không đang nói về GraphQL sao? Tại sao bạn lại nói về REST? Tại sao bạn muốn làm phức tạp cuộc sống của tôi?"

Vâng, thoạt nhìn chủ đề này có vẻ không liên quan. Nhưng tôi đã thêm nó vào so sánh này vì một lý do rất đơn giản: Matt Mullenweg đã nói rằng anh ta đang xem xét GraphQL để có thể đưa vào WordPress core, và điều mà những người đóng góp sẽ lo lắng là phải duy trì hai codebase.
Điều đó dẫn đến câu hỏi hiển nhiên: liệu máy chủ GraphQL có thể xử lý cả REST không?
Câu trả lời là "một phần có" đối với WPGraphQL, và "hoàn toàn có" đối với Gato GraphQL.
Về WPGraphQL. Có thể xác định một endpoint REST mà khi được giải quyết, chỉ đơn giản là thực thi một GraphQL query chứa các field cần thiết, dưới dạng một cuộc gọi nội bộ đến engine GraphQL, hoặc dưới dạng một thao tác POST bên ngoài thực thi đối với cùng một web server.
Nhưng điều đó không đủ để thỏa mãn WP REST API, vì nó cũng có một JSON schema, và chúng ta không thể thiếu nó.
Về Gato GraphQL. Tôi phải thừa nhận mình đã may mắn, vì công việc trên engine bên dưới của nó (mô hình component phía máy chủ gọi là PoP) bắt đầu khoảng năm 2013, tức là vài năm trước khi tôi biết đến thứ gọi là GraphQL, và dự án này phát triển với một số ý tưởng của riêng nó (mà tôi đã ghi lại trong bài viết cổ điển này của mình).
Sau đó, khi tôi bắt đầu viết code cho máy chủ GraphQL CMS-agnostic (mà Gato GraphQL dựa trên) khoảng 1,5 năm trước, tôi đã kết hợp các ý tưởng phát triển cho PoP với nền tảng được thiết lập bởi GraphQL, tạo ra một hệ thống hỗ trợ toàn bộ GraphQL spec, trong khi có khả năng thêm vào một tập hợp tính năng khác.
Trong lĩnh vực này, schema mà PoP sử dụng là API-agnostic, và là một superset của schema GraphQL. Schema PoP nằm ở /api/graphql/?query=fullSchema.
Sau đó, lớp máy chủ GraphQL định dạng schema PoP theo GraphQL specification, tạo ra GraphQL schema. Và tương tự, chúng ta có thể tạo ra JSON schema mà WP REST API yêu cầu.
Việc tạo ra JSON schema này chưa được thực hiện, nhưng hoàn toàn khả thi.
Điều đã được thực hiện rồi là tạo ra phản hồi của query ở nhiều định dạng. Ví dụ, GraphQL query này:
{
posts {
id
title
date
author {
name
}
}
}Nó cũng được giải quyết thông qua REST endpoint này: /posts/api/rest/?query=id|title|date|author.name.
Và chúng ta không cần phải dừng lại ở đó. Bạn cần tạo ra kết quả bằng một định dạng khác, chẳng hạn như XML? Không vấn đề gì: /api/?query=posts.id|title|date|author.name&datastructure=xml.
(Điều này có thể giúp triển khai đề xuất về một công cụ import/export mới cho WordPress, dựa trên schema. Điều này cũng làm rõ hơn một chút điều tôi đã nói trước đó: một giao diện duy nhất có thể cung cấp sức mạnh cho tất cả các tương tác dữ liệu, cả trong CMS lẫn từ CMS với các API bên ngoài.)
Người chiến thắng hiệp này: Gato GraphQL.
Hiệp 12: Hỗ trợ các tính năng mới
Liệu GraphQL spec đã hoàn thiện chưa? Câu trả lời là không: spec liên tục phát triển. Hiện tại, có 100 issue mở, nhiều trong số đó chứa các đề xuất sẽ được chính thức hóa vào một thời điểm nào đó trong tương lai.
Bây giờ, trong số 100 issue đó, chắc chắn sẽ có các tính năng mới mà chúng ta có thể hưởng lợi ngay hôm nay, phải không? Nếu vậy, tại sao phải chờ đợi?
Đó chính xác là cách suy nghĩ của tôi.

"Nhưng nếu điều gì đó không có trong GraphQL spec, thì chúng ta không nên thêm nó vào máy chủ GraphQL, hoặc người dùng sẽ bị nhầm lẫn!"
Điểm hay. Tuy nhiên, nếu chúng ta làm cho các tính năng mới chỉ khả dụng theo dạng opt-in, thì người dùng nhất định sẽ biết về nó, và không có vấn đề hay hiểu lầm nào xảy ra.
Một lần nữa, đó là cách suy nghĩ của tôi. Tuy nhiên, đây là vấn đề quan điểm, vì vậy nếu bạn thích chỉ sử dụng các tính năng mà mọi máy chủ GraphQL khác đều đang sử dụng, thì không sao.
Tôi tin rằng đây là cách WPGraphQL hoạt động. Ít nhất, tôi chưa thấy một tính năng nào vượt ra ngoài những gì đã được phê duyệt trong spec.
Đối với Gato GraphQL, tôi thường xuyên xem qua danh sách issue trong spec và, nếu tôi tìm thấy một tính năng hay, mà máy chủ của tôi có thể đáp ứng mà không cần nhiều công sức, thì tôi triển khai nó. (Thực ra, đây là một trong những sở thích của tôi.)
Đây là những tính năng "hướng tới tương lai" tôi đã triển khai cho đến nay:
✅ Thực thi nhiều queries
✅ Schema namespacing
✅ Nested mutations
✅ Composable directives
✅ Proactive feedback
✅ Versioning dựa trên field và directive
Và tôi đã lên kế hoạch thêm:
✳️ Subscriptions (đây đã là một phần của spec)
✳️ Directive @stream và @defer
✳️ Cú pháp chuỗi phẳng
Người chiến thắng hiệp này: Gato GraphQL.
Phán quyết!
Quý vị và các bạn.

Một đêm thật khó quên! Một trận đấu thật đáng nhớ! Hai tay đấm hạng nặng đã cống hiến hết mình cho ước mơ của họ.
Một ước mơ mà cả hai đang theo đuổi, nhưng chỉ một trong số họ có thể nắm bắt được.
Và bây giờ, chúng ta sẽ biết người đó là ai. Bây giờ, đến lúc nói sự thật!
Ai sẽ là nhà vô địch thế giới "GraphQL trong WordPress"?
Liệu có phải là nhà vô địch đương nhiệm được ca ngợi rộng rãi, được quần chúng yêu mến, xuất hiện trên các ấn phẩm lớn, WPGraphQL?
Hay đó sẽ là kẻ thách thức ngang tàng, dám đạp vào chân người khác mà không xin lỗi, đến không mời mà đến, Gato GraphQL?

Chúng ta đang chờ phán quyết của giám khảo. Thật căng thẳng! Ôi Trời ơi, xin hãy để trái tim tôi chịu đựng được khoảnh khắc này!
🥁 Và 🥁 người 🥁 chiến 🥁 thắng 🥁 làaaaaaaaaaaaaaaaaa 🥁 ...
Hòa!
2 võ sĩ, 2 tay đấm hạng nặng, họ hòa nhau!

Thật là một khoảnh khắc tuyệt vời! Hai đối thủ ôm nhau, cho thấy rằng chúng ta đều là bạn bè trong cộng đồng WordPress, như một gia đình lớn.
Vậy, lý do cho kết quả hòa là gì? Giám khảo giải thích:
👑 WPGraphQL phổ biến hơn, và việc sử dụng nó rộng rãi hơn.
👑 Gato GraphQL có kiến trúc tốt hơn, và có thể phục vụ WordPress tốt hơn về lâu dài.
Quý vị và các bạn, bạn đã nhận được phán quyết từ giám khảo!
Và chiếc cúp của chúng ta có hai găng tay: một cho mỗi đối thủ.

Nhưng phán quyết của bạn là gì?
Bạn sẽ tiếp tục sử dụng WPGraphQL vô điều kiện cho các nhu cầu headless của mình?
Hay bạn sẽ cho Gato GraphQL cơ hội mà nó đang đòi hỏi, tải plugin và dùng thử?
Quý vị và các bạn. Đó là tất cả cho đêm nay.
Chúng tôi thực sự hy vọng bạn đã thưởng thức trận đấu.
Và hãy hy vọng chúng ta sẽ sớm có một cuộc gặp gỡ mới giữa hai nhà vô địch của chúng ta.
Chúc ngủ ngon.
Cập nhật 01/05/2024: Tìm hiểu thêm trong so sánh Gato GraphQL vs WPGraphQL.