-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
RFC: Remove fragmentSpreadName from visitedFragments when visit is complete #1045
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for graphql-spec-draft ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Interesing!
Do we have the same issue for fields? Assuming {
id
name
# This is not passed to the resolver
name @live
} Because of this:
So the second |
@martinbonnin Speaking from GraphQL.js' POV the entire of |
Counterpoint to my proposal:
This could multiply up expensiveness easily. But then again, assuming it's memoized it'd be negligible. |
Really interesting! Additional potential counterpointBelow example is attempt to explore how nested (but non-cyclic!) fragments might be handled. Nested fragment depth is linear with respect to overall query length, but server field collection work would be non-linear with respect to the query length, potentially opening up an attack vector. query Malicious {
object {
...F1
...<10 more times>...
...F1
}
}
fragment F1 on SomeObject {
...F2
...<10 more times>...
...F2
}
fragment F2 on SomeObject {
...F3
...<10 more times>...
...F3
}
fragment F3 on SomeObject {
...F4
...<10 more times>...
...F4
}
fragment F4 on SomeObject {
...F5
...<10 more times>...
...F5
}
fragment F5 on SomeObject {
...FewFields
...<10 more times>...
...FewFields
}
fragment FewFields on SomeObject {
a
b
c
} Definitely appreciate the idea of a common solution.One approach would be to adopt the fragment argument Relay-esque approach to include execution-level directives on fragments like For differing directive usage on sibling spreads, I see 3 different scenarios:
Self-referencing fragments with differing arguments/directivesAnother point to consider is that presumably self-referencing fragment spreads with different arguments should also be allowed, as they do not form a true cycle. So we may require the Relay-esque style behavior anyway. Modifying your example above: fragment ComponentOne on Hero {
id
...HeroDetails(includeBio: true, includeAvatar: false)
...SubComponentA
}
fragment SubComponentA on Hero {
...HeroDetails(includeBio: false, includeAvatar: true)
} For |
I don't think we'll allow a fragment to reference itself even if it has different arguments. I think we should allow fragments to be specified multiple times with different directives, since different components may use the same data in different ways (e.g. the logged in user's avatar may be rendered in multiple places on a web page, in some it may be deferrable, and others not - that's up to the components themselves to decide). The issue of having to align Assuming field collection is memoized (where the implementation knows to key it by the arguments and directives applied) then your non-linear example wouldn't be much of an issue. I considered explicitly defining this in the spec like Matt does for fragment arguments, but the risk is that someone would use a Base64-encoded avatar image as an argument to a fragment, and suddenly in your malicious query example but extended to use fragment arguments we'd have to generate that large key many times! A more subtle option could be to track "fragments with no arguments and no directives" separately from those with either or both. |
I think we should allow fragments to be specified multiple times with different directives, since different components may use the same data in different ways (e.g. the logged in user's avatar may be rendered in multiple places on a web page, in some it may be deferrable, and others not - that's up to the components themselves to decide).
We should allow fragments to be specified by different components some with defer, some not, but once the named fragment is non-deferred by any particular component, the deferred version is superfluous and can/should be subsumed.
In other words, I think this particular situation should not fail validation, but the deferred spread should ideally be ignored.
|
Yep, exact same page on that! (From an observable behavior point of view. Not necessarily from the algorithm's point of view.) |
@robrichard raised an issue for
@defer
whereby under the current draft specification if you have this query:then the
@defer
will never be visited; but if you move the@defer
earlier:then the non-deferred version will never be visited.
@mjmahone has an RFC open about fragment arguments which suffers a similar issue: visits to a fragment aren't equivalent depending on the variables.
Matt's solution takes a Relay-esque approach and generates a key for the fragments based on the values of their arguments.
Another consideration is where there are user-defined directives; e.g.
{ id ...Profile name ...Profile @live }
might benefit from walkingProfile
again now that it has@live
attached.A simple solution to this is rather than each of these problems having their own solution, to simply navigate the fragment spread again - it's only a single layer that we need to worry about, so the cost is likely to be marginal. This RFC proposes this with a tiny change to the spec - after adding the fragmentSpreadName to visitedFragments, and calling CollectFields, we then remove it again.