graphql-zeus
graphql-zeus copied to clipboard
Union variants are not considered optional
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)}"]`,
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.
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?
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
}
}
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.
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
},
})
Good point, should it return null from backend on the type that is not included in the selection?
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
If item exitsts it returns just selected items
If only one item exists it returns only this item
Thanks. I will do it today/tomorrow. Thanks for all the input
done in 5.4.5