Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec edits to reduce "query ambiguity" #777

Merged
merged 2 commits into from
Apr 9, 2021

Conversation

benjie
Copy link
Member

@benjie benjie commented Sep 14, 2020

This PR addresses the "query ambiguity" issue raised in #715 and discussed in the May 2020 GraphQL Working Group.

I went through every usage of the word query, queries and queried in the spec and attempted to discern the different terminology we have going on. I've come up with the following definitions which are broadly in line with the terminology the spec already uses in places.

What follows are notes I took whilst doing this work, which also constitutes the beginnings of a glossary. This glossary is probably sufficient for WG members who already understand these concepts, but I'll need to tidy them up and define them more concretely if we want to add them as a glossary to the spec itself. (Also need to populate it with non-query terms.) I think if we do decide to add a glossary we should do that as a separate PR.

Glossary

When usage of these terms may cause ambiguity* the normally optional
parenthesized "(GraphQL)" should be included for clarity.

* example of an ambiguous phrase: "sending a request to a server" may refer to
an HTTP request, network request, or a GraphQL request.

(GraphQL) operation

Definition: an action you wish GraphQL to perform, for example retrieving
data, mutating data or state, or subscribing to events.

Examples:

A query operation should not mutate data or state, for that a mutation
operation should be used.

Used in the GraphQL spec:

Let {operation} be the result of {GetOperation(document, operationName)}.

(GraphQL) operation type

Definition: a type of operation supported by GraphQL - "query", "mutation", or
"subscription".

Examples:

GraphQL currently supports 3 operation types: query, mutation and
subscription.

Not to be confused with (GraphQL) root operation type.

Used in the GraphQL spec:

Schema extensions are used to represent a schema which has been extended from
an original schema. For example, this might be used by a GraphQL service which
adds additional operation types, or additional directives to an existing schema.

(GraphQL) query operation

A GraphQL operation of type query.

Used in the GraphQL spec:

If {operation} is a query operation: ...

(GraphQL) mutation operation

A GraphQL operation of type mutation.

Used in the GraphQL spec:

Otherwise if {operation} is a mutation operation: ...

(GraphQL) subscription operation

A GraphQL operation of type subscription.

Used in the GraphQL spec:

Otherwise if {operation} is a subscription operation: ...

(GraphQL) root operation type

The GraphQL object type associated with a given GraphQL operation type within
the schema.

Used in the GraphQL spec:

A schema defines the initial root operation type for each kind of operation it
supports: query, mutation, and subscription; this determines the place in the
type system where those operations begin.

(GraphQL) document

Definition: the textual representation (using GraphQL query language) of an
operation (or operations) you wish to perform, including selection sets and
fragments as appropriate.

Examples:

Once a GraphQL document is written, it should always mean the same
thing and return the same shaped result.

For example, this document will receive the name of the user
with id 4 from the Facebook implementation of GraphQL.

Clients use the GraphQL query language to make requests to a GraphQL service.
We refer to these request sources as GraphQL documents. A document
may contain operations (queries, mutations, and subscriptions) as
well as fragments, a common unit of composition allowing for data
requirement reuse
.

Inspired by.

Alternatives considered:

  • GraphQL operation document (could also be expected to include IDL)
  • Request document (too confusing with "request")

(GraphQL) operation variables

Definition: variables declared within an operation.

Previously "query variables".

Example: $devicePicSize is an operation variable in the following operation:

query getZuckProfile($devicePicSize: Int) {
  user(id: 4) {
    id
    name
    profilePic(size: $devicePicSize)
  }
}

Why not "request variables"? The variables are declared in the operation and
there doesn't seem to be a need to push the definition up to request level.

(GraphQL) request

Definition: the full description of what you wish GraphQL to execute,
including the GraphQL schema, document, variables, operation name and initial
value.

When using GraphQL over HTTP, it's common to encode the GraphQL request as
JSON.

Used in the GraphQL spec:

ExecuteRequest(schema, document, operationName, variableValues, initialValue):

(GraphQL) request error

Definition: an error which occurs during validating a GraphQL request
(including coercing the variables) resulting in the entire GraphQL request
being aborted.

Previously: consistently "query error" throughout the spec.

Why not "query error"? It also occurs for mutations, subscriptions, and invalid
documents.

Why not "operation error"? It can occur when operationName is not specified,
and thus the operation is indeterminate. Further it may result from invalid
variables which are a GraphQL request concern, not a GraphQL operation concern.

Unmodified terms

The verb "to query" is left in may places, as is the term "query language". A few of these are noted below:

GraphQL is a query language designed to build client applications...

A GraphQL server's type system must be queryable by the GraphQL language itself...

It describes the language and its grammar, the type system and the introspection system used to query it...

Questionable terms

query reuse

"query reuse" w.r.t fragments. "query" seems like the wrong term here (because
of how overloaded/vague it is) but I can't come up with a succinct alternative.
Best I've come up with is "data requirement reuse," but I'm not super happy
with it.

queried

By default, the key in the response object will use the field name
queried. However, you can define a different name by specifying an alias.

querying

Inline Fragments can be used directly within a selection to condition upon a
type condition when querying against an interface or union.

Fragments must specify the type they apply to. In this example, friendFields
can be used in the context of querying a User.

Can be replaced with 'selecting' / 'selecting fields from', using 'select' as
in 'selection set'.

query of

A query of an object value must select at least one field.

request

In many cases 'request' can be replaced with 'fetch' to avoid ambiguity with
'GraphQL request'.

If providing JSON for the variables' values, we could run this operation and
request profilePic of size 60 width:

query root object type

Also mutation/subscription root object type and simply "query root type". These
have the same meaning as query "root operation type", but "root object type" is
more explicit that the root operation type is an object type. We should pick
between them and stick to that throughout.

The type system, as described in the "Type System" section of the spec, must
provide a query root object type. If mutations or subscriptions are supported,
it must also provide a mutation or subscription root object type, respectively.

query execution

Replaced with "request execution" due to the function being called ExecuteRequest

Interesting terms

Fetch

There are three types of operations that GraphQL models:

  • query - a read-only fetch.
  • mutation - a write followed by a fetch.
  • subscription - a long-lived request that fetches data in response to source
    events.

Response key

A field's response key is its alias if an alias is provided, and it is
otherwise the field's name.

Ethos

Rather than being conservative with edits and leaving ambiguity I was quite heavy

Status

This is not ready for merging, it's only a first edit and there's likely inconsistencies where the final rules I applied weren't reapplied to earlier edits. Mostly this is a discovery exercise.

Next steps

I'll add this to the next GraphQL WG. I have broadly the following questions:

  1. in general are we happy with my chosen terms?
  2. "root operation type", "root object type" and "root type" term - need to pick one.
  3. Is there a better term than "querying" to use when querying a type, e.g. relating to field validity, fragment spreads, etc. Perhaps "selecting" or a derivative, inspired by "selection set"?

@eapache
Copy link
Member

eapache commented Sep 14, 2020

Thank you for tackling this! 🙏

  • The "Questionable Terms" section appears twice in your explanation, I think just copy-pasta?
  • For "query reuse", perhaps "selection reuse"?

@benjie
Copy link
Member Author

benjie commented Sep 14, 2020

  1. Thanks; fixed!
  2. maybe 👍

Also I accidentally included an earlier decision which was to use "operation document" which I've since rethought and gone with simply "document"; so have edited that into the description too.

@sungam3r
Copy link
Contributor

(GraphQL) request
Definition: the full description of what you wish GraphQL to execute,
including the GraphQL schema, document, variables, operation name and initial
value.

Why do you include schema and initial value in graphql request? This is purely server side implementation concept.

@benjie
Copy link
Member Author

benjie commented Sep 14, 2020

@sungam3r good question. The answer’s straight-forward: because that’s how the GraphQL spec defines it; this isn’t definitions for accessing a GraphQL schema over HTTP (for example), a request in schema spec terms relates to the items listed:

https://spec.graphql.org/June2018/#ExecuteRequest()

@sungam3r
Copy link
Contributor

GraphQL spec defines implementation part of executing request with some additional server-side context - schema and initialValue. In this paragraph, I do not see that the specification describes the content of the request. It says

To execute a request, the executor must have

Executor can have any number of things to execute the request, not related to the request itself.

this isn’t definitions for accessing a GraphQL schema over HTTP

It always seemed to me that the request should be defined as a (document, operationName, variables) for an arbitrary transport. To be honest, I find it strange if its definition would include something else.

@benjie
Copy link
Member Author

benjie commented Sep 15, 2020

I'm not sure; all requests indicate a schema - sometimes by explicitly having a schema instance, sometimes by referencing the schema via URL endpoint. You can't validate a GraphQL request without knowing to which GraphQL schema it applies. (Not true for the initial value, sure.)

But anyway; we're currently discussing something that's not actually part of the changes proposed by this PR - you're currently commenting on my notes on the terms that I added so that we as GraphQL Working Group members would know what's being referenced. An actual RFC to add a glossary would be a separate PR which can and should have this kind of discussion on this and many other topics.

@sungam3r
Copy link
Contributor

Ok

Copy link

@vwkd vwkd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the clarifications very much! 👍

I saw that you introduced the term “query operation” for an operation of type “query”, but didn’t use it consistently in the examples. To be consistent, the examples should then also be “query operations” to distinguish them from mutation / subscription operations. Of course the alternative would be to change “query operation” to “operation” in the other places instead.

As another thought, maybe for the glossary, now that “query” has been de-overloaded. What does the naked term “query” actually mean and when is it appropriate to use it?

@@ -431,7 +432,7 @@ Many arguments can exist for a given field:
Arguments may be provided in any syntactic order and maintain identical
semantic meaning.

These two queries are semantically identical:
These two operations are semantically identical:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operations”, to be consistent.

@@ -593,7 +594,7 @@ fragment standardProfilePic on User {
}
```

The queries `noFragments`, `withFragments`, and `withNestedFragments` all
The operations `noFragments`, `withFragments`, and `withNestedFragments` all
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operations”, to be consistent.

spec/Section 2 -- Language.md Outdated Show resolved Hide resolved
If a document contains only one query operation, and that query defines no
variables and contains no directives, that operation may be represented in a
short-hand form which omits the query keyword and query name.
If a document contains only one operation and the operation is query operation,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“a query operation”

@@ -1045,7 +1046,7 @@ literal representation of input objects as "object literals."
Input object fields may be provided in any syntactic order and maintain
identical semantic meaning.

These two queries are semantically identical:
These two operations are semantically identical:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operations”, to be consistent.

@@ -16,7 +16,7 @@ type User {
}
```

The query
The operation
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operation”, to be consistent.

@@ -1587,7 +1587,7 @@ extend type Query {
}
```

The following queries are valid:
The following operations are valid:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operations”, to be consistent.

@@ -1607,7 +1607,7 @@ query TakesListOfBooleanBang($booleans: [Boolean!]) {
}
```

The following queries are invalid:
The following operations are invalid:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operations”, to be consistent.

@@ -687,7 +687,7 @@ When more than one field of the same name is executed in parallel, their
selection sets are merged together when completing the value in order to
continue execution of the sub-selection sets.

An example query illustrating parallel fields with the same name with
An example operation illustrating parallel fields with the same name with
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operation”, to be consistent.


For example, if fetching one of the friends' names fails in the following
query:
operation:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Query operation”, to be consistent.

@benjie
Copy link
Member Author

benjie commented Nov 4, 2020

@vwkd Thanks for your review. There's a reason that I used operation over query operation in those cases: though they are query operations, the text applies for all types of operations, so the fact it's a query operation is incidental - part of the intention was to broaden the meaning that the text implies to make it clear that the text does not only apply to queries even though that's generally what we use in the examples.

@vwkd
Copy link

vwkd commented Nov 4, 2020

@benjie I intendedly left out the places where an operation was defined or mentioned in general, and commented only where there was a concrete example showing a query operation. I don't think explicitly mentioning the type of the operation in the example is implying that whatever was defined before it couldn't be used for operations of other types. On the contrary, I think being explicit about the type of operation used in the example helps clear confusion, just as mentioning if some shorthand is used in an example would too, but that's probably better saved for another time.

@vwkd
Copy link

vwkd commented Nov 7, 2020

Is it only me, or does SchemaDefinition not have a Description anymore? I can't seem to find references in the code that indicate any changes regarding this, but on my local build the Description in the SchemaDefinition is gone. Weird, since I can repeat this with a fresh clone and running npm i && npm run build.

@mcohen75
Copy link

Would it make sense to formalize the glossary you've created in the description, even in just for "internal" use? It would seem useful for those creating documentation as part of formal working group activities. I think members of the community would also benefit from something like this as it would help to further align usage of these terms.

@benjie
Copy link
Member Author

benjie commented Feb 22, 2021

Absolutely; it’s one of my action items to push that forward (it’s just currently queued up behind a few higher priority items).

@@ -68,7 +68,7 @@ schema {
}

"""
Root type for all your queries
Root type for all your query operations

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a valid use of the term query operation? According to the spec and the glossary I believe a query operation is an OperationDefinition with the type query.

If this is not a valid use of the term, what term should be used to describe these fields on the Query type?

Copy link

@mcohen75 mcohen75 Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recently had a conversation with a colleague here at Indeed and used (misused?) the term query operation in a similar context.

I said something like "when a response includes data for multiple query operations...". He pointed me to the spec and pointed out that only one query operation can be executed.

What I was trying to communicate was that it's possible to select multiple fields on the top level Query type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query is the root type for all query operations; you issue a selection set against the Query root type, this selection set may select more than one field like most selection sets (the exception being the selection set at the root of the subscription operation).

Here's a (single) query operation issuing a selection set against a root Query type:

query {
  __typename
  myField
  myOtherField { id }
}

So yes, I believe the usage here is correct.

According to the spec and the glossary I believe a query operation is an OperationDefinition with the type query.

Correct.

He pointed me to the spec and pointed out that only one query operation can be executed.

He's correct 👍

What term should be used to describe these fields on the Query type?

You could call them "Query fields" I guess; just like fields on the User type would by "User fields." I'm not sure we have an established name for them, the root level fields on the mutation operation would generally be called "mutation fields" and for subscription "subscription fields" so I think "query fields" would make sense, but is potentially ambiguous.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW the historical official name for these were "root fields" - when we generalized roots to be no different from other types, we dropped an official name. I've also heard "top level fields" which makes sense to me, but "Query fields" or "Fields on the Query type" both would be perfectly clear

@leebyron leebyron added the ✏️ Editorial PR is non-normative or does not influence implementation label Apr 6, 2021
@leebyron leebyron added this to the May2021 milestone Apr 6, 2021
@leebyron leebyron force-pushed the query-ambiguity-edits branch 4 times, most recently from 5912463 to e114dae Compare April 7, 2021 06:12
@benjie
Copy link
Member Author

benjie commented Apr 7, 2021

I'll review this in the next few hours 👍

Copy link
Member Author

@benjie benjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally good improvements to the text; I've called out a few things that I don't fully agree with and some minor issues which I will fix shortly.

spec/Section 1 -- Overview.md Outdated Show resolved Hide resolved
spec/Section 1 -- Overview.md Outdated Show resolved Hide resolved
spec/Section 1 -- Overview.md Outdated Show resolved Hide resolved
spec/Section 2 -- Language.md Outdated Show resolved Hide resolved
spec/Section 3 -- Type System.md Outdated Show resolved Hide resolved
spec/Section 3 -- Type System.md Outdated Show resolved Hide resolved
spec/Section 3 -- Type System.md Outdated Show resolved Hide resolved
spec/Section 4 -- Introspection.md Outdated Show resolved Hide resolved
spec/Section 4 -- Introspection.md Outdated Show resolved Hide resolved
@benjie
Copy link
Member Author

benjie commented Apr 7, 2021

I've added 4 more tiny commits which are justified in the resolved comments above (including references to the commit). There's a couple other changes that I think may warrant exploration (these are still open above); but I'm happy with this being merged as is.

@leebyron leebyron force-pushed the query-ambiguity-edits branch from 324a6bf to 07aec6e Compare April 7, 2021 18:43
leebyron added a commit that referenced this pull request Apr 7, 2021
Factored out of #777 - this rephrases input object introspection to be more accurate.
leebyron added a commit that referenced this pull request Apr 7, 2021
Clarify use of root types and improve formatting. Factored out of #777
leebyron added a commit that referenced this pull request Apr 7, 2021
Clarify the rules for using query shorthand. Factored out of #777
leebyron added a commit that referenced this pull request Apr 7, 2021
Factored out of #777. Clarifies when type definition & extension can and cannot be included in executable documents

To do this more clearly, this introduces a number of new grammar rules. This does not change the actual behavior of a parser (all existing docs are parsed equivalently, no new docs are legal). However instead of using language that manipulates existing rules this can just reference those already restricted.

Hopefully this actually is useful for implementations which seek to offer clear subsets for each use case.
@leebyron leebyron force-pushed the query-ambiguity-edits branch 3 times, most recently from c3a9e01 to 8278927 Compare April 7, 2021 22:18
leebyron added a commit that referenced this pull request Apr 7, 2021
Factored out of #777. This clarifies the relationship between field aliases and response keys.
leebyron added a commit that referenced this pull request Apr 7, 2021
Factored out of #777. This clarifies the relationship between field aliases and response keys.
leebyron added a commit that referenced this pull request Apr 7, 2021
Factored out of #777. This clarifies the relationship between field aliases and response keys.
@leebyron leebyron force-pushed the query-ambiguity-edits branch from 8278927 to 7bd26f7 Compare April 7, 2021 22:30
leebyron added a commit that referenced this pull request Apr 8, 2021
Derived from #777

Renames "field" to "meta-field" consistently. Adds "with the single exception of the subscription root
operation type". Clarifies some language.
@benjie
Copy link
Member Author

benjie commented Apr 8, 2021

The glossary entries in this PR description have been extracted to #846 (and they've also been improved).

leebyron added a commit that referenced this pull request Apr 9, 2021
Factored out of #777. Clarifies when type definition & extension can and cannot be included in executable documents

To do this more clearly, this introduces a number of new grammar rules. This does not change the actual behavior of a parser (all existing docs are parsed equivalently, no new docs are legal). However instead of using language that manipulates existing rules this can just reference those already restricted.

Hopefully this actually is useful for implementations which seek to offer clear subsets for each use case.
@leebyron leebyron force-pushed the query-ambiguity-edits branch 2 times, most recently from 623f655 to faf8683 Compare April 9, 2021 05:10
leebyron added a commit that referenced this pull request Apr 9, 2021
* Editorial: Clarify meta-fields in introspection

Derived from #777

Renames "field" to "meta-field" consistently. Adds "with the single exception of the subscription root
operation type". Clarifies some language.

* Update spec/Section 4 -- Introspection.md

Co-authored-by: Benjie Gillam <benjie@jemjie.com>

* Update spec/Section 4 -- Introspection.md

Co-authored-by: Benjie Gillam <benjie@jemjie.com>

* Update spec/Section 4 -- Introspection.md

Co-authored-by: Benjie Gillam <benjie@jemjie.com>

* wrap

Co-authored-by: Benjie Gillam <benjie@jemjie.com>
benjie and others added 2 commits April 8, 2021 22:15
I went through this editorial in two passes. One where I tuned the usage of "operation", "request", and "selection set". I hopefully made these spots slightly clearer, but I'm open to feedback. Second pass was more freeform prose edits in cases where I thought the intended ideas could have been clearer and avoid the query ambiguity in the first place.
@leebyron leebyron force-pushed the query-ambiguity-edits branch from faf8683 to e36b4b1 Compare April 9, 2021 05:16
@leebyron leebyron merged commit 9ec15e3 into graphql:main Apr 9, 2021
@benjie benjie deleted the query-ambiguity-edits branch April 13, 2021 18:53
rstoyanchev added a commit to spring-projects/spring-graphql that referenced this pull request May 12, 2021
Following revisions in the spec
graphql/graphql-spec#777, this commit applies
similar changes to type and method names where feasible.

The chief exception for now is the use of "query" for request input
since that is what it is called in the JSON for GraphQL over HTTP.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✏️ Editorial PR is non-normative or does not influence implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants