Graphene: Mutation inheritance in 1.0

Created on 3 Oct 2016  路  6Comments  路  Source: graphql-python/graphene

I'm having trouble inheriting multiple mutations together in 1.0.

Previously was able to set up a (reusable mutation) like this:

class SimpleCreationMutation(relay.ClientIDMutation):
    class Input:
        name = graphene.String(required=True)

    ok = graphene.Boolean()

    @classmethod
    def mutate_and_get_payload(cls, input, context, info):
        model = cls.Config.model

        name = input.get('name')

        instance = model(name=name)
        instance.save()

        return cls(result=instance, ok=bool(instance.id))

class CreateTag(SimpleCreationMutation):
    class Config:
        model = Tag

    result = graphene.Field(TagNode)

Now trying to call that mutation leads to this error:

"Argument \"input\" has invalid value {clientMutationId: \"test_mutation\", name: \"test_name\"}.\nIn field \"name\": Unknown field."

Most helpful comment

@morgante Did you ever find a way to make the class Input inheritable? I have a similar problem where I have a large number of CRUD mutations and I'd like to make the input shared between set and create mutations. I am successful at least sharing fields by inheriting from AbstractType just like the line ok = graphene.Boolean() in your example.

All 6 comments

@morgante While I agree this should work, one thing you could do in the meantime is using the AbstractType as shown here: https://github.com/graphql-python/graphene/blob/master/graphene/relay/tests/test_mutation.py#L36

@Globegitter I actually _did_ try to use the AbstractType and it still didn't work. Like so:

class SimpleCreationMutation(AbstractType):
    class Input:
        name = graphene.String(required=True)

    ok = graphene.Boolean()

    @classmethod
    def mutate_and_get_payload(cls, input, context, info):
        model = cls.Config.model

        name = input.get('name')

        instance = model(name=name)
        instance.save()

        return cls(result=instance, ok=bool(instance.id))

class CreateTag(SimpleCreationMutation, relay.ClientIDMutation):
    class Config:
        model = Tag

    result = graphene.Field(TagNode)

@morgante Did you ever find a way to make the class Input inheritable? I have a similar problem where I have a large number of CRUD mutations and I'd like to make the input shared between set and create mutations. I am successful at least sharing fields by inheriting from AbstractType just like the line ok = graphene.Boolean() in your example.

Hi @morgante . We're currently going through old issues that appear to have gone stale (ie. not updated in about the last 6 months) to try and clean up the issue tracker. If this is still important to you please comment and we'll re-open this.

Thanks!

I ended up with this pattern:

class AbstractCreateBaz(ObjectType):
    class Arguments:
        name = String()

    result = List(String)


def create_baz_mutate(name):
    # Put save code here
    return AbstractCreateBaz(result=name)


class CreateFoo(Mutation, AbstractCreateBaz):
    def mutate(self, info, name):
        return create_baz_mutate('foo')


class CreateBar(Mutation, AbstractCreateBaz):
    def mutate(self, info, name):
        return create_baz_mutate('bar')

class BazMutations(ObjectType):
    create_foo = CreateFoo.Field()
    create_bar = CreateBar.Field()

It's a bit verbose, is there a better way?

Found yet another way:
Define the class dynamically.

def create_class(foo_id: str): # so I can create a slightly different kind of class every time
    class CreateFoo(Mutation, AbstractCreateFoo):
        def mutate(self, info, name):
            # create code goes here
            return AbstractCreateFoo(result=bar)
    return type(foo_id, (CreateFoo,), {})

Hope this helps someone

Was this page helpful?
0 / 5 - 0 ratings