ariadne
ariadne copied to clipboard
Interface resolver issues with Pydantic schemas
I was facing an issue using and defining an interface in GraphQL when used together with Pydantic. The solution I finally managed to wotk with will not scale very well (not elegantly nor pythonic IMO).
PS: using latest versions of Flask (3.0.3), Pydantic (2.7.1) and Ariadne (0.23.0).
The basic GraphQL:
interface Metadata {
subject: String
date: String
}
type MetadataCommon implements Metadata {
subject: String
date: String
}
type MetadataBR implements Metadata {
subject: String
date: String
type: String
}
type Information {
id: String
metadata: Metadata!
}
type Response {
informations: [Information!]
}
type Query {
search (data: SearchInput) Response!
}
Basic Pydantic schemas:
class Metadata(BaseModel):
date: Optional[date] = None
subject: Optional[str] = None
class MetadataBR(Metadata):
type: Optional[str] = None
class Information(BaseModel):
id: str
metadata: Metadata
class Response(BaseModel):
informations: List[Information]
The interface resolver:
interface_metadata = InterfaceType("Metadata")
@interface_metadata.type_resolver
def resolve_metadata_type(obj, *_):
if isinstance(obj, schemas.MetadataBR):
return 'MetadataBR'
return 'MetadataCommon' # Returning the base value just for testing, could be None
In my code, currently I generate only MetadataBR
. But with the current definition of the Information model for Pydantic (where I define metadata being any class that can be evaluated to a base class and I can increase the number of possible classes in the future without adding new possible combinations to this field using Union). When the code reaches the resolver function, obj
for some reason comes with type schemas.Metadata
and without the type
field that is setted in the code.
Somewhere inside Ariadne code, it is converting my code to another type because if in my resolver, after I fetch the information and before returning the values, I try to dump the types and values, they all come correctly (MetadataBR and with type field).
What I had to do to make it work was change my python model to:
class Information(BaseModel):
id: str
metadata: MetadataBR
If I increase the number of metadata sub models, I would need to keep adding to several Unions.. making it not so readable.
Not sure if I missed something, but would be nice to have that working.
Thanks