graphql-code-generator icon indicating copy to clipboard operation
graphql-code-generator copied to clipboard

Add an @inline direction in client-preset to unmask actual GraphQL fragments

Open AaronBuxbaum opened this issue 2 years ago • 5 comments

Is your feature request related to a problem? Please describe.

A user may have prior-existing fragments, or want to use fragments, that are not 1:1 directly associated with a specific component. For example:

fragment User {
  id
  name
  ...
}

query {
  user(...) {
    ...User
  }
}

With the current fragment masking in client-preset, these fragments are assumed to be components, which will then fail to work.

Describe the solution you'd like

My suggestion is to mirror how Relay is designed, with an @inline or @relay(mask: false) directive. This directive indicates that a fragment is not a component's fragment and allows intermixing of actual fragments with component fragments:

query {
  user(...) {
     ...UserAvatar_User
     ...User @inline
  }
}

this will expand the User fragment, but continue to mask the UserAvatar_User fragment (which might itself want to expand the User fragment)

Describe alternatives you've considered

One alternative is to simply suggest that fragments themselves are an antipattern because repeated GraphQL entire objects should be abstracted to a component. I think this is an unrealistic approach, especially when considering transitioning onto fragment masking from an existing codebase.

Is your feature request related to a problem? Please describe.

No response

AaronBuxbaum avatar Sep 27 '23 22:09 AaronBuxbaum

I believe it could be related to https://github.com/dotansimha/graphql-code-generator/issues/9075, which describes an incremental adoption of fragment masking via a type utility to unmask a fragment.

Unmasking specific fragments via a directive is an option I like, and I wasn't thinking about!

Regarding the alternative mentioned, I do believe that it is an anti-pattern to create a single fragment shared across many containers, but I also recognize the fact that, in some particular cases, this would be super useful.

charpeni avatar Sep 29 '23 14:09 charpeni

@charpeni I think this is tangential, but if I'm not mistaken it has to be defined at the directive level (or at least, not at the Typescript level) to resolve this problem. This is because the fragment problem here is caused at the point of codegen, so we never get up to the point of Typescript at all to begin with.

My reading of #9075 is that an existing working codebase will need dramatic updates to update to fragment masking because you need to write every mask at once in order for it to work; the codegen works, but then each component isn't actually getting the props it thought it would

Though these could be consolidated by suggesting that the migrating user adds @inline to every fragment and then slowly removes them as they build the mask fragments 🤷

AaronBuxbaum avatar Sep 29 '23 21:09 AaronBuxbaum

This would also solve sharing a fragment between query and mutation (https://github.com/dotansimha/graphql-code-generator/discussions/9325) and also for cache updates (especially new additions where a fragment is needed)

KammererTob avatar Oct 26 '23 13:10 KammererTob

Some prior art: gql.tada supports an @_unmask directive much like this suggestion. https://gql-tada.0no.co/guides/fragment-colocation#fragment-masking

dallonf avatar Feb 04 '25 16:02 dallonf

This seems similar to Apollo's @unmask https://github.com/dotansimha/graphql-code-generator/pull/10163 🙂 If anyone has some time to create a PR, I'm happy to collab to move it over the line

eddeee888 avatar Feb 08 '25 13:02 eddeee888