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

Confusing documentation on self argument of mutate method of Mutations #951

Closed
allardhoeve opened this issue Apr 25, 2019 · 3 comments
Closed

Comments

@allardhoeve
Copy link

allardhoeve commented Apr 25, 2019

Hi there,

The documentation on Mutations is a little confusing about the arguments the mutate method of a Mutation receives. Two examples list the method as:

# https://github.com/allardhoeve/graphene/blame/abff3d75/docs/types/mutations.rst#L22

class Something(Mutation):
    def mutate(self, info, *args):
        pass

This is actually incorrect, as the mutate method is always a @staticmethod, because the resolver is unbound here in graphene/types/mutation.py.

This is documented further on as:

# https://github.com/allardhoeve/graphene/blame/abff3d75a39/docs/types/mutations.rst#L107

class CreatePerson(graphene.Mutation):
    ...
    @staticmethod
    def mutate(root, info, person_data=None):
        pass

I would like to document this better in this part of the documentation, because it has caused me a lot of time to figure this out and would like to spare other that effort.

Can you elaborate on when root is set and what it will contain? I've only seen cases where root is None.

Also, can you elaborate on why you chose to make the resolver method mutate a static method by default? It being a static method makes it hard to implement inheritance between Mutation classes.

Finally, how would I go about having a resolver method that is NOT a static method if I wanted to? The code suggests I could use Meta attributes to do so, but the documentation does not tell me how. I would like to add that to the documentation.

Edit: The resolvers always being a staticmethod is documented here, but you have to first know that def mutate is considered a resolver and also you'd have to really remember that.

Thanks

@dvndrsn
Copy link
Contributor

dvndrsn commented May 15, 2019

Hey @allardhoeve, thanks for your question!

The first argument of mutate, mutate_and_get_payload, and resolve_xxx method is always root instead of self, they are treated in the same way as a @staticmethod decorator. The documentation can definitely be more clear here. When you're resolving a query, root intuitively makes sense as the value object retuned from the last resolver you visited in the graph of results that is being used to resolve the current type's fields.

In practice, root is always None for the first field you resolve in a Query or Mutation. Since best practices have all Mutation fields being defined on the Root Mutation, root is always None in practice.

In theory, one can set any value that you want as root while executing a query. There is a not well documented argument of the Schema.execute method which can set the initial value for root! This would apply to both Query and Mutation.

class Query(graphene.ObjectType):
    hello = graphene.String(name=graphene.String())

   def resolve_hello(root, info, name):
       greeting = root
       return f'{greeting}, {name}!'

schema = Schema(query=Query)
query_string = '{ greeting(name: "GraphQL!" }'
response = schema.execute(query_string, root='Howdy')
print(response.data['hello'])
# "Howdy, GraphQL!"

I'm going to take a stab at making the documentation for both Mutation and Query resolvers more clear with a PR soon.

@dvndrsn
Copy link
Contributor

dvndrsn commented May 19, 2019

PR #969 is up to address this (and several other documentation concerns.

@jkimbo
Copy link
Member

jkimbo commented Jun 9, 2019

#969 has been merged

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

No branches or pull requests

4 participants