{"id":13561983,"url":"https://github.com/wundergraph/graphql-go-tools","last_synced_at":"2026-02-21T22:25:51.752Z","repository":{"id":37976655,"uuid":"156971837","full_name":"wundergraph/graphql-go-tools","owner":"wundergraph","description":"GraphQL Router / API Gateway framework written in Golang, focussing on correctness, extensibility, and high-performance. Supports Federation v1 \u0026 v2, Subscriptions \u0026 more.","archived":false,"fork":false,"pushed_at":"2026-02-19T16:26:31.000Z","size":26857,"stargazers_count":815,"open_issues_count":39,"forks_count":158,"subscribers_count":18,"default_branch":"master","last_synced_at":"2026-02-19T20:26:38.036Z","etag":null,"topics":["ast","ast-normalization","ast-parser","ast-printer","ast-transformation","ast-visitor","complexity-analysis","execution","execution-engine","golang","graphql","graphql-tools","introspection","introspection-query","lexer","linter","parser","parsing","printing","validation"],"latest_commit_sha":null,"homepage":"https://wundergraph.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wundergraph.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-11-10T10:46:56.000Z","updated_at":"2026-02-19T16:27:26.000Z","dependencies_parsed_at":"2024-08-05T15:00:09.386Z","dependency_job_id":"af110ded-f65d-4d84-961d-f2fa38e69a3d","html_url":"https://github.com/wundergraph/graphql-go-tools","commit_stats":{"total_commits":2589,"total_committers":45,"mean_commits":57.53333333333333,"dds":0.5488605639242952,"last_synced_commit":"155cdab36cb656de36659c8c6309a6e50444abce"},"previous_names":["jensneuse/graphql-go-tools"],"tags_count":428,"template":false,"template_full_name":null,"purl":"pkg:github/wundergraph/graphql-go-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wundergraph%2Fgraphql-go-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wundergraph%2Fgraphql-go-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wundergraph%2Fgraphql-go-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wundergraph%2Fgraphql-go-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wundergraph","download_url":"https://codeload.github.com/wundergraph/graphql-go-tools/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wundergraph%2Fgraphql-go-tools/sbom","scorecard":{"id":515125,"data":{"date":"2025-07-07","repo":{"name":"github.com/wundergraph/graphql-go-tools","commit":"1166a10a5da4151af5a7abeea7bee45d63d71349"},"scorecard":{"version":"v5.2.1-18-gbb9c347d","commit":"bb9c347dff6349d986baab6578a46d68a5524c62"},"score":4.6,"checks":[{"name":"Code-Review","score":8,"reason":"Found 26/30 approved changesets -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/execution.yml:1","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/pr-title.yml:11","Info: topLevel 'issues' permission set to 'read': .github/workflows/pr-title.yml:12","Warn: topLevel 'contents' permission set to 'write': .github/workflows/release.yml:8","Warn: no topLevel permission defined: .github/workflows/v2.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#cii-best-practices"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#license"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#binary-artifacts"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#signed-releases"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/execution.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/execution.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/execution.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/execution.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/execution.yml:50: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/execution.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/execution.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/execution.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/execution.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/execution.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr-title.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/pr-title.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr-title.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/pr-title.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/v2.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/v2.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/v2.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/v2.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/v2.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/v2.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/v2.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/v2.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/v2.yml:60: update your workflow using https://app.stepsecurity.io/secureworkflow/wundergraph/graphql-go-tools/v2.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/pr-title.yml:41","Info:   0 out of  10 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"88 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2024-2920 / GHSA-2hmf-46v7-v6fx","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-pfq8-rq6v-vf5m","Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5","Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp","Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq","Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr","Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765","Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-5q6m-3h65-w53x","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-g4rg-993r-mgx7","Warn: Project is vulnerable to: GHSA-c9g6-9335-x697","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6","Warn: Project is vulnerable to: GHSA-4v9v-hfq4-rm2v","Warn: Project is vulnerable to: GHSA-9jgg-88mc-972h","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T01:36:39.126Z","repository_id":37976655,"created_at":"2025-08-20T01:36:39.126Z","updated_at":"2025-08-20T01:36:39.126Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29695779,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T18:18:25.093Z","status":"ssl_error","status_checked_at":"2026-02-21T18:18:22.435Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","ast-normalization","ast-parser","ast-printer","ast-transformation","ast-visitor","complexity-analysis","execution","execution-engine","golang","graphql","graphql-tools","introspection","introspection-query","lexer","linter","parser","parsing","printing","validation"],"created_at":"2024-08-01T13:01:03.299Z","updated_at":"2026-02-21T22:25:51.731Z","avatar_url":"https://github.com/wundergraph.png","language":"Go","readme":"[![GoDoc](https://pkg.go.dev/badge/github.com/wundergraph/graphql-go-tools/v2)](https://pkg.go.dev/github.com/wundergraph/graphql-go-tools/v2)\n[![v2-ci](https://github.com/wundergraph/graphql-go-tools/actions/workflows/v2.yml/badge.svg)](https://github.com/wundergraph/graphql-go-tools/actions/workflows/v2.yml)\n# GraphQL Router / API Gateway Framework written in Golang\n\n[\u003cp align=\"center\"\u003e\u003cimg height=\"auto\" src=\"./assets/logo.png\"\u003e\u003c/p\u003e](https://wundergraph.com/)\n\n## We're hiring!\n\nAre you interested in working on graphql-go-tools?\nWe're looking for experienced Go developers and DevOps or Platform Engineering specialists to help us run Cosmo Cloud.\nIf you're more interested in working with Customers on their GraphQL Strategy,\nwe also offer Solution Architect positions.\n\nCheck out the [currently open positions](https://wundergraph.com/jobs#open-positions).\n\n## The State of GraphQL Federation 2024\n\nGet insights from industry experts and Federation practitioners across all industries and learn how companies are using GraphQL Federation.\nHead over to the [State of GraphQL Federation 2024](https://wundergraph.com/state-of-graphql-federation/2024) page and download the full **48 page PDF report** for free!\n\n## From the WunderGraph Blog\n\nHere's a selection of blog posts that focus on the technical aspects of GraphQL Federation,\ndiving into the internals of this library:\n\n- [**How we scaled Cosmo Router for the SuperBowl**](https://wundergraph.com/blog/scaling-graphql-federation-for-the-superbowl)\n- [**The Architecture of our Observability Stack**](https://wundergraph.com/blog/scaling_graphql_observability)\n- [**How Normalization affects Query Planning**](https://wundergraph.com/blog/normalization_query_planning_graphql_federation)\n- [**Zero cost abstraction for the @skip and @include Directives**](https://wundergraph.com/blog/zero_cost_abstraction_for_skip_include_in_federated_graphql)\n- [**Algorithm to minify GraphQL ASTs by up to 99%**](https://wundergraph.com/blog/graphql_query_ast_minification)\n- [**Federated GraphQL Subscriptions with NATS and Event Driven Architecture**](https://wundergraph.com/blog/distributed_graphql_subscriptions_with_nats_and_event_driven_architecture)\n- [**Implementing the viewer pattern in GraphQL Federation**](https://wundergraph.com/blog/graphql_federation_viewer_pattern)\n- [**How we're using Epoll/Kqueue to scale GraphQL Subscriptions**](https://wundergraph.com/blog/edfs_scaling_graphql_subscriptions_in_go)\n- [**ASTJSON - A fast way to merge JSON objects**](https://wundergraph.com/blog/astjson_high_performance_json_transformations_in_golang)\n- [**Dataloader 3.0, an efficient algorithm for Federation data loading**](https://wundergraph.com/blog/dataloader_3_0_breadth_first_data_loading)\n\n## Replacement for Apollo Router\n\nIf you're looking for a complete ready-to-use Open Source Router for Federation,\nhave a look at the [Cosmo Router](https://github.com/wundergraph/cosmo) which is based on this library.\n\nCosmo Router wraps this library and provides a complete solution for Federated GraphQL including the following features:\n- [x] Federation Gateway\n- [x] OpenTelemetry Metrics \u0026 Distributed Tracing\n- [x] Prometheus Metrics\n- [x] GraphQL Schema Usage Exporter\n- [x] Health Checks\n- [x] GraphQL Playground\n- [x] Execution Tracing Exporter \u0026 UI in the Playground\n- [x] Federated Subscriptions over WebSockets (graphql-ws \u0026 graphql-transport-ws protocol support) and SSE\n- [x] Authentication using JWKS \u0026 JWT\n- [x] Highly available \u0026 scalable using S3 as a backend for the Router Config\n- [x] Persisted Operations / Trusted Documents\n- [x] Traffic Shaping (Timeouts, Retries, Header \u0026 Body Size Limits, Subgraph Header forwarding)\n- [x] Custom Modules \u0026 Middleware\n\n## State of the packages\n\nThis repository contains multiple packages joined via [workspace](https://github.com/wundergraph/graphql-go-tools/blob/master/go.work).\n\n| Package                                                                                                       | Description                                                                                                                                                                                                                        | Package dependencies                                                                                                                                                                            | Maintenance state                  |\n|---------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|\n| [graphql-go-tools v2](https://github.com/wundergraph/graphql-go-tools/blob/master/v2/go.mod)                  | GraphQL engine implementation consisting of lexer, parser, ast, ast validation, ast normalization, datasources, query planner and resolver. Supports GraphQL Federation. Has built-in support for batching federation entity calls | -                                                                                                                                                                                               | actual version, active development |\n| [execution](https://github.com/wundergraph/graphql-go-tools/blob/master/execution/go.mod)                     | Execution helpers for the request handling and engine configuration builder                                                                                                                                                        | depends on [graphql-go-tools v2](https://github.com/wundergraph/graphql-go-tools/blob/master/v2/go.mod) and [composition](https://github.com/wundergraph/cosmo/blob/main/composition-go/go.mod) | actual version                     |\n| [examples/federation](https://github.com/wundergraph/graphql-go-tools/blob/master/examples/federation/go.mod) | Example implementation of graphql federation gateway. This example is not production ready. For production ready solution please consider using [cosmo router](https://github.com/wundergraph/cosmo/tree/main)                     | depends on [execution](https://github.com/wundergraph/graphql-go-tools/blob/master/execution/go.mod) package                                                                                    | actual federation gateway example  |\n| [graphql-go-tools v1](https://github.com/wundergraph/graphql-go-tools/blob/v1.67.4/go.mod)                    | Deprecated and retracted GraphQL engine implementation. Not supported nor maintained. It was removed from the repo in v1.67.5.                                                                                                     | -                                                                                                                                                                                               | deprecated                         |\n\n\n## Notes\n\nThis library is used in production at [WunderGraph](https://wundergraph.com/).\nWe support and actively improve only the v2 module.\n\nWe have customers who pay us to maintain this library and steer the direction of the project.\n[Contact us](https://wundergraph.com/contact/sales) if you're looking for commercial support, features or consulting.\n\n## Performance\n\nThe architecture of this library is designed for performance, high throughput and low garbage collection overhead.\nThe following benchmark measures the \"overhead\" of loading and resolving a GraphQL response from four static in-memory Subgraphs at 0,007459 ms/op.\nIn more complete end-to-end benchmarks, we've measured up to 8x more requests per second and 8x lower p99 latency compared to Apollo Router, which is written in Rust.\n\n```shell\ncd v2/pkg/engine/resolve\ngo test -run=nothing -bench=Benchmark_NestedBatchingWithoutChecks -memprofile memprofile.out -benchtime 3s \u0026\u0026 go tool pprof memprofile.out\ngoos: darwin\ngoarch: arm64\npkg: github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve\nBenchmark_NestedBatchingWithoutChecks-10          473186              7134 ns/op          52.00 MB/s        2086 B/op         36 allocs/op\n```\n\n## Tutorial\n\nIf you're here to learn how to use this library to build your own custom GraphQL Router or API Gateway,\nhere's a speed-run tutorial, based on how we use this library in Cosmo Router.\n\n```go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cespare/xxhash/v2\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/ast\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/astnormalization\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/astparser\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/astprinter\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/asttransform\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/astvalidation\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/datasource/staticdatasource\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/plan\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve\"\n\t\"github.com/wundergraph/graphql-go-tools/v2/pkg/operationreport\"\n)\n\n/*\nExampleParsePrintDocument shows you the most basic usage of the library.\nIt parses a GraphQL document and prints it back to a writer.\n*/\nfunc ExampleParsePrintDocument() {\n  input := []byte(`query Hello { world }`)\n\n  report := \u0026operationreport.Report{}\n  document := ast.NewSmallDocument()\n  parser := astparser.NewParser()\n  printer := \u0026astprinter.Printer{}\n\n  document.Input.ResetInputBytes(input)\n  parser.Parse(document, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  out := \u0026bytes.Buffer{}\n  err := printer.Print(document, out)\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(out.String()) // Output: query Hello {world}\n}\n\n/*\nOkay, that was easy, but also not very useful.\nLet's try to parse a more complex document and print it back to a writer.\n*/\n\n// ExampleParseComplexDocument shows a special feature of the printer\nfunc ExampleParseComplexDocument() {\n  input := []byte(`\n    query {\n      hello\n      foo {\n        bar\n      }\n    }\n  `)\n\n  report := \u0026operationreport.Report{}\n  document := ast.NewSmallDocument()\n  parser := astparser.NewParser()\n  printer := \u0026astprinter.Printer{}\n\n  document.Input.ResetInputBytes(input)\n  parser.Parse(document, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  out := \u0026bytes.Buffer{}\n  err := printer.Print(document, out)\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(out.String()) // Output: { hello foo { bar } }\n}\n\n/*\nYou'll notice that the printer removes all whitespace and newlines.\nBut what if we wanted to print the document with indentation?\n*/\n\nfunc ExamplePrintWithIndentation() {\n  input := []byte(`\n    {\n      hello\n      foo {\n        bar\n      }\n    }\n  `)\n\n  report := \u0026operationreport.Report{}\n  document := ast.NewSmallDocument()\n  parser := astparser.NewParser()\n\n  document.Input.ResetInputBytes(input)\n  parser.Parse(document, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  out, err := astprinter.PrintStringIndent(document, \"  \")\n  if err != nil {\n    panic(err)\n  }\n  fmt.Println(out)\n  // Output: {\n  //   hello\n  //   foo {\n  //     bar\n  //   }\n  // }\n}\n\n/*\nOkay, fantastic. We can parse and print GraphQL documents.\nAs a next step, we could analyze the document and extract some information from it.\nWhat if we wanted to know the name of the operation in the document, if any?\nAnd what if we wanted to know about the Operation type?\n*/\n\nfunc ExampleParseOperationNameAndType() {\n  input := []byte(`\n    query MyQuery {\n      hello\n      foo {\n        bar\n      }\n    }\n  `)\n\n  report := \u0026operationreport.Report{}\n  document := ast.NewSmallDocument()\n  parser := astparser.NewParser()\n\n  document.Input.ResetInputBytes(input)\n  parser.Parse(document, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  operationCount := 0\n  var (\n    operationNames []string\n    operationTypes []ast.OperationType\n  )\n\n  for _, node := range document.RootNodes {\n    if node.Kind != ast.NodeKindOperationDefinition {\n      continue\n    }\n    operationCount++\n    name := document.OperationDefinitionNameString(node.Ref)\n    operationNames = append(operationNames, name)\n    operationType := document.OperationDefinitions[node.Ref].OperationType\n    operationTypes = append(operationTypes, operationType)\n  }\n\n  fmt.Println(operationCount) // Output: 1\n  fmt.Println(operationNames) // Output: [MyQuery]\n}\n\n/*\nWe've now seen how to analyze the document and learn a bit about it.\nWe could now add some validation to our application,\ne.g. we could check for the number of operations in the document,\nand return an error if there are multiple anonymous operations.\n\nWe could also validate the Operation content against a schema.\nBut before we do this, we need to normalize the document.\nThis is important because validation relies on the document being normalized.\nIt was much easier to build the validation and many other features on top of a normalized document.\n\nNormalization is the process of transforming the document into a canonical form.\nThis means that the document is transformed in a way that makes it easier to reason about it.\nWe inline fragments, we remove unused fragments,\nwe remove duplicate fields, we remove unused variables,\nwe remove unused operations etc...\n\nSo, let's normalize the document!\n*/\n\nfunc ExampleNormalizeDocument() {\n  input := []byte(`\n    query MyQuery {\n      hello\n      hello\n      foo {\n        bar\n        bar\n      }\n      ...MyFragment\n    }\n\n    fragment MyFragment on Query {\n      hello\n      foo {\n        bar\n      }\n    }\n  `)\n\n  schema := []byte(`\n    type Query {\n      hello: String\n      foo: Foo\n    }\n  \n    type Foo {\n      bar: String\n    }\n  `)\n\n  report := \u0026operationreport.Report{}\n  document := ast.NewSmallDocument()\n  parser := astparser.NewParser()\n\n  document.Input.ResetInputBytes(input)\n  parser.Parse(document, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  schemaDocument := ast.NewSmallDocument()\n  schemaParser := astparser.NewParser()\n  schemaDocument.Input.ResetInputBytes(schema)\n  schemaParser.Parse(schemaDocument, report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  // graphql-go-tools is very strict about the schema\n  // the above GraphQL Schema is not fully valid, e.g. the `schema { query: Query }` part is missing\n  // we can fix this automatically by merging the schema with a base schema\n  err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument)\n  if err != nil {\n    panic(err)\n  }\n\n  // you can customize what rules the normalizer should apply\n  normalizer := astnormalization.NewWithOpts(\n    astnormalization.WithExtractVariables(),\n    astnormalization.WithInlineFragmentSpreads(),\n    astnormalization.WithRemoveFragmentDefinitions(),\n    astnormalization.WithRemoveNotMatchingOperationDefinitions(),\n  )\n\n  // It's generally recommended to always give your operation a name\n  // If it doesn't have a name, just add one to the AST before normalizing it\n  // This is not strictly necessary, but ensures that all normalization rules work as expected\n  normalizer.NormalizeNamedOperation(document, schemaDocument, []byte(\"MyQuery\"), report)\n\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  out, err := astprinter.PrintStringIndent(document, \"  \")\n  if err != nil {\n    panic(err)\n  }\n\n  fmt.Println(out)\n  // Output: query MyQuery {\n  //   hello\n  //   foo {\n  //     bar\n  //   }\n  // }\n}\n\n/*\nOkay, that was a lot of work, but now we have a normalized document.\nAs you can see, all the duplicate fields have been removed and the fragment has been inlined.\n\nWhat can we do with it?\nWell, the possibilities are endless,\nbut why don't we start with validating the document against a schema?\nAlright. Let's do it!\n*/\n\nfunc ExampleValidateDocument() {\n  input := []byte(`\n    query MyQuery {\n      helo\n    }\n  `)\n  schema := []byte(`\n    type Query {\n      hello: String\n    }\n  `)\n\n  report := \u0026operationreport.Report{}\n\n  operationDocumentParser := astparser.NewParser()\n  operationDocument := ast.NewSmallDocument()\n  operationDocument.Input.ResetInputBytes(input)\n  operationDocumentParser.Parse(operationDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  schemaParser := astparser.NewParser()\n  schemaDocument := ast.NewSmallDocument()\n  schemaDocument.Input.ResetInputBytes(schema)\n  schemaParser.Parse(schemaDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument)\n  if err != nil {\n    panic(err)\n  }\n\n  validator := astvalidation.DefaultOperationValidator()\n  validator.Validate(operationDocument, schemaDocument, report)\n  if report.HasErrors() {\n    println(report.Error())\n  }\n}\n\n/*\nFantastic, we've now got a GraphQL document that is valid against a schema.\n\nAs a next step, we could generate a cache key for the document.\nThis is very useful if we want to start doing expensive operations afterward that could be de-duplicated or cached.\nAt the same time, generating a cache key from a normalized document is not as trivial as it sounds.\nLet's take a look!\n*/\n\nfunc ExampleGenerateCacheKey() {\n  operationDocument := ast.NewSmallDocument()\n  schemaDocument := ast.NewSmallDocument()\n  report := \u0026operationreport.Report{}\n\n  normalizer := astnormalization.NewWithOpts(\n    astnormalization.WithExtractVariables(),\n    astnormalization.WithInlineFragmentSpreads(),\n    astnormalization.WithRemoveFragmentDefinitions(),\n    astnormalization.WithRemoveNotMatchingOperationDefinitions(),\n  )\n\n  normalizer.NormalizeNamedOperation(\n    operationDocument, schemaDocument, []byte(\"MyQuery\"), report)\n  printer := \u0026astprinter.Printer{}\n  keyGen := xxhash.New()\n  err := printer.Print(operationDocument, keyGen)\n  if err != nil {\n    panic(err)\n  }\n\n  // you might be thinking that we're done now, but we're not\n  // we've extracted the variables, so we need to add them to the cache key\n\n  _, err = keyGen.Write(operationDocument.Input.Variables)\n  if err != nil {\n    panic(err)\n  }\n\n  key := keyGen.Sum64()\n  fmt.Printf(\"%x\\n\", key) // Output: {cache key}\n}\n\n/*\nGood job! We now have a correct cache key for the document.\nWe're using this ourselves in production to de-duplicate e.g. planning the execution of a GraphQL Operation.\n\nThere's just one problem with the above code.\nAn attacker could easily send the same document with a different Operation name and get a different cache key.\nThis could quite easily fill up our cache with duplicate entries.\nTo prevent this, we can make the operation name static.\nLet's change out code to account for this.\n*/\n\nfunc ExampleGenerateCacheKeyWithStaticOperationName() {\n  staticOperationName := []byte(\"O\")\n\n  operationDocument := ast.NewSmallDocument()\n  schemaDocument := ast.NewSmallDocument()\n  report := \u0026operationreport.Report{}\n\n  normalizer := astnormalization.NewWithOpts(\n    astnormalization.WithExtractVariables(),\n    astnormalization.WithInlineFragmentSpreads(),\n    astnormalization.WithRemoveFragmentDefinitions(),\n    astnormalization.WithRemoveNotMatchingOperationDefinitions(),\n  )\n\n  // First, we add the static operation name to the document and get an \"address\" to the byte slice (string) in the document\n  // We cannot just add a string to an AST because the AST only stores references to byte slices\n  // Storing strings in AST nodes would be very inefficient and would require a lot of allocations\n  nameRef := operationDocument.Input.AppendInputBytes(staticOperationName)\n\n  for _, node := range operationDocument.RootNodes {\n    if node.Kind != ast.NodeKindOperationDefinition {\n      continue\n    }\n    name := operationDocument.OperationDefinitionNameString(node.Ref)\n    if name != \"MyQuery\" {\n      continue\n    }\n    // Then we set the name of the operation to the address of the static operation name\n    // Now we have renamed MyQuery to O\n    operationDocument.OperationDefinitions[node.Ref].Name = nameRef\n  }\n\n  // Now we can normalize the modified document\n  // All Operations that don't have the name O will be removed\n  normalizer.NormalizeNamedOperation(operationDocument, schemaDocument, staticOperationName, report)\n\n  printer := \u0026astprinter.Printer{}\n  keyGen := xxhash.New()\n  err := printer.Print(operationDocument, keyGen)\n  if err != nil {\n    panic(err)\n  }\n\n  _, err = keyGen.Write(operationDocument.Input.Variables)\n  if err != nil {\n    panic(err)\n  }\n\n  key := keyGen.Sum64()\n  fmt.Printf(\"%x\\n\", key) // Output: {cache key}\n}\n\n/*\nWith these changes, the name of the operation doesn't matter anymore.\nIndependent of the name, the cache key will always be the same.\n\nAs a next step, we could start planning the execution of the operation.\nThis is a very complex topic, so we'll just show you how to plan the operation.\nGoing into detail would be beyond the scope of this example.\nIt took us years to get this right, so we won't be able to explain it in a few lines of code.\n\ngraphql-go-tools is not a GraphQL server by itself.\nIt's a library that you can use to build Routers, Gateways, or even GraphQL Server frameworks on top of it.\nWhat this means is that there's no built-in support to define \"resolvers\".\nInstead, you have to define DataSources that are used to resolve fields.\n\nA DataSource can be anything, e.g. a static value, a HTTP JSON API, a GraphQL API, a WASM Lambda, a Database etc.\nIt's up to you to implement the DataSource interface.\n\nThe simplest DataSource is the StaticDataSource.\nIt's a DataSource that returns a static value for a field.\nLet's see how to use it!\n\nYou have to attach the DataSource to one or more fields in the schema,\nand you have to provide a config and a factory for the DataSource,\nso that the planner knows how to create an execution plan for the DataSource and an \"instance\" of the DataSource.\n*/\n\nfunc ExamplePlanOperation() {\n  staticDataSource, err := plan.NewDataSourceConfiguration[staticdatasource.Configuration](\n    \"StaticDataSource\",\n    \u0026staticdatasource.Factory[staticdatasource.Configuration]{},\n    \u0026plan.DataSourceMetadata{\n      RootNodes: []plan.TypeField{\n        {\n          TypeName:   \"Query\",\n          FieldNames: []string{\"hello\"},\n        },\n      },\n    },\n    staticdatasource.Configuration{\n      Data: `{\"hello\":\"world\"}`,\n    },\n  )\n  if err != nil {\n    panic(err)\n  }\n\n  config := plan.Configuration{\n    DataSources: []plan.DataSource{\n      staticDataSource,\n    },\n    Fields: []plan.FieldConfiguration{\n      {\n        TypeName:              \"Query\", // attach this config to the Query type and the field hello\n        FieldName:             \"hello\",\n        DisableDefaultMapping: true,              // disable the default mapping for this field which only applies to GraphQL APIs\n        Path:                  []string{\"hello\"}, // returns the value of the field \"hello\" from the JSON data\n      },\n    },\n  }\n\n  input := []byte(`query O { hello }`)\n  schema := []byte(`type Query { hello: String }`)\n\n  report := \u0026operationreport.Report{}\n  operationDocument := ast.NewSmallDocument()\n  operationDocumentParser := astparser.NewParser()\n  operationDocument.Input.ResetInputBytes(input)\n  operationDocumentParser.Parse(operationDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  schemaDocument := ast.NewSmallDocument()\n  schemaParser := astparser.NewParser()\n  schemaDocument.Input.ResetInputBytes(schema)\n  schemaParser.Parse(schemaDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  operationName := \"O\"\n\n  err = asttransform.MergeDefinitionWithBaseSchema(schemaDocument)\n  if err != nil {\n    panic(err)\n  }\n\n  planner, err := plan.NewPlanner(config)\n  if err != nil {\n    panic(err)\n  }\n  executionPlan := planner.Plan(operationDocument, schemaDocument, operationName, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n  fmt.Printf(\"%+v\\n\", executionPlan) // Output: Plan...\n}\n\n/*\nAs you can see, the planner has created a plan for us.\nThis plan can now be executed by using the Resolver.\n*/\n\nfunc ExampleExecuteOperation() {\n  var preparedPlan plan.Plan\n  resolver := resolve.New(context.Background(), resolve.ResolverOptions{})\n\n  ctx := resolve.NewContext(context.Background())\n\n  switch p := preparedPlan.(type) {\n  case *plan.SynchronousResponsePlan:\n    out := \u0026bytes.Buffer{}\n    err, _ := resolver.ResolveGraphQLResponse(ctx, p.Response, nil, out)\n    if err != nil {\n      panic(err)\n    }\n    fmt.Println(out.String()) // Output: {\"data\":{\"hello\":\"world\"}}\n  case *plan.SubscriptionResponsePlan:\n    // this is a Query, so we ignore Subscriptions for now, but they are supported\n  }\n}\n\n/*\nWell done! You've now seen how to parse, print, validate, normalize, plan and execute a GraphQL document.\nYou've built a complete GraphQL API Gateway from scratch.\nThat said, this was really just the tip of the iceberg.\n\nWhen you look under the hood of graphql-go-tools, you'll notice that a lot of its functionality is built on top of the AST,\nmore specifically on top of the \"astvisitor\" package.\nIt comes with a lot of useful bells and whistles that help you to solve complex problems.\n\nYou'll notice that almost everything, from normalization to printing, planning, validation, etc.\nis built on top of the AST and the astvisitor package.\n\nLet's take a look at a basic example of how to use the astvisitor package to build higher level functionality.\nHere's a simple use case:\n\nLet's walk through the AST of a GraphQL document and extract all tuples of (TypeName, FieldName).\nThis is useful, e.g. when you want to extract information about the fields that are used in a document.\n*/\n\ntype visitor struct {\n  walker                *astvisitor.Walker\n  operation, definition *ast.Document\n  typeFields            [][]string\n}\n\nfunc (v *visitor) EnterField(ref int) {\n  // get the name of the enclosing type (Query)\n  enclosingTypeName := v.walker.EnclosingTypeDefinition.NameString(v.definition)\n  // get the name of the field (hello)\n  fieldName := v.operation.FieldNameString(ref)\n  // get the type definition of the field (String)\n  definitionRef, exists := v.walker.FieldDefinition(ref)\n  if !exists {\n    return\n  }\n  // get the name of the field type (String)\n  fieldTypeName := v.definition.FieldDefinitionTypeNameString(definitionRef)\n  v.typeFields = append(v.typeFields, []string{enclosingTypeName, fieldName, fieldTypeName})\n}\n\nfunc ExampleWalkAST() {\n  report := \u0026operationreport.Report{}\n\n  operationInput := []byte(`query O { hello }`)\n  operationParser := astparser.NewParser()\n  operationDocument := ast.NewSmallDocument()\n  operationDocument.Input.ResetInputBytes(operationInput)\n  operationParser.Parse(operationDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  schemaInput := []byte(`type Query { hello: String }`)\n  schemaParser := astparser.NewParser()\n  schemaDocument := ast.NewSmallDocument()\n  schemaDocument.Input.ResetInputBytes(schemaInput)\n  schemaParser.Parse(schemaDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n\n  err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument)\n  if err != nil {\n    panic(err)\n  }\n\n  walker := astvisitor.NewWalker(24)\n\n  vis := \u0026visitor{\n    walker:     \u0026walker,\n    operation:  operationDocument,\n    definition: schemaDocument,\n  }\n\n  walker.RegisterEnterFieldVisitor(vis)\n  walker.Walk(operationDocument, schemaDocument, report)\n  if report.HasErrors() {\n    panic(report.Error())\n  }\n  fmt.Printf(\"%+v\\n\", vis.typeFields) // Output: [[Query hello String]]\n}\n\n/*\nThis is just a very basic example of what you can do with the astvisitor package,\nbut you can see that it's very powerful and flexible.\n\nYou can register callbacks for every AST node and do whatever you want with it.\nIn addition, the walker helps you to keep track of the current position in the AST,\nand it can help you to figure out the enclosing type of a field,or the ancestors or a node.\n*/\n```\n\nI hope this tutorial gave you a good overview of what you can do with this library.\nIf you have any questions, feel free to open an issue.\nFollowing, here's a list of all the important packages in this library and what problems they solve.\n\n- ast: the GraphQL AST and all the logic to work with it.\n- astimport: import GraphQL documents from one AST into another\n- astnormalization: normalize a GraphQL document\n- astparser: parse a string into a GraphQL AST\n- astprinter: print a GraphQL AST into a string\n- asttransform: transform a GraphQL AST, e.g. merge it with a base schema\n- astvalidation: validate a GraphQL AST against a schema\n- astvisitor: walk through a GraphQL AST and execute callbacks for every node\n- engine/datasource: the DataSource interface and some implementations\n- engine/datasource/graphql_datasource: the GraphQL DataSource implementation, including support for Federation\n- engine/plan: plan the execution of a GraphQL document\n- engine/resolve: execute the plan\n- introspection: convert a GraphQL Schema into an introspection JSON document\n- lexer: turn a string containing a GraphQL document into a list of tokens\n- playground: add a GraphQL Playground to your Go HTTP server\n- subscription: implements GraphQL Subscriptions over WebSockets and SSE\n\n## Contributors\n\n- [Jens Neuse][jens-neuse-github] (Project Lead \u0026 Active Maintainer)\n  - Initial version of graphql-go-tools\n  - Currently responsible for the loader and resolver implementation\n- [Sergiy Petrunin 🇺🇦][sergiy-petrunin-github] (Active Maintainer)\n  - Helped cleaning up the API of the pipeline package\n  - Refactored the ast package into multiple files\n  - Author of the introspection converter (introspection JSON -\u003e AST)\n  - Fixed various bugs in the parser \u0026 visitor \u0026 printer\n  - Refactored and enhanced the astimport package\n  - Current maintainer of the plan package\n- [Patric Vormstein][patric-vormstein-github] (Inactive)\n  - Fixed lexer on windows\n  - Author of the graphql package to simplify the usage of the library\n  - Refactored the http package to simplify usage with http servers\n  - Author of the starwars package to enhance testing\n  - Refactor of the Subscriptions Implementation\n- [Mantas Vidutis][mantas-vidutis-github] (Inactive)\n  - Contributions to the http proxy \u0026 the Context Middleware\n- [Jonas Bergner][jonas-bergner-github] (Inactive)\n  - Contributions to the initial version of the parser, contributions to the tests\n  - Implemented Type Extension merging (deprecated)\n- [Vasyl Domanchuk][vasyl-github] (Inactive)\n  - Implemented the logic to generate a federation configuration\n  - Added federation example\n  - Added the initial version of the batching implementation\n\n[jens-neuse-github]: https://github.com/jensneuse\n[mantas-vidutis-github]: https://github.com/mvid\n[jonas-bergner-github]: https://github.com/java-jonas\n[patric-vormstein-github]: https://github.com/pvormste\n[sergiy-petrunin-github]: https://github.com/devsergiy\n[vasyl-github]: https://github.com/chedom\n\n## Contributions\n\nFeel free to file an issue in case of bugs.\nWe're open to your ideas to enhance the repository.\n\nYou are open to contribute via PR's.\nPlease open an issue to discuss your idea before implementing it so we can have a discussion.\nMake sure to comply with the linting rules.\nYou must not add untested code.\n","funding_links":[],"categories":["Go","Implementations"],"sub_categories":["JavaScript/TypeScript"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwundergraph%2Fgraphql-go-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwundergraph%2Fgraphql-go-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwundergraph%2Fgraphql-go-tools/lists"}