From 0463d68f106eebc3af673e901c8faa4f1109b402 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Tue, 5 May 2026 12:53:46 -0500 Subject: [PATCH 1/5] Add Fully Qualified Operation Names (FQON) GAP Introduces GAP-0 proposing a human-readable, unambiguous identifier for GraphQL operations, useful as lookup keys in static configuration files without coupling to document IDs. Co-Authored-By: Claude Opus 4.7 --- gaps/GAP-0/DRAFT.md | 124 ++++++++++++++++++++++++++++++++++++++++ gaps/GAP-0/README.md | 96 +++++++++++++++++++++++++++++++ gaps/GAP-0/metadata.yml | 9 +++ 3 files changed, 229 insertions(+) create mode 100644 gaps/GAP-0/DRAFT.md create mode 100644 gaps/GAP-0/README.md create mode 100644 gaps/GAP-0/metadata.yml diff --git a/gaps/GAP-0/DRAFT.md b/gaps/GAP-0/DRAFT.md new file mode 100644 index 0000000..fba95ff --- /dev/null +++ b/gaps/GAP-0/DRAFT.md @@ -0,0 +1,124 @@ +# Fully Qualified Operation Name (FQON) + +**Introduction** + +:: This document specifies _Fully Qualified Operation Name_ (FQON), a +human‑readable, unambiguous identifier for GraphQL operations. + +The primary motivation is to define a "lookup key" that may be used in static +configuration files (e.g. for alerting rules per operation) which correctly +targets operations, but without having to update the configuration each time a +_document id_ changes. + +This specification assumes usage of +[trusted documents](https://graphql.org/learn/security/#trusted-documents) and +[Git version control](https://git-scm.com/). + +**Example** + +Given the following operation defined in a Git repository named `yelp/frontend`, +and in a package named `styleguide`: + +```graphql example +query GetHeaderData { + ... +} +``` + +The _FQON_ for this operation may be defined as: + +```example +GetHeaderData:styleguide:yelp/frontend:1 +``` + +When defining alerting rules for this operation, we can target all versions of +this operation by omitting the _version_ suffix: + +```example +GetHeaderData:styleguide:yelp/frontend +``` + +**Motivation** + +We may identify operations using either: + +- The _operation name_ (e.g. {"GetHeaderData"}) +- The _document id_ produced by hashing the operation body (e.g. {"605fad0ee0a88..."}) + +Because GraphQL operation names are not be guaranteed to be globally unique, +they cannot reliably identify an operation across multiple platforms or +deployment versions. On the other hand, a _document id_ is guaranteed to be +unique but is inconvenient for humans to read and maintain. + +Note: See for additional context. + +**Use Cases** + +- A _FQON_ may be printed instead of the operation name in application logs. + This encourages correct behavior when humans use this identifier to look up + the operation body in the document registry or codebase. +- A partial _FQON_ may be used instead of a _document id_ as lookup keys in + static configuration files (e.g. alerting rules) in order to avoid duplication + and extra steps when an operation is updated (and thus, its _document id_). + +## Definition + +FullyQualifiedOperationName :: OperationName : Project? : RepoFullName : Version + +OperationName +: The _Name_ of the operation as declared on the _OperationDefinition_ node. + +Project +: The identifier for the package or directory containing the operation. +: This is defined only for operations that live in a monorepo. + +RepoFullName +: The full name of the Git repository (in the format of {"owner/repo"}). + +Version +: A positive integer that increments each time the document body changes. +: The tuple of _OperationName_, _Project_ and _RepoFullName_ identifies a +document; the _Version_ part distinguishes its revisions. +: The _trusted document_ registry or other persistence layer must calculate or +store version numbers, starting at {1} and increasing monotonically. + +**Examples** + +A _Fully Qualified Operation Name_ with all parts: + +```example +GetHeaderData:styleguide:yelp/frontend:1 +``` + +A _Fully Qualified Operation Name_ which omits `Project` (i.e. +`petstore/website` is _not_ a monorepo, and has no concept of "projects"): + +```example +AllPets::petstore/website:1 +``` + +## Partial Matches + +Any _FQON_ part may be omitted to perform a partial match. + +With the exception of omitting _Project_, partial matches must also omit the +`:Version` suffix. + +The primary use case of this specification is to omit `:Version` for use as +lookup keys in static configuration files, as a way to target to all versions +of an operation. + +**Examples** + +| Pattern | Matches | +| --------------------------- | ------------------------------------------------------------------------------------------------------- | +| `GetFoo::` | All operations named {"GetFoo"} | +| `::bazcorp/qux` | All operations inside the {"bazcorp/qux"} Git repository | +| `GetFoo:barpkg:bazcorp/qux` | All operations named {"GetFoo"} inside the {"barpkg"} package inside the {"bazcorp/qux"} Git repository | + +## Security Considerations + +It is recommended to avoid exposing FQONs in client code to avoid leaking +potentially sensitive internal repository names or project/directory names. + +Clients should still send only the _document id_ over the wire, which is opaque. diff --git a/gaps/GAP-0/README.md b/gaps/GAP-0/README.md new file mode 100644 index 0000000..ce31b73 --- /dev/null +++ b/gaps/GAP-0/README.md @@ -0,0 +1,96 @@ +# GAP-0: Fully Qualified Operation Name (FQON) + +Fully Qualified Operation Names (FQONs) are an alternate way to identify and +refer to GraphQL operations that provide both human readability and uniqueness +guarantees. + +The primary motivation is to define a "lookup key" that may be used in static +configuration files (e.g. for alerting rules per operation) which correctly +targets operations, but without having to update the configuration each time a +_document id_ changes. + +## The problem + +When using +[trusted documents](https://graphql.org/learn/security/#trusted-documents), we +may identify queries in two different ways: + +1. The "query name" (e.g. `GetConsumerHeaderData`) +2. The "document id" (e.g. `605fad0ee0a88...`) + +_Query names are not guaranteed to be unique_. + +When using operation names, a developer might see `"GetUserInfo"` in service log, +copy and paste that string, use `git grep` and find it in the codebase -- only +to later discover it's the _wrong_ `GetUserInfo` query! + +- Query names are only guaranteed to be unique with additional tooling. +- Even if tooling guarantees uniqueness within a repository, query names could + be reused in a _different_ repository — e.g. Web/iOS/Android code might + feasibly live in different Git repositories, and reuse operation names for + similar features. +- Additionally, servers may receive traffic for different versions of + the same query in order to support old mobile application installs - which + would share the same operation name. + +Document IDs are unambiguous and may be used to solve this problem. However, +document IDs are not human friendly since they don't carry any semantic meaning, +which encourages developers to use document names in instead - which leads the +footgun outlined above. + +Additionally, by definition, document IDs change each time the operation is +updated. If we use document IDs as lookup keys in an alerting configuration +file, this must be updated each time a new version of the query is published. +This creates duplication and a maintenance burden. + +## Solution + +A _Fully Qualified Operation Name_ (FQON) is a human readable string that can +provide the same guarantees of uniqueness as document IDs, but and can be used +partially to omit the version number in such cases as alert config files. + +**Example**: + +```yaml +# alert_thresholds.yaml +operations: + - fqon: GetFoo::bazcorp/qux + error_ratio: 0.3 + owner: myteam@example.com + - fqon: BarStuff::bazcorp/qux + error_ratio: 0.4 + alert: myteam@example.com +``` + +## Definition + +The format is: + +``` +name:project:repo:version +``` + +This is enough information to unambiguously identify the exact document +(assuming that client tooling guarantees no duplicate operation names per +project). + +**Example**: + +``` +GetConsumerHeaderData:yelp-styleguide:yelp/frontend:3 +``` + +The right hand side components of the FQON can be omitted for a partial match: + +**Example**: + +``` +GetConsumerHeaderData:yelp-styleguide:yelp/frontend +``` + +^ this will match any version of the "same" query, and is recommended for use +as lookup keys in static configuration files + +### ARN Syntax + +`:` as a separator is inspired by [ARNs](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html) diff --git a/gaps/GAP-0/metadata.yml b/gaps/GAP-0/metadata.yml new file mode 100644 index 0000000..4144565 --- /dev/null +++ b/gaps/GAP-0/metadata.yml @@ -0,0 +1,9 @@ +id: 0 +title: "Fully Qualified Operation Names" +status: proposal +authors: + - name: "Mark Larah" + email: "markl@yelp.com" + githubUsername: "@magicmark" +sponsor: "@magicmark" +discussion: "https://github.com/graphql/graphql-spec/issues/1185" From ed185f6c3faa4dd770f1553c6baf19cb2b55c2d9 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Tue, 5 May 2026 13:00:23 -0500 Subject: [PATCH 2/5] Update GAP metadata with new ID and discussion link --- gaps/GAP-0/metadata.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gaps/GAP-0/metadata.yml b/gaps/GAP-0/metadata.yml index 4144565..65a9d4f 100644 --- a/gaps/GAP-0/metadata.yml +++ b/gaps/GAP-0/metadata.yml @@ -1,4 +1,4 @@ -id: 0 +id: 7 title: "Fully Qualified Operation Names" status: proposal authors: @@ -6,4 +6,4 @@ authors: email: "markl@yelp.com" githubUsername: "@magicmark" sponsor: "@magicmark" -discussion: "https://github.com/graphql/graphql-spec/issues/1185" +discussion: "https://github.com/graphql/gaps/pull/7" From dac90f5b8189cb450aefda5ebaf2c65e33e34bb9 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Tue, 5 May 2026 13:01:33 -0500 Subject: [PATCH 3/5] Update README.md --- gaps/GAP-0/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gaps/GAP-0/README.md b/gaps/GAP-0/README.md index ce31b73..f09d775 100644 --- a/gaps/GAP-0/README.md +++ b/gaps/GAP-0/README.md @@ -1,4 +1,4 @@ -# GAP-0: Fully Qualified Operation Name (FQON) +# GAP-7: Fully Qualified Operation Name (FQON) Fully Qualified Operation Names (FQONs) are an alternate way to identify and refer to GraphQL operations that provide both human readability and uniqueness @@ -13,12 +13,12 @@ _document id_ changes. When using [trusted documents](https://graphql.org/learn/security/#trusted-documents), we -may identify queries in two different ways: +may identify operations in two different ways: -1. The "query name" (e.g. `GetConsumerHeaderData`) +1. The "operation name" (e.g. `GetConsumerHeaderData`) 2. The "document id" (e.g. `605fad0ee0a88...`) -_Query names are not guaranteed to be unique_. +_Operation names are not guaranteed to be unique_. When using operation names, a developer might see `"GetUserInfo"` in service log, copy and paste that string, use `git grep` and find it in the codebase -- only From fa447d65086d6dc22a350fc3eebcfc4192ccee07 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Thu, 7 May 2026 15:24:08 -0500 Subject: [PATCH 4/5] Add summary to metadata for GAP-0 Added a summary for the Fully Qualified Operation Names proposal. --- gaps/GAP-0/metadata.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gaps/GAP-0/metadata.yml b/gaps/GAP-0/metadata.yml index 65a9d4f..73b3460 100644 --- a/gaps/GAP-0/metadata.yml +++ b/gaps/GAP-0/metadata.yml @@ -1,5 +1,9 @@ id: 7 title: "Fully Qualified Operation Names" +summary: > + A human-readable, unambiguous identifier for GraphQL operations. May be used + as lookup keys in static configuration files as an alternative to persisted + document IDs. status: proposal authors: - name: "Mark Larah" From a1e6ed7ae079faa91cd635b6d21adaa6ec979b5b Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Thu, 7 May 2026 15:25:49 -0500 Subject: [PATCH 5/5] Rename GAP-0 to GAP-7 Co-Authored-By: Claude Opus 4.7 --- gaps/{GAP-0 => GAP-7}/DRAFT.md | 0 gaps/{GAP-0 => GAP-7}/README.md | 0 gaps/{GAP-0 => GAP-7}/metadata.yml | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename gaps/{GAP-0 => GAP-7}/DRAFT.md (100%) rename gaps/{GAP-0 => GAP-7}/README.md (100%) rename gaps/{GAP-0 => GAP-7}/metadata.yml (100%) diff --git a/gaps/GAP-0/DRAFT.md b/gaps/GAP-7/DRAFT.md similarity index 100% rename from gaps/GAP-0/DRAFT.md rename to gaps/GAP-7/DRAFT.md diff --git a/gaps/GAP-0/README.md b/gaps/GAP-7/README.md similarity index 100% rename from gaps/GAP-0/README.md rename to gaps/GAP-7/README.md diff --git a/gaps/GAP-0/metadata.yml b/gaps/GAP-7/metadata.yml similarity index 100% rename from gaps/GAP-0/metadata.yml rename to gaps/GAP-7/metadata.yml