Skip to content
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

Union InputType? #721

Closed
yywing opened this issue May 7, 2018 · 5 comments
Closed

Union InputType? #721

yywing opened this issue May 7, 2018 · 5 comments

Comments

@yywing
Copy link

yywing commented May 7, 2018

I have three type.

class A(InputType):
    pass

class B(InputType):
    start_time = String()

class C(InputType):
    start_time = String()
    end_time = String()

So I hope that:

class T(Union):
    class Meta:
        types = (A, B, C)

the data maybe like:

{_type: A}
{_type:B, start_time: xxxx}
{_type:C,  start_time:xxx, end_time: xxx}

By the way, why an ObjectType or InputType must have fields?

@yywing
Copy link
Author

yywing commented May 7, 2018

And I think it is a very normal usage.Is there any way to solve it?

@jkimbo
Copy link
Member

jkimbo commented May 7, 2018

It's currently not possible but there is an ongoing debate in the graphql-js repo about it: graphql/graphql-js#207

I think it's probably more complexity than it's worth and I agree with Lee here: graphql/graphql-js#207 (comment)

@jkimbo jkimbo closed this as completed May 7, 2018
@fcoclavero
Copy link

@jkimbo the input union spec was updated on the GraphQL RFC.

@Dave-Lopper
Copy link

Dave-Lopper commented Dec 21, 2022

Can anyone advise here?
I am running into a very similar scenario where I have an Element that can be either:

class ImageElementInput(graphene.InputObjectType):
    element_type = ElementTypeEnum()
    url = graphene.String()
    description = graphene.String(required=False)
    rounding = graphene.Int(required=False)

or

class TextElementInput(graphene.InputObjectType):
    color = graphene.String()
    element_type = ElementTypeEnum()
    font = graphene.String()
    text_copy = graphene.String()
    weight = graphene.Int()
    size = graphene.Int(required=False)

I'd like to have them both as a union type (discriminated on the element_type attribute)

I have similar use cases at a lot of places throughout the feature I am developing, and graphene.Union works great for that when dealing with Output types.

I also have looked into graphene-pydantic, hoping to get something done with the Pydantic discriminated Unions but it turns out that graphene-pydantic does not support them yet. (See Here)
And will probably start doing so on Output types, espacially if the way to support this does not exist in Graphene.

Has anyone any clue or, idea of another approach to get this done, or achieve a similar result?

@erikwrede
Copy link
Member

erikwrede commented Dec 21, 2022

@Dave-Lopper while I can't comment on your exact use case, but judging from your example, this sounds like a great case to have two separate mutations: AddImageElement and AddTextElement instead of making complex mutations with choices. Roughly based on graphql-rules: https://graphql-rules.com/rules/mutation-required-args

@oneOf is another up-to-date option but since it is not added to spec or graphql-js, so we cannot use it in graphene yet.

However, for complex inputs I'd definitely recommend separate mutations, especially when they're already encapsulated into two separate input types.

For a current alternative, you could create a wrapper input providing the types you want to union as optional fields/resolver args:

input AddElementInput {
imageInput: ImageElementInput
textInput: TextElementInput
}

However, I do not recommend this approach as it dilutes the expressivity of the schema. From the schema it is no longer directly visible if only one of the inputs is allowed, no inputs are allowed, or both inputs are allowed at the same time. This is not a good pattern to follow.

In the future, please open up a new issue referencing the issues you already looked up. This is much easier than tracking comments under closed issues. 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants