How to resolve a Field nested in another Type using Graphene GraphQL?
Asked Answered
M

1

12

I have 3 files: authors.py, posts.py and schema.py.

Posts have one Author and the Query is built in the schema file.

I'm trying to resolve Author from inside Post without declaring a resolver function in Post, since Author already has a resolver function for itself declared. The following code works, but I have to reference resolve_author from inside the Post type and it doesn't seem right. I think Graphene should pass the parent param directly to Author, no?

If I don't set a resolver for author in the Post type, it simply returns null.

schema.py

import graphene
from graphql_api import posts, authors


class Query(posts.Query, authors.Query):
    pass


schema = graphene.Schema(query=Query)

authors.py

from graphene import ObjectType, String, Field


class Author(ObjectType):
    id = ID()
    name = String()


class Query(ObjectType):
    author = Field(Author)

    def resolve_author(parent, info):
        return {
            'id': '123',
            'name': 'Grizzly Bear',
            'avatar': '#984321'
        }

posts.py

from graphene import ObjectType, String, Field
from graphql_api import authors


class Post(ObjectType):
    content = String()
    author = Field(authors.Author)

    def resolve_author(parent, info):
        # I'm doing like this and it works, but it seems wrong. 
        # I think Graphene should be able to use my resolver 
        # from the Author automatically...
        return authors.Query.resolve_author(parent,
                                            info, id=parent['authorId'])


class Query(ObjectType):
    post = Field(Post)

    def resolve_post(parent, info):
        return {
            'content': 'A title',
            'authorId': '123',
        }
Melina answered 7/8, 2019 at 10:21 Comment(1)
I have the same issue . it works fine in local but in live server it shows post not found in resolver error. . schema is type User{ id:Int firstname:string lastname:string post:Post }Yaekoyael
S
2

Query.resolve_author wouldn't be called because there is no relation between it and Post object.

I suggest something like:

from graphene import ObjectType, String, Field
from graphql_api import authors


class Post(ObjectType):
    content = String()
    author = Field(authors.Author)

    def resolve_author(self, info):
        # author_utils.get_author returns complete object that will be passed into Author's object resolvers (if some fields are missing)
        # I suggest returning here an object from database so author resolver would extract another fields inside
        # But it may be just an id that will be passed in Author resolvers as first arguments
        return author_utils.get_author(post_id=self.id)


class Query(ObjectType):
    post = Field(Post)

    def resolve_post(parent, info):
        # Here you shouldn't author_id as it's not defined in type 
        return {
            'content': 'A title',
        }

And Author (assume author_utils.get_author just returns an id):

class Author(ObjectType):
    id = ID()
    name = String()

    def resolve_id(id, info):
        # root here is what resolve_author returned in post. Be careful, it also will be called if id is missing after Query.resolve_author
        return id

    def resolve_name(id, info):
        # same as resolve_id
        return utils.get_name_by_id(id)
Showmanship answered 7/8, 2019 at 12:58 Comment(3)
It is not very efficient this way, I have to fetch the post and then fetch the post again to get the author. There is no problem in return author_id from the Field resolver, because it will be filtered by the edge resolvers. You are right that there is no relationship between Post and Author, so I shouldn't expect Post to fetch Author automatically, but there should be a better approach to this...Melina
I worked with django orm and the best approach I found is fetching all data I have to resolve in the root resolver (there is great lib for this - graphene-django-optimizer) and then passing this data to resolvers, so they get complete object and don't have to access db. Related fields (as Author of the Post) are already fetched in root resolver and only things I have to do is mapping db-fields into graphql type.Showmanship
That makes sense. I tried something here, I will update this thread after I try it out.Melina

© 2022 - 2024 — McMap. All rights reserved.