Graphene-django: New SerializerMutation which is conform with ApolloClient

Created on 6 Jul 2018  路  8Comments  路  Source: graphql-python/graphene-django

Hello,
I'm a bit new to the whole graphene django dev scene so it might be that I dont have everything right

So I'm working on a project that uses ApolloClient on the frontend and I wanted to get the automatic cache updates working. For that to work, the arguments of the mutation have to be the individual fields of that ObjectType to be mutated. Also it should return the ObjectType directly and not a wrapping of that ObjectType.

Somehow I was unable to get my backend running like this with the current graphene django combination. So I started digging and modified the SerializerMutation from graphene-django a bit. Below is what I came up with so far. Maybe some experts can comment on this. I don't know why the ClientIDMutation is used currently. I skipped that in my implementation and just used graphene.Mutation directly. Well let me know if this is any use or not. In case of the former I would be glad to polish this up and make a pull request.

class MySerializerMutation(graphene.Mutation):
    class Arguments:
        pass

    @classmethod
    def __init_subclass_with_meta__(cls, serializer_class=None, output_type=None, lookup_field=None, model_class=None, **options):
        serializer_class = serializer_class

        for k, v in fields_for_serializer(
            serializer_class(), (), (), is_input=True).items():
            setattr(cls.Arguments, k, v)

        setattr(cls, 'Output', output_type)

        if model_class is None:
            serializer_meta = getattr(serializer_class, 'Meta', None)
            if serializer_meta:
                model_class = getattr(serializer_meta, 'model', None)

        _meta = SerializerMutationOptions(cls)
        _meta.lookup_field = lookup_field
        _meta.model_operations = ['update', 'create']
        _meta.serializer_class = serializer_class
        _meta.model_class = model_class
        super(MySerializerMutation, cls).__init_subclass_with_meta__(_meta=_meta, **options)


    @classmethod
    def get_serializer_kwargs(cls, root, info, **input):
        lookup_field = cls._meta.lookup_field
        model_class = cls._meta.model_class

        if model_class:
            if 'update' in cls._meta.model_operations and lookup_field in input:
                instance = get_object_or_404(model_class, **{
                    lookup_field: input[lookup_field]})
            elif 'create' in cls._meta.model_operations:
                instance = None
            else:
                raise Exception(
                    'Invalid update operation. Input parameter "{}" required.'.format(
                        lookup_field
                    ))

            return {
                'instance': instance,
                'data': input,
                'context': {'request': info.context}
            }

        return {'data': input, 'context': {'request': info.context}}

    @classmethod
    def mutate(cls, root, info, **input):
        kwargs = cls.get_serializer_kwargs(root, info, **input)
        serializer = cls._meta.serializer_class(**kwargs)

        if serializer.is_valid():
            obj = serializer.save()
            return obj
        else:
            errors = [
                ErrorType(field=key, messages=value)
                for key, value in serializer.errors.items()
            ]

            return cls(errors=errors)
wontfix

Most helpful comment

hey @spflueger, when I implemented the serialiser mutation I mistakenly decided to not wrap the returned fields in a new type. I have a custom version of serialiser mutation to fix this, which works similar to what I proposed here: #386

I'll see if I can send the PR soon :)

All 8 comments

hey @spflueger, when I implemented the serialiser mutation I mistakenly decided to not wrap the returned fields in a new type. I have a custom version of serialiser mutation to fix this, which works similar to what I proposed here: #386

I'll see if I can send the PR soon :)

hey @patrick91

when I implemented the serialiser mutation I mistakenly decided to not wrap the returned fields in a new type

I'm confused about "mistakenly decided to not wrap the returned fields in a new type". Are you talking about your own serializer mutation or about the one in the repo? Because I was not able to get the repo serializer mutation to return just the fields of the object, only the wrapped version. That's why I wrote my own serializer mutation.

Not sure I understood you correctly. So your custom version will fix this by having this flag or switch to allow a wrapped or non-wrapped type return?

Btw, what is the benefit of the ClientIDMutation?

I wrote the implementation of the serialiser mutation and when I did it I wasn't using Apollo yet :)

Not sure I understood you correctly. So your custom version will fix this by having this flag or switch to allow a wrapped or non-wrapped type return?

yes, the flag would be for backwards compatibility mainly, but I guess it is also good to allow users to choose how they want the API to behave

Btw, what is the benefit of the ClientIDMutation?

Not sure to be honest :)

Ah ok, I get it. Your idea sounds good to me. Thanks for the effort!

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@spflueger Any news on PR for this?

I thought @patrick91 was trying to make a PR for this. Too be honest, I haven't been coding for this project for months now. I'm still using the code snippet I send above...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BrianChapman picture BrianChapman  路  3Comments

dan-klasson picture dan-klasson  路  4Comments

hyusetiawan picture hyusetiawan  路  4Comments

khankuan picture khankuan  路  4Comments

nickhudkins picture nickhudkins  路  3Comments