amaster507
(Anthony Master)
November 9, 2020, 8:35am
1
I just stumbled upon this comment from graphql spec issue:
opened 01:55PM - 06 Jul 15 UTC
closed 07:02PM - 06 Jul 15 UTC
If we have a simple query, with only a SelectionSet:
```
{
hero {
n… ame
}
}
```
which is the same as
```
query HeroNameQuery {
hero {
name
}
}
```
The tests in `graphql.js` show this expected answer:
```
{
data: {
hero: {
name: 'R2-D2'
}
}
}
```
I know we can have many root in one query:
```
query FetchLukeAndLeiaAliased {
luke: human(id: "1000") {
name
}
leia: human(id: "1003") {
name
}
}
```
Resulting in this answer:
```
{
data: {
luke: {
name: 'Luke Skywalker'
},
leia: {
name: 'Leia Organa'
}
}
}
```
But, and it's my main concern, what if we have more that one operation in one query, which seems to be valid in the specifications (examples in http://facebook.github.io/graphql/#sec-All-Variable-Uses-Defined and http://facebook.github.io/graphql/#sec-All-Variables-Used).
For example what is the expected answer for this graphql query (dumb query just for the example):
```
query LukeAndLeiaNames {
luke: human(id: "1000") {
name
}
leia: human(id: "1003") {
name
}
}
query LukeAndLeiaHomePlanet {
luke: human(id: "1000") {
homePlanet
}
leia: human(id: "1003") {
homePlanet
}
}
```
I currently have no idea, except that there should be one more level between `data` and a query result using the name of the operation (which must be unique in the document, as said in the specification).
Or each query have its own "object" response, with `data`, `errors`... But in this case how are they "encapsulated"? In a main object with the operation names used as keys ? I could not find anything about this in the specification or the graphql.js tests.
Thanks for your answer, I'm currently writing a python graphql server and it will help me to know that ;)
What really peaked my interest was:
Q: what’s the point of having a document that can contains many operations
A: 3. It’s possible to write a “batch” API for GraphQL, where you use the results from one query as the parameters to another. We’re still working out the exact details there, but if you do that, it’s useful to specify multiple queries in a single document; you’d specify which one you wanted to run at the start and the relationships between them.
Are these the three GraphQL spec blockers from having upserts in GraphQL?
opened 10:46PM - 24 Sep 18 UTC
👻 Needs Champion
💭 Strawman (RFC 0)
*This is a restricted version of #375.*
[I have this giant thing I was lookin… g at doing with GH's GraphQL API](https://platform.github.community/t/differentiating-issues-from-prs/7322), but I ran into a stumbling block: I would need to issue a single request for each set of values rather than just reusing the query and plugging each variable in appropriately.
Instead, could we allow something like this: `{"query": "...", "variables": [...]}`, returning an array of `"data"` results rather than a single `"data"` object? Instead of `"variables"` being a single object, it's specified as an array of objects, where each entry is itself a standard variables object. This doesn't go as far as enabling variable dependencies like in #375, but it does allow a broad degree of batching that can be (and already is) optimized to death by database engines and other querying engines.
Server-side, this could be merged into a single tree with the parameters as array views at each position. This enables a broad array of potential optimizations without much cost.
opened 11:26PM - 08 Nov 17 UTC
👻 Needs Champion
💭 Strawman (RFC 0)
# RFC exporting variables between queries
This RFC calls for the ability to "… export" variables from one query into another.
This allows a single server call to be made and outputs from one query to be fed into
others as variables.
So given:
query A {
hero
{
id @export(as:"droidId")
name
friends @export(as:"r2d2Friends")
{
name @export(as:"friendNames")
}
}
}
query B($droidId : String!) {
droid (id : $droidId ) {
name
}
}
Output values from operation A would be exported as the variables named "droidId", "r2d2Friends", and "friendNames"
The operation B would be detected to be dependent on operation A and would be executed after operation A completes. It would receive the
value of "droidId" as a variable from operation A
# Multiple operation support
This RFC is dependent on https://github.com/facebook/graphql/issues/375, that is the ability to execute multiple operations in one server interaction
# Variable arity
There are design questions around variable arity. In the example above the "droidId" exported variable can be thought of as a singleton value because the surrounding types are not lists types.
Where as "r2d2Friends" can be thought of as a list value because the surrounding types are list values and hence multiple exported variable values are possible.
One can imagine in certain cases some one might want map like semantics so that "the first / last" value of a list is considered a singleton value.
Naming could be used to indicate behaviour say, for example where plural export names imply a list while singlar variable names imply a singleton value. eg: "droidId" would always be considered a singleton value where as "friendNames" would always be considered a list value.
This is a great discussion point we think.
# Consumer Supplied Variable Values
If the consumer caller supplies their own variable values, these will be passed to each operation. The exported variables will be placed into the variables map and will overwrite any existing variables with the same name key.
# Exported Variable Value Validation
Validation of the variable values would follow the same rules as consumer supplied variable values.
Validation errors would be placed on each operation execution result
# Current implementations
Sangria has this capability today https://sangria-graphql.org/learn/#batch-executor and graphql-java has a PR exploring the idea https://github.com/graphql-java/graphql-java/pull/808
These are based on the ideas presented in a Facebook presentation about capabilities used within Facebook today.
We would love to see the Facebook learnings represented back out to the greater graphql community.
opened 10:09PM - 06 Nov 17 UTC
👻 Needs Champion
💭 Strawman (RFC 0)
# RFC - Executing multiple operations in a query
Today you can define multipl… e operations in the one query document but the specification states you can only execute one of them at a time. So given :
query A {
hero
{
id
name
friends
{
name
}
}
}
query
droid (id : $droidId ) {
name
}
}
You must indicate which operation to run. See http://facebook.github.io/graphql/October2016/#sec-Executing-Requests
This RFC proposes that we add the ability to run multiple operations at the one time.
# Naming the operation
We propose that a list of operations be able to be given to the execution
ExecuteRequest(schema, document, operationNames, variableValues, initialValue)
* Let operations be the result of GetOperations(document, operationNames).
* Let coercedVariableValues be the result of CoerceVariableValues(schema, operation, variableValues).
* For each operation in operations
* If operation is a query operation:
* Return ExecuteQuery(operations, schema, coercedVariableValues, initialValue).
* Otherwise if operation is a mutation operation:
* Return ExecuteMutation(operations, schema, coercedVariableValues, initialValue).
GetOperations(document, operationNames)
* If operationName is null or empty:
* If document contains exactly one operation.
* Return the Operation contained in the document.
* Otherwise produce a query error requiring operationName.
* Otherwise:
* Let operations be the Operations named operationNames in document.
* If any of the operations are not found, produce a query error.
* Return operations.
# Executing each operation
The list of operations will be executed in the order specified. A list of `ExecutionResult`s will be produced that represent each operation.
If an operation is a mutation, then the serial execution will be applied to it as per a single operation.
The finaly result will be a single `ExecutionResult` that contains the list of `ExecutionResult` for each operation executed. This preserves the current expected signature from an graphql execution.
However like subsciptions, the top level data iterm is a proscibed shape, that is list of `ExecutionResult`
var executionResult = ExecuteRequest(schema,document,["A,"B"], variables)
var listOfResults = executionResult.data
for (result in listOfResults) {
// process each result
}
# Operation dependencies
Directive capabilities can create dependencies between the execution of operations.
For example B might depend on A executing first. If the graphql implementation detects such a dependency then it will wait for dependee operation (say A) to complete before executing the dependent operation (say B)
If not dependencies are detected, or the graphql implementation does not allow dependencies, then the operations can be executed in parralel, assuming they are query operations.
# Variables given to each operation
The variables that are specified on the original execution will be given to each operation.
The graphql implementation is free to augment those variables with new values as it executes.
New variables will be subject to the same validation rules as the initial variables.
# Capabilities unlocked because of multiple operations
Multiple operations allows for more efficient graphql queries. Multiple queries can be sent over slow mobile networks (which preparsed queries make even more efficient) and results can be sent back as soon as thye are obtained
One you have the ability to have multiple operations, you can introduce new capabilities like variable export.
This RFC is not concerned with defining exactly how this happens but having multiple operations is a pre-cursor to such capabilities.
For examaple imagine a query like
query A {
hero
{
id @export(as:"droidId")
name
friends @export(as:"r2d2Friends")
{
name @export(as:"friendNames")
}
}
}
query B($droidId : String!) {
droid (id : $droidId ) {
name
}
}
Output values from operation A would be exported as the variables named "droidId", "r2d2Friends", and "friendNames"
The operation B would be detected to be dependent on operation A and would be executed after operation A completes. It would receive the value of "droidId" as a variable from operation A
# Open Questions
The return shape of the results is an open question. Should it be a list (as proposed) or be async iterator in line with subscription operations.
When the returned results are `Promise` based then the distinction between list of Promise and async iterator of `Promise` is very small and we prefer the simple list.
There is a symmetry between a list of operations as input and a list of results as output.
# Current implementations
Sangria has this capability today sangria-graphql.org/learn/#batch-executor and graphql-java has a PR exploring the idea https://github.com/graphql-java/graphql-java/pull/808
It would be awesome if we were close to having a spec for upserts in GraphQL so maybe we could have that DQL feature in GraphQL. Has anyone looked into this?