question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Union types cannot be resovled. Documentation incomplete

See original GitHub issue

I am setting up a GraphQL Server with Python using Starlette and Graphene and ran into a problem I cannot find a solution for. The Graphene Documentation does not go into detail regarding the union type, which I am trying to implement. I set up a minimum example based on the graphene documentation which you can run to replicate this problem

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)))

If you then go to http://localhost:8080/graphq and enter the following query

query Humans{
  result {
    episode
    characters {
      ... on Human {
        name
      }
    }
  }
}
I get this error

 {
    "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
                }
            ]
        }
    ]
}

which I am now stuck with. Maybe someone has done this already and can help out? How can I resolve this at runtime. I have already tried different approaches for example I changed classes Character and 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')]}

resulting in

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

Any ideas would be very appreciated!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
R1nat-Pcommented, Nov 26, 2020

@jkimbo this works. Thanks a lot.

How it worked? It returns only 1 class attributes because in resolve_type is return to the 1 class, and not all attributes from union-ed classes.

Thanks!

4reactions
R1nat-Pcommented, Nov 26, 2020

@R1nat-P it does not have anything to do with the union-ed class. instance is the actual data with which the class is called and instance[“type”] is just the attribute. You could also do with instance.get(“type”). I suggest you to have a closer look at the source code or even set the example up your self locally. Btw, here you can find the stackoverflow article corresponding to it. Hope this helps.

@jmandt ,

Actually was done like was described in official documentation link , therefore was added the part with resolve_type , no luck.

class LoginData(graphene.Union):
    class Meta:
        types = (UsersData, MembershipData)

    @classmethod
    def resolve_type(cls, instance, info):
            if instance["type"] == "UsersData":
                return UsersData
            if instance["type"] == "MembershipData":
                return MembershipData

And getting the following result

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to resolve interfaces and union types in AppSync
Sending the query produces a rather strange error: { "errors" : [ { "errorType" : "BadRequestException", "message" : "Could not determine the ...
Read more >
Typescript unable to resolve property on the union type
Property 'availability' does not exist on type 'SearchLocationQuery'. So you have to check for their type e.g. with the in operator e.g. export ......
Read more >
Federation error codes - Apollo GraphQL Docs
Since federation 2.1. 0, the case this error used to cover is now a warning (with code INCONSISTENT_NON_REPEATABLE_DIRECTIVE_ARGUMENTS ) instead of an error....
Read more >
Handbook - Unions and Intersection Types - TypeScript
Union Exhaustiveness checking​​ Function lacks ending return statement and return type does not include 'undefined'. Function lacks ending return statement and ...
Read more >
Error conditions in Databricks
Cannot resolve <sqlExpr> due to data type mismatch: ... are from different Delta tables, please use Dataset's union()/unionByName() APIs.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found