Conversation
Summary of ChangesHello @ardatan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a robust and flexible plugin system to the router, transforming it into a highly extensible platform. By integrating a series of well-defined plugin hooks throughout the request lifecycle, from initial HTTP handling to final execution and response, the router now supports custom logic injection at critical points. This refactoring not only enables advanced features like Automatic Persisted Queries, response caching, and custom authorization rules but also streamlines the core pipeline by centralizing common functionalities and improving modularity. The extensive suite of new end-to-end tests validates the functionality and stability of this new plugin architecture, demonstrating its potential for a wide range of custom router behaviors. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive plugin system to the router, enabling custom logic at various stages of the request pipeline. Key changes include adding plugins configuration to HiveRouterConfig, introducing PluginRegistry and PluginService for managing and integrating plugins, and defining several new plugin hooks (on_http_request, on_graphql_params, on_graphql_parse, on_graphql_validation, on_query_plan, on_execute, on_subgraph_execute, on_subgraph_http_request, on_supergraph_reload) within the hive-router-plan-executor crate. The JwtRequestDetails and AuthorizationMetadata types have been refactored to use owned String and Value types, and AuthorizationMetadata has been moved to a new hive-router-internal crate. The request processing pipeline has been significantly refactored to accommodate these hooks, moving from direct error returns to Result types and introducing a new deserialize_graphql_params module. Additionally, the bench/subgraphs now uses DashMap for request logging and includes new upload and oneofTest mutations for testing multipart and oneOf input types. Dependencies have been updated to include bollard, multer, redis, and other related crates. Review comments highlight a security vulnerability in the upload function due to potential path traversal, recommend replacing sonic_rs::from_slice_unchecked with from_slice or adding a safety comment, and suggest refactoring the execute_query_plan method into smaller, more manageable functions for improved readability and maintainability.
I am having trouble creating individual review comments. Click here to see my feedback.
bench/subgraphs/products.rs (132-144)
The upload function has a few issues that should be addressed:
- Security Vulnerability (Path Traversal): The file path is constructed using `format!("/tmp/{}
async fn upload(&self, ctx: &Context<'_>, file: Option<Upload>) -> async_graphql::Result<String> {
let uploaded_file = file.ok_or_else(|| "No file uploaded")?.value(ctx)?;
// Sanitize filename to prevent path traversal
let filename = std::path::Path::new(&uploaded_file.filename)
.file_name()
.ok_or_else(|| async_graphql::Error::new("Invalid filename"))?;
let path = std::env::temp_dir().join(filename);
let mut tmp_file = tokio::fs::File::create(&path).await?;
tokio::io::copy(&mut uploaded_file.into_async_read(), &mut tmp_file).await?;
Ok(path.to_string_lossy().into_owned())
}bin/router/src/pipeline/deserialize_graphql_params.rs (95-100)
The use of unsafe with sonic_rs::from_slice_unchecked is a concern. The style guide (Rule J) requires a safety comment for unsafe blocks explaining why it's safe. from_slice_unchecked assumes the input is valid UTF-8, but an HTTP request body isn't guaranteed to be, even with a JSON content type. A malicious request could lead to undefined behavior.
Please replace this with the safe sonic_rs::from_slice or add a detailed safety comment justifying the performance gain and explaining how the validity of the byte slice is guaranteed.
let execution_request = sonic_rs::from_slice::<GraphQLParams>(&body_bytes).map_err(|e| {
warn!("Failed to parse body: {}", e);
PipelineErrorVariant::FailedToParseBody(e)
})?;lib/executor/src/execution/plan.rs (71-201)
The execute_query_plan method is quite long and handles many concerns, making it difficult to follow. As per the style guide (Rule E), it would be beneficial to break this down into smaller, more focused functions to improve readability and maintainability. For example, the plugin hook logic could be separated from the main execution logic.
|
🐋 This PR was built and pushed to the following Docker images: Image Names: Platforms: Image Tags: Docker metadata{
"buildx.build.provenance/linux/amd64": {
"builder": {
"id": "https://github.com/graphql-hive/router/actions/runs/22393835154/attempts/1"
},
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/docker/dockerfile@1.21",
"digest": {
"sha256": "27f9262d43452075f3c410287a2c43f5ef1bf7ec2bb06e8c9eeb1b8d453087bc"
}
},
{
"uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Famd64",
"digest": {
"sha256": "329e54034ce498f9c6b345044e8f530c6691f99e94a92446f68c0adf9baa8464"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "router.Dockerfile"
},
"parameters": {
"frontend": "gateway.v0",
"args": {
"cmdline": "docker/dockerfile:1.21",
"label:org.opencontainers.image.created": "2026-02-25T11:09:00.621Z",
"label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"label:org.opencontainers.image.licenses": "MIT",
"label:org.opencontainers.image.revision": "879dd4a75fc20137b2cbc445c993192e12988699",
"label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
"label:org.opencontainers.image.title": "router",
"label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
"label:org.opencontainers.image.vendor": "theguild",
"label:org.opencontainers.image.version": "pr-628",
"source": "docker/dockerfile:1.21"
},
"locals": [
{
"name": "context"
},
{
"name": "dockerfile"
}
]
},
"environment": {
"github_actor": "ardatan",
"github_actor_id": "20847995",
"github_event_name": "pull_request",
"github_event_payload": {
"action": "synchronize",
"after": "ad6a855a4d7374aba01258d15c14583f411db780",
"before": "a6d5894d2dd3e12989423b9d6c120a38b9c24e59",
"enterprise": {
"avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
"created_at": "2024-07-02T08:52:28Z",
"description": "",
"html_url": "https://github.com/enterprises/the-guild",
"id": 187753,
"name": "The Guild",
"node_id": "E_kgDOAALdaQ",
"slug": "the-guild",
"updated_at": "2026-02-11T08:01:14Z",
"website_url": "https://the-guild.dev/"
},
"number": 628,
"organization": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
"events_url": "https://api.github.com/orgs/graphql-hive/events",
"hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
"id": 182742256,
"issues_url": "https://api.github.com/orgs/graphql-hive/issues",
"login": "graphql-hive",
"members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
"node_id": "O_kgDOCuRs8A",
"public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
"repos_url": "https://api.github.com/orgs/graphql-hive/repos",
"url": "https://api.github.com/orgs/graphql-hive"
},
"pull_request": {
"_links": {
"comments": {
"href": "https://api.github.com/repos/graphql-hive/router/issues/628/comments"
},
"commits": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628/commits"
},
"html": {
"href": "https://github.com/graphql-hive/router/pull/628"
},
"issue": {
"href": "https://api.github.com/repos/graphql-hive/router/issues/628"
},
"review_comment": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
},
"review_comments": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628/comments"
},
"self": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628"
},
"statuses": {
"href": "https://api.github.com/repos/graphql-hive/router/statuses/ad6a855a4d7374aba01258d15c14583f411db780"
}
},
"active_lock_reason": null,
"additions": 9071,
"assignee": null,
"assignees": [],
"author_association": "MEMBER",
"auto_merge": null,
"base": {
"label": "graphql-hive:main",
"ref": "main",
"repo": {
"allow_auto_merge": false,
"allow_forking": true,
"allow_merge_commit": false,
"allow_rebase_merge": false,
"allow_squash_merge": true,
"allow_update_branch": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"default_branch": "main",
"delete_branch_on_merge": true,
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"squash_merge_commit_message": "PR_BODY",
"squash_merge_commit_title": "PR_TITLE",
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"use_squash_pr_title_as_default": true,
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sha": "ce3f102b470f424904c5d970fc53a33e5a904b95",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
}
},
"body": "Documentation > https://github.com/graphql-hive/console/pull/7387\r\nPreview of the docs -> https://pr-7387.hive-landing-page.pages.dev/docs/router/guides/extending-the-router\r\nExample plugins -> https://github.com/graphql-hive/router/tree/plugin-system/plugin_examples\r\n\r\nTODO:\r\n- Document why API is implemented in this way and that way (payload.initialize_plugins, OnPluginInitResult type e.g.)\r\n- Documentation updates",
"changed_files": 213,
"closed_at": null,
"comments": 5,
"comments_url": "https://api.github.com/repos/graphql-hive/router/issues/628/comments",
"commits": 1,
"commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/628/commits",
"created_at": "2025-12-19T14:23:59Z",
"deletions": 1198,
"diff_url": "https://github.com/graphql-hive/router/pull/628.diff",
"draft": false,
"head": {
"label": "graphql-hive:plugin-system",
"ref": "plugin-system",
"repo": {
"allow_auto_merge": false,
"allow_forking": true,
"allow_merge_commit": false,
"allow_rebase_merge": false,
"allow_squash_merge": true,
"allow_update_branch": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"default_branch": "main",
"delete_branch_on_merge": true,
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"squash_merge_commit_message": "PR_BODY",
"squash_merge_commit_title": "PR_TITLE",
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"use_squash_pr_title_as_default": true,
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sha": "ad6a855a4d7374aba01258d15c14583f411db780",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
}
},
"html_url": "https://github.com/graphql-hive/router/pull/628",
"id": 3117772466,
"issue_url": "https://api.github.com/repos/graphql-hive/router/issues/628",
"labels": [],
"locked": false,
"maintainer_can_modify": false,
"merge_commit_sha": "1eff976ef7e8e4be9c3dbfde8567c2406156fb6f",
"mergeable": null,
"mergeable_state": "unknown",
"merged": false,
"merged_at": null,
"merged_by": null,
"milestone": null,
"node_id": "PR_kwDONSTNFM651W6y",
"number": 628,
"patch_url": "https://github.com/graphql-hive/router/pull/628.patch",
"rebaseable": null,
"requested_reviewers": [],
"requested_teams": [],
"review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
"review_comments": 124,
"review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/628/comments",
"state": "open",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/ad6a855a4d7374aba01258d15c14583f411db780",
"title": "Plugin System",
"updated_at": "2026-02-25T10:58:19Z",
"url": "https://api.github.com/repos/graphql-hive/router/pulls/628",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
"events_url": "https://api.github.com/users/ardatan/events{/privacy}",
"followers_url": "https://api.github.com/users/ardatan/followers",
"following_url": "https://api.github.com/users/ardatan/following{/other_user}",
"gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/ardatan",
"id": 20847995,
"login": "ardatan",
"node_id": "MDQ6VXNlcjIwODQ3OTk1",
"organizations_url": "https://api.github.com/users/ardatan/orgs",
"received_events_url": "https://api.github.com/users/ardatan/received_events",
"repos_url": "https://api.github.com/users/ardatan/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
"type": "User",
"url": "https://api.github.com/users/ardatan",
"user_view_type": "public"
}
},
"repository": {
"allow_forking": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"custom_properties": {
"vanta_production_branch_name": "main"
},
"default_branch": "main",
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sender": {
"avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
"events_url": "https://api.github.com/users/ardatan/events{/privacy}",
"followers_url": "https://api.github.com/users/ardatan/followers",
"following_url": "https://api.github.com/users/ardatan/following{/other_user}",
"gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/ardatan",
"id": 20847995,
"login": "ardatan",
"node_id": "MDQ6VXNlcjIwODQ3OTk1",
"organizations_url": "https://api.github.com/users/ardatan/orgs",
"received_events_url": "https://api.github.com/users/ardatan/received_events",
"repos_url": "https://api.github.com/users/ardatan/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
"type": "User",
"url": "https://api.github.com/users/ardatan",
"user_view_type": "public"
}
},
"github_job": "docker",
"github_ref": "refs/pull/628/merge",
"github_ref_name": "628/merge",
"github_ref_protected": "false",
"github_ref_type": "branch",
"github_repository": "graphql-hive/router",
"github_repository_id": "891604244",
"github_repository_owner": "graphql-hive",
"github_repository_owner_id": "182742256",
"github_run_attempt": "1",
"github_run_id": "22393835154",
"github_run_number": "1597",
"github_runner_arch": "X64",
"github_runner_environment": "github-hosted",
"github_runner_image_os": "ubuntu24",
"github_runner_image_version": "20260201.15.1",
"github_runner_name": "GitHub Actions 1000590268",
"github_runner_os": "Linux",
"github_runner_tracking_id": "github_f0914dd2-173a-49ec-ace2-07ce9ea5a850",
"github_server_url": "https://github.com",
"github_triggering_actor": "ardatan",
"github_workflow": "build-router",
"github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/628/merge",
"github_workflow_sha": "879dd4a75fc20137b2cbc445c993192e12988699",
"platform": "linux/amd64"
}
}
},
"buildx.build.provenance/linux/arm64": {
"builder": {
"id": "https://github.com/graphql-hive/router/actions/runs/22393835154/attempts/1"
},
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/docker/dockerfile@1.21",
"digest": {
"sha256": "27f9262d43452075f3c410287a2c43f5ef1bf7ec2bb06e8c9eeb1b8d453087bc"
}
},
{
"uri": "pkg:docker/gcr.io/distroless/cc-debian12@latest?platform=linux%2Farm64",
"digest": {
"sha256": "329e54034ce498f9c6b345044e8f530c6691f99e94a92446f68c0adf9baa8464"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "router.Dockerfile"
},
"parameters": {
"frontend": "gateway.v0",
"args": {
"cmdline": "docker/dockerfile:1.21",
"label:org.opencontainers.image.created": "2026-02-25T11:09:00.621Z",
"label:org.opencontainers.image.description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"label:org.opencontainers.image.licenses": "MIT",
"label:org.opencontainers.image.revision": "879dd4a75fc20137b2cbc445c993192e12988699",
"label:org.opencontainers.image.source": "https://github.com/graphql-hive/router",
"label:org.opencontainers.image.title": "router",
"label:org.opencontainers.image.url": "https://github.com/graphql-hive/router",
"label:org.opencontainers.image.vendor": "theguild",
"label:org.opencontainers.image.version": "pr-628",
"source": "docker/dockerfile:1.21"
},
"locals": [
{
"name": "context"
},
{
"name": "dockerfile"
}
]
},
"environment": {
"github_actor": "ardatan",
"github_actor_id": "20847995",
"github_event_name": "pull_request",
"github_event_payload": {
"action": "synchronize",
"after": "ad6a855a4d7374aba01258d15c14583f411db780",
"before": "a6d5894d2dd3e12989423b9d6c120a38b9c24e59",
"enterprise": {
"avatar_url": "https://avatars.githubusercontent.com/b/187753?v=4",
"created_at": "2024-07-02T08:52:28Z",
"description": "",
"html_url": "https://github.com/enterprises/the-guild",
"id": 187753,
"name": "The Guild",
"node_id": "E_kgDOAALdaQ",
"slug": "the-guild",
"updated_at": "2026-02-11T08:01:14Z",
"website_url": "https://the-guild.dev/"
},
"number": 628,
"organization": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"description": "Schema registry, analytics and gateway for GraphQL federation and other GraphQL APIs.",
"events_url": "https://api.github.com/orgs/graphql-hive/events",
"hooks_url": "https://api.github.com/orgs/graphql-hive/hooks",
"id": 182742256,
"issues_url": "https://api.github.com/orgs/graphql-hive/issues",
"login": "graphql-hive",
"members_url": "https://api.github.com/orgs/graphql-hive/members{/member}",
"node_id": "O_kgDOCuRs8A",
"public_members_url": "https://api.github.com/orgs/graphql-hive/public_members{/member}",
"repos_url": "https://api.github.com/orgs/graphql-hive/repos",
"url": "https://api.github.com/orgs/graphql-hive"
},
"pull_request": {
"_links": {
"comments": {
"href": "https://api.github.com/repos/graphql-hive/router/issues/628/comments"
},
"commits": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628/commits"
},
"html": {
"href": "https://github.com/graphql-hive/router/pull/628"
},
"issue": {
"href": "https://api.github.com/repos/graphql-hive/router/issues/628"
},
"review_comment": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}"
},
"review_comments": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628/comments"
},
"self": {
"href": "https://api.github.com/repos/graphql-hive/router/pulls/628"
},
"statuses": {
"href": "https://api.github.com/repos/graphql-hive/router/statuses/ad6a855a4d7374aba01258d15c14583f411db780"
}
},
"active_lock_reason": null,
"additions": 9071,
"assignee": null,
"assignees": [],
"author_association": "MEMBER",
"auto_merge": null,
"base": {
"label": "graphql-hive:main",
"ref": "main",
"repo": {
"allow_auto_merge": false,
"allow_forking": true,
"allow_merge_commit": false,
"allow_rebase_merge": false,
"allow_squash_merge": true,
"allow_update_branch": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"default_branch": "main",
"delete_branch_on_merge": true,
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"squash_merge_commit_message": "PR_BODY",
"squash_merge_commit_title": "PR_TITLE",
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"use_squash_pr_title_as_default": true,
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sha": "ce3f102b470f424904c5d970fc53a33e5a904b95",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
}
},
"body": "Documentation > https://github.com/graphql-hive/console/pull/7387\r\nPreview of the docs -> https://pr-7387.hive-landing-page.pages.dev/docs/router/guides/extending-the-router\r\nExample plugins -> https://github.com/graphql-hive/router/tree/plugin-system/plugin_examples\r\n\r\nTODO:\r\n- Document why API is implemented in this way and that way (payload.initialize_plugins, OnPluginInitResult type e.g.)\r\n- Documentation updates",
"changed_files": 213,
"closed_at": null,
"comments": 5,
"comments_url": "https://api.github.com/repos/graphql-hive/router/issues/628/comments",
"commits": 1,
"commits_url": "https://api.github.com/repos/graphql-hive/router/pulls/628/commits",
"created_at": "2025-12-19T14:23:59Z",
"deletions": 1198,
"diff_url": "https://github.com/graphql-hive/router/pull/628.diff",
"draft": false,
"head": {
"label": "graphql-hive:plugin-system",
"ref": "plugin-system",
"repo": {
"allow_auto_merge": false,
"allow_forking": true,
"allow_merge_commit": false,
"allow_rebase_merge": false,
"allow_squash_merge": true,
"allow_update_branch": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"default_branch": "main",
"delete_branch_on_merge": true,
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"squash_merge_commit_message": "PR_BODY",
"squash_merge_commit_title": "PR_TITLE",
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"use_squash_pr_title_as_default": true,
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sha": "ad6a855a4d7374aba01258d15c14583f411db780",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
}
},
"html_url": "https://github.com/graphql-hive/router/pull/628",
"id": 3117772466,
"issue_url": "https://api.github.com/repos/graphql-hive/router/issues/628",
"labels": [],
"locked": false,
"maintainer_can_modify": false,
"merge_commit_sha": "1eff976ef7e8e4be9c3dbfde8567c2406156fb6f",
"mergeable": null,
"mergeable_state": "unknown",
"merged": false,
"merged_at": null,
"merged_by": null,
"milestone": null,
"node_id": "PR_kwDONSTNFM651W6y",
"number": 628,
"patch_url": "https://github.com/graphql-hive/router/pull/628.patch",
"rebaseable": null,
"requested_reviewers": [],
"requested_teams": [],
"review_comment_url": "https://api.github.com/repos/graphql-hive/router/pulls/comments{/number}",
"review_comments": 124,
"review_comments_url": "https://api.github.com/repos/graphql-hive/router/pulls/628/comments",
"state": "open",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/ad6a855a4d7374aba01258d15c14583f411db780",
"title": "Plugin System",
"updated_at": "2026-02-25T10:58:19Z",
"url": "https://api.github.com/repos/graphql-hive/router/pulls/628",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
"events_url": "https://api.github.com/users/ardatan/events{/privacy}",
"followers_url": "https://api.github.com/users/ardatan/followers",
"following_url": "https://api.github.com/users/ardatan/following{/other_user}",
"gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/ardatan",
"id": 20847995,
"login": "ardatan",
"node_id": "MDQ6VXNlcjIwODQ3OTk1",
"organizations_url": "https://api.github.com/users/ardatan/orgs",
"received_events_url": "https://api.github.com/users/ardatan/received_events",
"repos_url": "https://api.github.com/users/ardatan/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
"type": "User",
"url": "https://api.github.com/users/ardatan",
"user_view_type": "public"
}
},
"repository": {
"allow_forking": true,
"archive_url": "https://api.github.com/repos/graphql-hive/router/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/graphql-hive/router/assignees{/user}",
"blobs_url": "https://api.github.com/repos/graphql-hive/router/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/graphql-hive/router/branches{/branch}",
"clone_url": "https://github.com/graphql-hive/router.git",
"collaborators_url": "https://api.github.com/repos/graphql-hive/router/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/graphql-hive/router/comments{/number}",
"commits_url": "https://api.github.com/repos/graphql-hive/router/commits{/sha}",
"compare_url": "https://api.github.com/repos/graphql-hive/router/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/graphql-hive/router/contents/{+path}",
"contributors_url": "https://api.github.com/repos/graphql-hive/router/contributors",
"created_at": "2024-11-20T16:16:12Z",
"custom_properties": {
"vanta_production_branch_name": "main"
},
"default_branch": "main",
"deployments_url": "https://api.github.com/repos/graphql-hive/router/deployments",
"description": "Open-source (MIT) GraphQL Federation Router. Built with Rust for maximum performance and robustness.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/graphql-hive/router/downloads",
"events_url": "https://api.github.com/repos/graphql-hive/router/events",
"fork": false,
"forks": 8,
"forks_count": 8,
"forks_url": "https://api.github.com/repos/graphql-hive/router/forks",
"full_name": "graphql-hive/router",
"git_commits_url": "https://api.github.com/repos/graphql-hive/router/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/graphql-hive/router/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/graphql-hive/router/git/tags{/sha}",
"git_url": "git://github.com/graphql-hive/router.git",
"has_discussions": false,
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": false,
"has_pull_requests": true,
"has_wiki": false,
"homepage": "https://the-guild.dev/graphql/hive/docs/router",
"hooks_url": "https://api.github.com/repos/graphql-hive/router/hooks",
"html_url": "https://github.com/graphql-hive/router",
"id": 891604244,
"is_template": false,
"issue_comment_url": "https://api.github.com/repos/graphql-hive/router/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/graphql-hive/router/issues/events{/number}",
"issues_url": "https://api.github.com/repos/graphql-hive/router/issues{/number}",
"keys_url": "https://api.github.com/repos/graphql-hive/router/keys{/key_id}",
"labels_url": "https://api.github.com/repos/graphql-hive/router/labels{/name}",
"language": "Rust",
"languages_url": "https://api.github.com/repos/graphql-hive/router/languages",
"license": {
"key": "mit",
"name": "MIT License",
"node_id": "MDc6TGljZW5zZTEz",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit"
},
"merges_url": "https://api.github.com/repos/graphql-hive/router/merges",
"milestones_url": "https://api.github.com/repos/graphql-hive/router/milestones{/number}",
"mirror_url": null,
"name": "router",
"node_id": "R_kgDONSTNFA",
"notifications_url": "https://api.github.com/repos/graphql-hive/router/notifications{?since,all,participating}",
"open_issues": 58,
"open_issues_count": 58,
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/182742256?v=4",
"events_url": "https://api.github.com/users/graphql-hive/events{/privacy}",
"followers_url": "https://api.github.com/users/graphql-hive/followers",
"following_url": "https://api.github.com/users/graphql-hive/following{/other_user}",
"gists_url": "https://api.github.com/users/graphql-hive/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/graphql-hive",
"id": 182742256,
"login": "graphql-hive",
"node_id": "O_kgDOCuRs8A",
"organizations_url": "https://api.github.com/users/graphql-hive/orgs",
"received_events_url": "https://api.github.com/users/graphql-hive/received_events",
"repos_url": "https://api.github.com/users/graphql-hive/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/graphql-hive/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/graphql-hive/subscriptions",
"type": "Organization",
"url": "https://api.github.com/users/graphql-hive",
"user_view_type": "public"
},
"private": false,
"pull_request_creation_policy": "all",
"pulls_url": "https://api.github.com/repos/graphql-hive/router/pulls{/number}",
"pushed_at": "2026-02-25T10:58:18Z",
"releases_url": "https://api.github.com/repos/graphql-hive/router/releases{/id}",
"size": 5097,
"ssh_url": "git@github.com:graphql-hive/router.git",
"stargazers_count": 73,
"stargazers_url": "https://api.github.com/repos/graphql-hive/router/stargazers",
"statuses_url": "https://api.github.com/repos/graphql-hive/router/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/graphql-hive/router/subscribers",
"subscription_url": "https://api.github.com/repos/graphql-hive/router/subscription",
"svn_url": "https://github.com/graphql-hive/router",
"tags_url": "https://api.github.com/repos/graphql-hive/router/tags",
"teams_url": "https://api.github.com/repos/graphql-hive/router/teams",
"topics": [
"apollo-federation",
"federation",
"federation-gateway",
"graphql",
"graphql-federation",
"router"
],
"trees_url": "https://api.github.com/repos/graphql-hive/router/git/trees{/sha}",
"updated_at": "2026-02-25T10:55:23Z",
"url": "https://api.github.com/repos/graphql-hive/router",
"visibility": "public",
"watchers": 73,
"watchers_count": 73,
"web_commit_signoff_required": false
},
"sender": {
"avatar_url": "https://avatars.githubusercontent.com/u/20847995?v=4",
"events_url": "https://api.github.com/users/ardatan/events{/privacy}",
"followers_url": "https://api.github.com/users/ardatan/followers",
"following_url": "https://api.github.com/users/ardatan/following{/other_user}",
"gists_url": "https://api.github.com/users/ardatan/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/ardatan",
"id": 20847995,
"login": "ardatan",
"node_id": "MDQ6VXNlcjIwODQ3OTk1",
"organizations_url": "https://api.github.com/users/ardatan/orgs",
"received_events_url": "https://api.github.com/users/ardatan/received_events",
"repos_url": "https://api.github.com/users/ardatan/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/ardatan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ardatan/subscriptions",
"type": "User",
"url": "https://api.github.com/users/ardatan",
"user_view_type": "public"
}
},
"github_job": "docker",
"github_ref": "refs/pull/628/merge",
"github_ref_name": "628/merge",
"github_ref_protected": "false",
"github_ref_type": "branch",
"github_repository": "graphql-hive/router",
"github_repository_id": "891604244",
"github_repository_owner": "graphql-hive",
"github_repository_owner_id": "182742256",
"github_run_attempt": "1",
"github_run_id": "22393835154",
"github_run_number": "1597",
"github_runner_arch": "X64",
"github_runner_environment": "github-hosted",
"github_runner_image_os": "ubuntu24",
"github_runner_image_version": "20260201.15.1",
"github_runner_name": "GitHub Actions 1000590268",
"github_runner_os": "Linux",
"github_runner_tracking_id": "github_f0914dd2-173a-49ec-ace2-07ce9ea5a850",
"github_server_url": "https://github.com",
"github_triggering_actor": "ardatan",
"github_workflow": "build-router",
"github_workflow_ref": "graphql-hive/router/.github/workflows/build-router.yaml@refs/pull/628/merge",
"github_workflow_sha": "879dd4a75fc20137b2cbc445c993192e12988699",
"platform": "linux/amd64"
}
}
},
"buildx.build.ref": "builder-3a4ac71c-f634-4d31-acf3-eb6292305f2a/builder-3a4ac71c-f634-4d31-acf3-eb6292305f2a0/hgza85m3l7zglfqo17k7sp5l8",
"containerimage.descriptor": {
"mediaType": "application/vnd.oci.image.index.v1+json",
"digest": "sha256:1a59ac52a8866bb2fac3b9ff3ae0118f09db1e0ca5175b7b5396cbb4754b4a1a",
"size": 1609
},
"containerimage.digest": "sha256:1a59ac52a8866bb2fac3b9ff3ae0118f09db1e0ca5175b7b5396cbb4754b4a1a",
"image.name": "ghcr.io/graphql-hive/router:pr-628,ghcr.io/graphql-hive/router:sha-879dd4a"
} |
63154db to
b4fabd3
Compare
61deae4 to
2ba4c52
Compare
df0377d to
a4fb2d6
Compare
Extracted from #628 Introduces `pub fn from_message_and_code` to create an error with an error code in the extensions which reduce the code a lot in different places. Helpers that take `&str` or `String` are replaced with `Into<String>` so that extra `.to_string()` or `.into()` calls for different variations of string can be avoided. Benefits; - No need for `.to_string()`, `.clone()` and `.into()` for different variations of string ```diff let message_ref: &str = ...; let code_ref: &str = ...; let error_from_refs = GraphQLError::from_message_and_code( - message_ref.to_string() + message_ref - code_ref.to_string() + code_ref ); ``` - No need to call `GraphQLErrorExtensions::from_code` thanks to `message_and_code` helper ```diff - GraphQLError::from_message_and_extensions( + GraphQLError::from_message_and_code( message, - GraphQLErrorExtensions::from_code(code + code ) ``` --------- Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>
Extracted from #628 - `SubgraphExecutor` now returns `SubgraphResponse` that has the deserialized response in it with `bytes: Bytes` to be stored in the response storage later on. - `HTTPSubgraphExecutor` is now responsible of deserialization instead of Plan executor. - No need for `Arc<Bytes>` because `Bytes` already uses `Arc` internally so it has 0 cost of cloning Why? In the plugin system's `on_subgraph_execute` hook is expected to return `SubgraphResponse` which is basically `data`, `errors` and `extensions` (of course together with an optional `bytes` and `headers`). In order to have a better DX, I wanted to make this flow's return value `SubgraphResponse` while keeping `HttpResponse` as `on_subgraph_http_request`'s return value. In this way `SubgraphResponse` becomes HTTP-independent, and it will be easy to handle errors and etc without generating bytes and doing deserialization and serialization work etc for prebuilt responses. For example `graphql_error_to_bytes` is no longer needed with this. It can be just `SubgraphResponse { errors: vec![error], ...Default:default()` --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
f5ee85a to
ee3641a
Compare
…cutor (#652) Extracted from #628 Combining with #651 , the aim is to reduce the number of extra structs. Today, `PlanExecutionOutput` which is the return type of `execute_query_plan` in `executor/execution/plan.rs`, returns `body: Vec<u8>` and `headers: http::HeaderMap`. Then, in the `router/pipeline`, `ResponseBuilder` is called with `Bytes::from` of `PlanExecutionOutput.body` and `PlanExecutionOutput.headers` is converted to `ntex::HeaderMap`, then `content_type` is set here. With this PR, the response aggregator is sent with `PlanExecutionOutput`, and during the response build, the response headers aggregator sets the headers into `ResponseBuilder` directly. So now `modify_client_headers` helper accepts `ResponseBuilder`, not `http:HeaderMap`. And since this throws `HeaderPropagationError` in the pipeline executor, I had to add `HeaderPropagationError` to `PipelineError`. I also extracted `PipelineError` to `FailedExecutionResult` logic to a `From` trait so that other future implementations that serializes and sets the body in a different way can use it and serialize `FailedExecutionResult` on their own. Currently it is used here only -> https://github.com/graphql-hive/router/pull/652/changes#diff-f3dc2f2d579374645281d6950414266d8984195dbf45c00f0a754ceca8550aadR95 ---- Update: After recent changes, I see that `project_by_operation` is used for `dry_run` but it is actually unnecessary as we just need to serialize `extensions` which has nothing to do with projection since it uses `sonic_rs::Value`.
c6f3a95 to
b56ee69
Compare
|
@gemini-code-assist review |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive plugin system to the router, enabling custom logic injection at various stages of the request lifecycle. Key changes include adding numerous new plugin examples (e.g., Apollo Sandbox, APQ, Async Auth, Multipart, Response Cache, Root Field Limit, Usage Reporting) to the workspace and Cargo.lock, along with their dependencies. The core router logic has been refactored to integrate this system, moving authorization metadata and background task management to an internal crate (hive_router_internal). The router's entry point now accepts a PluginRegistry, and a PluginService middleware is added to the Ntex application to manage plugin hooks. Several pipeline stages (graphql_params, parse, validation, query_plan, execute, subgraph_execute, subgraph_http_request, supergraph_reload, graphql_error, shutdown) have been updated to incorporate plugin hooks, allowing plugins to modify payloads, short-circuit execution with custom responses, or register callbacks for post-processing. The e2e tests and subgraphs were also updated to support these new plugin functionalities, including adding a Mutation type for file uploads and oneOf tests. Review comments highlighted critical areas for improvement: the unwrap() call in the incoming request deduplication plugin was flagged as dangerous and a potential denial-of-service vulnerability, recommending graceful error handling; the use of StatusCode::PAYLOAD_TOO_LARGE for a @oneOf validation error was deemed semantically incorrect, suggesting StatusCode::BAD_REQUEST; and an inconsistent error code (TOO_MANY_ROOT_FIELDS) in the @oneOf validation rule was noted, recommending TOO_MANY_FIELDS_SET_IN_ONEOF for clarity and consistency.
aa8c1eb to
2477b25
Compare
784e21a to
0cffc2b
Compare
2b28145 to
e19606b
Compare
039e0e5 to
a6d5894
Compare
a6d5894 to
ad6a855
Compare
Documentation > graphql-hive/console#7387
Preview of the docs -> https://pr-7387.hive-landing-page.pages.dev/docs/router/guides/extending-the-router
Example plugins -> https://github.com/graphql-hive/router/tree/plugin-system/plugin_examples
TODO: