联合类型无法在运行时解析对象类型

时间:2020-08-05 14:54:40

标签: python graphql graphene-python starlette graphql-python

我正在使用Starlette和Graphene用Python设置GraphQL服务器,遇到一个我找不到解决方案的问题。 Graphene Documentation没有详细介绍我要实现的联合类型。 我根据石墨烯文档建立了一个最小示例,您可以运行该示例来复制此问题

import os

import uvicorn
from graphene import ObjectType, Field, List, String, Int, Union
from graphene import Schema
from starlette.applications import Starlette
from starlette.graphql import GraphQLApp
from starlette.routing import Route

mock_data = {
    "episode": 3,
    "characters": [
        {
            "type": "Droid",
            "name": "R2-D2",
            "primaryFunction": "Astromech"
        },
        {
            "type": "Human",
            "name": "Luke Skywalker",
            "homePlanet": "Tatooine"
        },
        {
            "type": "Starship",
            "name": "Millennium Falcon",
            "length": 35
        }
    ]
}


class Human(ObjectType):
    name = String()
    homePlanet = String()


class Droid(ObjectType):
    name = String()
    primary_function = String()


class Starship(ObjectType):
    name = String()
    length = Int()


class Characters(Union):
    class Meta:
        types = (Human, Droid, Starship)


class SearchResult(ObjectType):
    characters = List(Characters)
    episode = Int()


class RootQuery(ObjectType):
    result = Field(SearchResult)

    @staticmethod
    def resolve_result(_, info):
        return mock_data


graphql_app = GraphQLApp(schema=Schema(query=RootQuery))

routes = [
    Route("/graphql", graphql_app),
]

api = Starlette(routes=routes)

if __name__ == "__main__":
    uvicorn.run(api, host="127.0.0.1", port=int(os.environ.get("PORT", 8080)))

如果您随后转到 http:// localhost:8080 / graphq 并输入以下查询

query Humans{
  result {
    episode
    characters {
      ... on Human {
        name
      }
    }
  }
}

我收到此错误

 {
    "data": {
        "result": {
            "episode": 3,
            "characters": null
        }
    },
    "errors": [
        {
            "message": "Abstract type Characters must resolve to an Object type at runtime for field SearchResult.characters with value \"[{'type': 'Droid', 'name': 'R2-D2', 'primaryFunction': 'Astromech'}, {'type': 'Human', 'name': 'Luke Skywalker', 'homePlanet': 'Tatooine'}, {'type': 'Starship', 'name': 'Millennium Falcon', 'length': 35}]\", received \"None\".",
            "locations": [
                {
                    "line": 4,
                    "column": 5
                }
            ]
        }
    ]
}

我现在坚持使用。也许有人已经做到了,可以帮上忙吗? 如何在运行时解决此问题。我已经尝试过其他方法,例如,我更改了 Character RootQuery 类:

class Character(Union):
    class Meta:
        types = (Human, Droid, Starship)

    def __init__(self, data, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.data = data
        self.type = data.get("type")

    def resolve_type(self, info):
        if self.type == "Human":
            return Human
        if self.type == "Droid":
            return Droid
        if self.type == "Starship":
            return Starship


class RootQuery(ObjectType):
    result = Field(SearchResult)
    
    @staticmethod
    def resolve_result(_, info):
        return {**mock_data, "characters": [Character(character) for character in mock_data.get('characters')]}

导致

{
    "data": {
        "result": {
            "episode": 3,
            "characters": [
                {},
                {
                    "name": null
                },
                {}
            ]
        }
    }
}

任何想法都将不胜感激!

1 个答案:

答案 0 :(得分:1)

jkimbo回答了问题here

class Character(Union):
    class Meta:
        types = (Human, Droid, Starship)

    @classmethod
    def resolve_type(cls, instance, info):
        if instance["type"] == "Human":
            return Human
        if instance["type"] == "Droid":
            return Droid
        if instance["type"] == "Starship":
            return Starship


class RootQuery(ObjectType):
    result = Field(SearchResult)

    def resolve_result(_, info):
        return mock_data

注意,我只是返回模拟数据,并且我已经更新了resolve_type方法以根据数据进行切换。联合类型使用与接口相同的resolve_type方法来确定运行时解析为哪种类型:https://docs.graphene-python.org/en/latest/types/interfaces/#resolving-data-objects-to-types