graphql-zeus icon indicating copy to clipboard operation
graphql-zeus copied to clipboard

Union variants are not considered optional

Open martinjlowm opened this issue 1 year ago • 9 comments

I just came across a problem with using fragments and I noticed from the following code emitting logic that enum variants are not considered optional. Is there a particular reason why that is the case?

https://github.com/graphql-editor/graphql-zeus/blob/master/packages/graphql-zeus-core/TreeToTS/templates/valueTypes/index.ts#L16

Type-wise this would require all fragments to be provided into the selection criteria because the fragment key-literal signature is required.

I'd argue optionality (as in the following) would be the desired behavior.

(f) => `\t\t["...on ${getTypeName(f.type.fieldType)}"]?: ${VALUETYPES}["${getTypeName(f.type.fieldType)}"]`,

martinjlowm avatar Nov 05 '23 10:11 martinjlowm

I would really like this also, I've yet to come across a GraphQL server that specifically requires all union variants in a request, so this feels like an easy win for a single character change.

chrishale avatar Nov 20 '23 14:11 chrishale

I don't know TBH, but you are expecting that server can return all types of union so this is correct behavior. If we made it optional it doesnt make sense. What happens when server returns other Type that we dont have? Runtime Error?

aexol avatar Dec 17 '23 11:12 aexol

Can you elaborate on the last part? Not sure I understand your first statement either. Surely, marking the fragment optional still allows you to express all variant types.

As a concrete example consider the following query (GitHub's API is a good one, seeing that they heavily use unions):

# Zeus (with this proposal patched)
["ProjectV2ItemContent"]: AliasType<{
  ["...on DraftIssue"]?: ValueTypes["DraftIssue"],
  ["...on Issue"]?: ValueTypes["Issue"],
  ["...on PullRequest"]?: ValueTypes["PullRequest"]
  __typename?: boolean | `@${string}`
}>;

With the current behavior, one would have to express the query with all fragments included as the following even if you are only interested in the Issue-variant.

content {
  __typename
  ...on Issue {
    body
  }
  ...on DraftIssue {
    body # don't care
  }
  ...on PullRequest {
    body # don't care
  } 
}

Whereas making the field optional, the equivalent query would be:

content {
  __typename
  ...on Issue {
    body
  }
}

martinjlowm avatar Dec 18 '23 08:12 martinjlowm

I have seen some GraphQL servers implement a ... on Error for when something goes wrong but I think it's far more typical that when you don't pass the union that you're asking to return that you'd get an empty object, or just the __typename in the example above.

chrishale avatar Dec 19 '23 10:12 chrishale

Having a lot of troubles because unions are not optional.

We have two environments: prod and dev. We removed one option (...on SomeDeprecatedOption) on dev stand backend and now we want to update prod without downtime.

But if we update BE with old FE deployed, all requests will fail with graphql error Unknown type "SomeDeprecatedOption"

And if we try to update FE first, removing this option from the selector, it fails on build time with TS error: Property '["...on SomeDeprecatedOption"]' is missing

So, I'm forced to find workarounds like disabling TS in order to upgrade


By the way, graphql requests with partial union options selected are still valid and execute correctly, so such strict TS disables some GraphQL functionality. Another use case: I may want to have several selectors for one union type. handling some parts of it in different places of the app. Right now, zeus doesn't make it possible. Such selectors will show "Property is missing" error:

export const FirstContentSelector = Selector('SomeStrapiDynamicZone')({
  '...on FirstUnionType': {
    title: true
  },
})

export const SecondContentSelector = Selector('SomeStrapiDynamicZone')({
  '...on SecondUnionType': {
    image: true
  },
})

klonwar avatar Aug 15 '24 16:08 klonwar

Good point, should it return null from backend on the type that is not included in the selection?

aexol avatar Aug 15 '24 20:08 aexol

As for graphql, it's just returns what you've selected, just like any other graphql query.

If all items selected are missing it returns empty objects image

If item exitsts it returns just selected items image image

If only one item exists it returns only this item image

klonwar avatar Aug 16 '24 08:08 klonwar

Thanks. I will do it today/tomorrow. Thanks for all the input

aexol avatar Aug 19 '24 09:08 aexol

done in 5.4.5

aexol avatar Aug 23 '24 10:08 aexol